NullPointerException when inject enterprise bean into JAX-RS 2.0 REST service - rest

I am trying to inject and EJB 3.1 in one of my RESTful services. I've followed the post: Inject an EJB into JAX-RS (RESTful service) and tried all options except building an injection provider. The current solution that I am trying uses a combination of #RequestScoped and #Inject, but my injected bean variable is still null. I have a beans.xml in the /WEB-INF folder.
How can I inject an EJB into my REST service class?
UserService
#Local
#Path("user/v1")
#Produces(MediaType.APPLICATION_JSON)
public class UserServiceV1 implements SystemLogger {
#Inject
private ApplicationBean appBean;
#GET
#Path("pingbean")
#Produces(MediaType.APPLICATION_JSON)
public Response pingAppBean() {
if(appBean == null) {
return Response.status(Response.Status.UNAUTHORIZED).entity("{\"faild\": \"App bean is null\"}").build();
}
String message = appBean.getHello();
return Response.status(Response.Status.OK)
.entity(message)
.build();
}
}
ApplicationBean
The SystemHandler resides in jar module and is a standard class with business logic.
#Stateless
#Local
public class ApplicationBean implements ApplicationBeanLocal {
#Override
public String getHello() {
return "Hello from ApplicationBean";
};
}
JAX-RS configuration
#ApplicationPath("service")
public class ApplicationService extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(UserServiceV1.class);
resources.add(ApplicationBean.class);
resources.add(CorsFilterProvider.class);
return resources;
}
}
Exception
14:07:01,230 ERROR [io.undertow.request] UT005023: Exception handling request to /MyApp/service/user/v1/login: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76) [resteasy-jaxrs-3.0.14.Final.jar:3.0.14.Final]
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:212) [resteasy-jaxrs-3.0.14.Final.jar:3.0.14.Final]
Resteasy /JAX-RS
I've added a CDI implementation for resteasy according to the documentation
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-cdi</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
EDIT: changed code details in the question and title

EJB 3.1 implies a Java EE 6 container implementation.
Java EE 6 implies JAX-RS 1.1.
JAX-RS 1.1 is only required to support #EJB injection of enterprise java beans.
JAX-RS 2.0 as provided in a Java EE 7 implementation supports #Inject for EJBs.

As Steve C answered, the proper way to inject an EJB in JAX-RS 1.1 is with the javax.ejb.EJB annotation. The REST service must also be an EJB for this to work. As such, you have to use the javax.ejb.Stateless annotation instead of javax.enterprise.context.RequestScoped.
The end result is as follows:
#Stateless
#Path("user/v1")
public class UserServiceV1 implements SystemLogger {
#EJB
private ApplicationBean appBean;
//etc.
}
EDIT
Your updated code doesn't deploy. Either have ApplicationBean implement ApplicationBeanLocal and inject the interface, or don't implement it and inject the class directly. With that corrected, I managed to run your example just fine.
Also, in ApplicationService, you don't need to add ApplicationBean.class. You only register there REST root resources and feature providers. #Local is also unnecessary in the UserServiceV1 class, it's not an EJB.
Furthermore, it's beans.xml, not bean.xml (but this file is not necessary anymore from CDI 1.1 on).
See my testcode below:
pom.xml dependencies for the jar module:
<dependencies>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
ApplicationBeanLocal.java:
public interface ApplicationBeanLocal {
String getHello();
}
ApplicationBean.java:
#Stateless
#Local
public class ApplicationBean implements ApplicationBeanLocal {
#Override
public String getHello() {
return "Hello from ApplicationBean";
}
}
pom.xml dependencies for the JAX-RS application:
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-cdi</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<!-- The jar-module containing ApplicationBean and ApplicationBeanLocal -->
<dependency>
<groupId>test</groupId>
<artifactId>testjar</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
TestApplication.java:
#ApplicationPath("service")
public class TestApplication extends Application {
private final Set<Class<?>> resources = new HashSet<>();
public TestApplication() {
resources.add(UserServiceV1.class);
}
#Override
public Set<Class<?>> getClasses() {
return resources;
}
}
UserServiceV1.java
#Path("user/v1")
#RequestScoped
#Produces(MediaType.APPLICATION_JSON)
public class UserServiceV1 {
#Inject // Note that I'm referencing the interface, not the implementation
private ApplicationBeanLocal appBean;
#GET
#Path("pingbean")
#Produces(MediaType.APPLICATION_JSON)
public Response pingAppBean() {
final String message = appBean.getHello();
return Response.status(Response.Status.OK).entity(message).build();
}
}

Related

Quarkus MongoDB panache transactional Rollback has no effect

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mongodb-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-narayana-jta</artifactId>
</dependency>
//repo
#ApplicationScoped
public class ProjectRepository implements
PanacheMongoRepositoryBase<Project, String> {
....
}
//transaction method
#Inject
ProjectRepository projectRepository
....
#Transactional
public Project import(Order order, User user) {
Project project = factor.from(order);
projectRepository.persist(project);
if (project.id != null){
//try to throw exception manually
throw new RuntimeException("testing");
}
return project;
}
I have tried #transactional annotation with mongodb 4.4.10 and quarkus 2.5.1. Transaction still has no rollback effect. any ideas ? thanks

Hazelcast Repository Still queries the Database

I am working on a spring boot project. In that, i have an entity called ProductMap which i want to keep in cache. I did that using MapLoader and defining the configuration for the map as below.
#Bean
public Config hazelcastConfig() {
return new Config().setInstanceName("hazelcast-instance").addMapConfig(
new MapConfig().setName("ProductMap")
.setMapStoreConfig(
new MapStoreConfig().setEnabled(true).setInitialLoadMode(MapStoreConfig.InitialLoadMode.EAGER)
.setClassName("com.hazelcast.example.HzTest.config.ProductMapLoader")
));
}
ProductMap entity:
#Data
#Entity
#KeySpace("ProductMap")
#Table
public class ProductMap implements Serializable {
#Id
#org.springframework.data.annotation.Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer Id;
private String name;
private Integer category;
private Integer productType;
}
ProductMapLoader:
#Log4j2
#Component
public class ProductMapLoader implements MapLoader<Integer, ProductMap>, ApplicationContextAware {
private static ProductMapRepository productMapRepository;
#Override
public synchronized ProductMap load(Integer integer) {
System.out.println("Load::" + integer);
return productMapRepository.findById(integer).get();
}
#Override
public synchronized Map<Integer, ProductMap> loadAll(Collection<Integer> collection) {
Map<Integer, ProductMap> result = new HashMap<>();
for (Integer key : collection) {
ProductMap productMap = this.load(key);
if (productMap != null) {
result.put(key, productMap);
}
}
return result;
}
#Override
public synchronized Iterable<Integer> loadAllKeys() {
System.out.println("load all keys" + productMapRepository);
return productMapRepository.findAllProdMapKeys();
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
productMapRepository = applicationContext.getBean(ProductMapRepository.class);
}
}
I am loading the cache on startup,
#PostConstruct
public void Init() {
IMap map = hazelcastInstance.getMap("ProductMap"); // this will load the cache
}
In also created a HazelcastRepository,
public interface ProductMapKvRepo extends KeyValueRepository<ProductMap, Integer> {
List<ProductMap> findByProductType(Integer productType);
}
In one of my service methods, it calls productMapKvRepo.findAll() and productMapKvRepo.findByProductType(1). But the repository still queries the database.
Hibernate: select productmap0_.id as id1_0_, productmap0_.category as category2_0_, productmap0_.name as name3_0_, productmap0_.product_type as product_4_0_ from product_map productmap0_
Hibernate: select productmap0_.id as id1_0_, productmap0_.category as category2_0_, productmap0_.name as name3_0_, productmap0_.product_type as product_4_0_ from product_map productmap0_ where productmap0_.product_type=?
dependencies used:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>3.12.7</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-client</artifactId>
<version>3.12.7</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>spring-data-hazelcast</artifactId>
<version>2.2.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.13</version>
</dependency>
</dependencies>
Can anyone tell me what is wrong here and what can i do?
Your logs indicate that your Spring Data repository is Hibernate-backed which means your project is misconfigured. Spring Data Hazelcast doesn't use Hibernate to read data from the Hazelcast IMDG cluster.
If the use of Hibernate is intended(most likely), then you should consider using its native second-level cache capabilities with Hazelcast instead of wrapping Spring Data repositories inside a MapLoader. You can find the example here.
However, if you want to apply the read-through caching pattern with a MapLoader, you'd need to use a spring-data-hazelcast artifact to read data from Hazelcast cluster directly.
While I was working with Spring Boot v2.1.3.RELEASE and Spring v5.1.5.RELEASE , spring was injecting SimpleJpaRepository type for both repositories :
MyStandardRepository And MyHazelCastRepository, with the presence only of #EnableHazelcastRepositories
By adding also #EnableJpaRepositories to my HazelcastConfiguration class :
spring then injected SimpleKeyValueRepository bean type into MyHazelCastRepository :
#Configuration
#EnableHazelcastRepositories(basePackages = {"com.test.repository.hazelcast"})
#EnableJpaRepositories(basePackages = {"com.test.repository.dao"})
public class HazelcastConfiguration {
#Bean
HazelcastInstance hazelcastInstance() {
return Hazelcast.newHazelcastInstance();
}
#Bean
public KeyValueOperations keyValueTemplate() {
return new KeyValueTemplate(new HazelcastKeyValueAdapter(hazelcastInstance()));
}
#Bean
public HazelcastKeyValueAdapter hazelcastKeyValueAdapter(HazelcastInstance hzInstance) {
return new HazelcastKeyValueAdapter(hzInstance);
}
}

Configure Wildfly 10 to use Jackson (as JSON provider)

I have an application that has webservices built with Jersey and Jackson as JSON provider, all this in a Tomcat application server.
I need to make this application working on Wildfly 10 and everything is working fine, beside the webservice response that is not taking in consideration the Jackson annotations. From what I read Wildfly was using Jettison as default and in the newer version Jackson2 is used.
The preferred solution would be to make RestEasy (from Wildfly 10) to use Jackson and for this I tried to exclude Jackson2 and Jettison and make a dependency to Jackson in (META-INF\jboss-deployment-structure.xml), as below:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclusions>
<module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
<module name="org.jboss.resteasy.resteasy-jettison-provider"/>
</exclusions>
<dependencies>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
Apparently this is not enough, since is behaving as before.
What else should I try?
UPDATE:
Since my application should work the same on both Tomcat (using Jersey) and Wildfly (using RestEasy), I cannot rely on using jackson from resteasy inside my application, hence I'm importing org.codehaus.jackson.
So, I register my application like this:
import javax.ws.rs.core.Application;
public class RestApplication extends Application
{
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(RestObjectMapperProvider.class);
classes.add(GeneratedService.class);
return classes;
}
}
And rest object mapper provider:
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.ObjectMapper;
#Provider
public class RestObjectMapperProvider implements ContextResolver<ObjectMapper>
{
private final ObjectMapper objectMapper;
public RestObjectMapperProvider()
{
this.objectMapper = new ObjectMapper();
this.objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
}
#Override
public ObjectMapper getContext(Class<?> type)
{
return this.objectMapper;
}
}
I'm building my app with Gradle and below is the Jackson dependency:
compile group: 'org.codehaus.jackson', name: 'jackson-jaxrs', version: '1.9.+'
Since under Tomcat (Jersey) the annotation are considered, my guess would be that in Wildfly my exclusions are not considered. Is there any way to check which JSON Provider was considered, beside checking the response?
I'm curious why you are using Jackson 1.x instead of 2.x? The instructions are similar for both but the Jackson Configuration would have to change. Below are instructions for 1.x.
jboss-deployment-structure.xml (same as yours):
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<exclusions>
<module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
<module name="org.jboss.resteasy.resteasy-jettison-provider"/>
</exclusions>
<dependencies>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
Register your application with #Application:
#ApplicationPath("/api/v1")
public class V1Application extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(JacksonConfigurationProvider.class);
classes.add(TestResource.class);
return classes;
}
}
Use a jackson configuration provider like:
#Provider
#Consumes({MediaType.APPLICATION_JSON, "text/json"})
#Produces({MediaType.APPLICATION_JSON, "text/json"})
public class JacksonConfigurationProvider extends ResteasyJacksonProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(JacksonConfigurationProvider.class);
public JacksonConfigurationProvider() {
super();
LOGGER.info("loading jackson configurator");
JacksonObjectMapper mapper = JacksonObjectMapper.get();
setMapper(mapper);
}
}
Then, in your JacksonObjectMapper is where you tell it to read the annotations:
public class JacksonObjectMapper extends ObjectMapper {
public static JacksonObjectMapper get() {
JacksonObjectMapper mapper = new JacksonObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
JacksonAnnotationIntrospector jacksonAnnotationIntrospector = new JacksonAnnotationIntrospector();
mapper.setDeserializationConfig(mapper.getDeserializationConfig().withAnnotationIntrospector
(jacksonAnnotationIntrospector));
mapper.setSerializationConfig(mapper.getSerializationConfig().withAnnotationIntrospector
(jacksonAnnotationIntrospector));
return mapper;
}
}
My Jackson Object looks like this:
#JsonRootName("foobar")
public class TestType {
#JsonProperty("goodbye")
String hello;
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
}
}
As a convienence I also have this in my web.xml, it allows you to request json by just putting .json on the URL rather than setting headers:
<context-param>
<param-name>resteasy.media.type.mappings</param-name>
<param-value>json : application/json, xml : application/xml</param-value>
</context-param>
When I call http://127.0.0.1:8080/api/v1/test.json I get:
{
"foobar": {
"goodbye": "Here is some random string"
}
}
I have posted my full working code here: https://github.com/teacurran/java-experiments/tree/master/stackoverflow-sandbox/Q42416036
The fix was to put the exclusions and the dependencies in the sub-deployment, instead of deployment tag, as I was doing.
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<sub-deployment name="axis.war">
<exclusions>
<module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
<module name="org.jboss.resteasy.resteasy-jettison-provider"/>
</exclusions>
<dependencies>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
</dependencies>
</sub-deployment>

#Autowired are giving Null Pointer Exceptions in SpringBoot CXF application

I have created a SpringBoot CXF soap service from an existing WSDL file. I can now access WSDL from my service running on embedded tomcat from the springboot application. When I am trying to send a request to the service from soap-ui, the control reaches the implementation of the service method and then while it access the #Autowired service layer, it throws all NPE, as the service object is null (I have seen this while debugging). If I manually create (new Service() by commenting out the #Autowired object), the flow can reach the service implementation and then the DAO object fails as it cannot #Autowire the DAO Impl, further when i create the manually DAO Impl object it fails at #PersistenceContext, as it the entity manager is null.
I have made sure service is annotated with #Service, DAO layer with #Repository, still the issue persists. Also i have added #ComponentScan and giving all the package names, still i am getting null for all #Autowired.
Code below: Configuration class
#SpringBootApplication
public class EmWebSvcBootApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(EmWebSvcBootApplication.class, args);
}
public static final String SERVICE_NAME_URL_PATH = "/em";
public static final String EM_ISSUER_SERVICE_NAME_URL_PATH = "/EntitlementIssuer";
#Bean(name=Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public ServletRegistrationBean cxfServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new CXFServlet(), SERVICE_NAME_URL_PATH + "/*");
// Add custom Title to CXF´s ServiceList
Map<String, String> initParameters = servletRegistrationBean.getInitParameters();
initParameters.put("service-list-title", "My Test service");
return servletRegistrationBean;
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), new EntitlementIssuerEndpointImpl());
endpoint.setServiceName(entitlementIssuer_Service().getServiceName());
endpoint.setWsdlLocation(entitlementIssuer_Service().getWSDLDocumentLocation().toString());
endpoint.publish(EM_ISSUER_SERVICE_NAME_URL_PATH);
return endpoint;
}
#Bean EntitlementIssuer_Service entitlementIssuer_Service(){
return new EntitlementIssuer_Service();
}
}
Service class:
#Service
public class EntitlementIssuerServiceImpl implements EntitlementIssuerService {
private static final Logger logger = LoggerFactory.getLogger(EntitlementIssuerServiceImpl.class);
#Autowired
private EntitlementIssuerDAO entitlementIssuerDAO;
#Transactional(readOnly=true)
public List<EntitlementIssuerResponseWrapper> getEntitlementIssuers(EntitlementIssuerRequestWrapper requestWrapper)
throws EMSystemException, EMBusinessException {
try{
daoResponse = entitlementIssuerDAO.findEntitlementIssuers(requestWrapper);
}catch(Throwable t){
logger.error("Error while getting entitlement issuers: " + t.getMessage());
throw new EMSystemException("Error while getting entitlement issuers: " + t.getMessage());
}
}
DAO layer:
#Repository
public class EntitlementIssuerDaoImpl implements EntitlementIssuerDAO{
#PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
#Override
public List<EntitlementIssuer> findEntitlementIssuers(EntitlementIssuerRequestWrapper request) {
Session session = (Session) entityManager.getDelegate();
Criteria criteria = session.createCriteria(EntitlementIssuer.class, "entitlementIssuer");
setupCriteria(request,criteria);
List<EntitlementIssuer> output = criteria.list();
return output;
}
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<em.wsdl.version>2.2.0</em.wsdl.version>
<cxf.version>3.1.7</cxf.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- Apache CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
I have added all the configurations that i am using, any help to fix this is highly appreciated. Basically all the #Autowired services, data layers, and entity managers are not loaded (as i see them as null in the debug).
I have been able to fix the issue based on the info from https://github.com/codecentric/cxf-spring-boot-starter
/**
* Configuration of SOAP Web services
*/
#Configuration
public class EntitlementIssuerServiceSOAPConfig {
#Autowired
private Bus bus;
#Bean
public EntitlementIssuerService getEntitlementIssuerServiceWebServiceImpl() {
return new EntitlementIssuerServiceWebServiceImpl();
}
#Bean (name = "EntitlementIssuerServiceWebService")
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, getEntitlementIssuerServiceWebServiceImpl());
endpoint.publish("/EntitlementIssuerService");
return endpoint;
}
}

AspectJ: #AfterReturning methods not calling

I have a problem with execution of AspectJ pointcuts. My aspect is:
#Component
#Aspect
public class UploadToDefaultAspect {
private static Logger logger = Logger.getLogger(UploadToDefaultAspect.class);
private Sardine sardine;
private String webCloudDataDir;
#Autowired private ConfigurationFactory configuration;
#Autowired private GeoProcessorDAO geoService;
#PostConstruct
private void init() {
webCloudDataDir = configuration.getConfigurationValue(DEFAULT_CLOUD_LOCATION) + DIR_CLOUD_DATA;
}
#AfterReturning(
pointcut = "execution(* web.service.SystemService.uploadGeoTZCSV(..))",
returning = "country")
public void uploadAfterReturning( Country country ) throws CloudException {
// upload stuff
}
}
web.service.SystemService is an interface with several methods including uploadGeoTZCSV:
Country uploadGeoTZCSV( MultipartFile geoTZFile ) throws CSVUploadException;
When I debug uploadGeoTZCSV it works but aspect's method is not calling at all (it is managed by Spring and I see invocation of init() in the logs). Also I have aop configured in the applicationContext.xml:
<aop:aspectj-autoproxy proxy-target-class="true"/>
Spring 4.2.3.RELEASE, AspectJ 1.8.7:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
Where I am wrong?
Thank you.
UPDATE 1. It also does not work when I move AOP configuration into the XML:
<aop:aspectj-autoproxy/>
<!-- AOP beans -->
<bean id="uploadToDefaultAspect" class="web.aop.UploadToDefaultAspect" init-method="init"/>
<aop:config>
<aop:aspect id="uploadToDefaultAspect" ref="uploadToDefaultAspect">
<!-- #AfterReturning -->
<aop:pointcut id="pointCutAfterReturning"
expression="execution(* web.service.SystemService.uploadGeoTZCSV(..))"/>
<aop:after-returning method="uploadGeoTZCSVAfterReturning" returning="country"
pointcut-ref="pointCutAfterReturning"/>
</aop:aspect>
</aop:config>
What is going on?
Finally, I found a solution - just add #EnableAspectJAutoProxy to the implementation of web.service.SystemService:
#Service
#EnableAspectJAutoProxy
public class SystemServiceImpl implements SystemService {