AspectJ: #AfterReturning methods not calling - aspectj

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 {

Related

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);
}
}

How to test EJB with TomEE?

I'm using TomEE with Intellij to test my EJB/JPA beans. I saw on this answer that I should use a embedded container to test. I discovered Arquillian on this other answer(from the same question) but as stated on comments, it's difficult to set it up and not user friendly, things beginners like me search for.
Unfortunately I'm not using glassfish-embedded-all dependency as answered, but tomee-embedded. I saw on this official tutorial it should use JTA as well as answered above. But why?
Doing as last link, I was getting this error:
No EJBContainer provider available: no provider names had been found.
Then using a piece of code from #BeforeClass method from this answer. My test is shown below:
Properties properties = new Properties();
properties.setProperty(EJBContainer.PROVIDER, "tomee-embedded");
EJBContainer container = EJBContainer.createEJBContainer(properties);
AccountDao dao = (AccountDao) container.getContext().lookup("java:global/Test/AccountDao");
Where Test is my application name and AccountDao is my Stateless Bean that I want tested. But now I'm getting this error:
Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: PG_CLASS
Although I'm not using HSQLDB, I'm having this error. How can I correctly add some postgresql properties to correctly instantiate my Hibernate entityManager? Here's my persistence.xml:
<persistence-unit name="unitName">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>entity.PersistentEntity.Account</class>
<properties>
<property name="tomee.jpa.factory.lazy" value="true"/>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/click10"/>
<property name="javax.persistence.jdbc.user" value="postgres"/>
<property name="javax.persistence.jdbc.password" value="postgres"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
I have had success with using the TomEE embedded container for unit tests. As with any external JUnit resource it can be managed using a #Rule so I have two classes, the Rule class and a wrapper for the Embedded TomEE.
The wrapper class for the TomEE Container class. Configures an embedded derby datasource, and a user so we can test Basic authentication.
/**
* class for starting an Embedded TomEE server which will scan the classpath and start the application.
* The configuration configures an InMemory derby database, and tells JPA to create tables based on the Entity annotations
*
*/
public class EmbeddedTomEE {
public static final String USERNAME = "aUser";
public static final String PASSWORD = "aPassword";
private Container container;
public void start() {
Configuration configuration = new Configuration();
Properties properties = new Properties();
properties.setProperty("jdbc/UdDB", "new://Resource?type=DataSource");
properties.setProperty("jdbc/UdDB.jdbcDriver", "org.apache.derby.jdbc.EmbeddedDriver");
properties.setProperty("jdbc/UdDB.jdbcUrl", "jdbc:derby:memory:udb;create=true");
properties.setProperty("jdbc/UdDB.username", "SA");
properties.setProperty("jdbc/UdDB.password", "");
properties.setProperty("jdbc/UdDB.jtaManaged", "true");
properties.setProperty("persistence_unit.javax.persistence.schema-generation.database.action", "create");
properties.setProperty("persistence_unit.javax.persistence.sql-load-script-source", "META-INF/testdata.sql");
properties.setProperty("rest-persistence_unit.eclipselink.logging.level", "FINE"); //use 'FINE' for JPA logging
configuration.setProperties(properties);
// use a random port so we can have TomEE running parallel with tests
configuration.randomHttpPort();
configuration.setWebXml("src/main/webapp/WEB-INF/web.xml");
HashMap<String, String> users = new HashMap<>();
users.put(USERNAME, PASSWORD);
configuration.setUsers(users);
HashMap<String, String> roles = new HashMap<>();
roles.put("aUser", "user");
configuration.setRoles(roles);
container = new Container(configuration).deployClasspathAsWebApp();
}
public int getPort() {
return container.getConfiguration().getHttpPort();
}
public void stop() {
container.close();
}
}
The JUnit Rule which takes care of starting the embedded TomEE before each test is executed. We also have some logic to avoid the cost of starting and stopping the container with every test. The class also creates a JAX-RS webClient that can be used to make calls to the applications REST services.
/**
* JUnit rule for running an EmbeddedTomEE in memory. The rule has static state, this is to avoid starting and stopping the embedded container
* with every test. Every time no test are running we start a timer, which is canceled if another test is started. This way the rule works well for a
* single test run inside an IDE, and running multiple tests from Maven.
*
*/
public class EmbeddedTomEERule extends ExternalResource {
private static EmbeddedTomEE tomEE;
private static final AtomicInteger count = new AtomicInteger();
private static Timer timer;
#Override
protected void before() throws Throwable {
startIfNeeded();
if (timer != null) {
timer.cancel();
}
count.incrementAndGet();
}
#Synchronized
private void startIfNeeded() {
if (tomEE == null) {
tomEE = new EmbeddedTomEE();
tomEE.start();
Runtime.getRuntime().removeShutdownHook(new Thread(() -> tomEE.stop()));
}
}
#Override
protected void after() {
int runningTests = count.decrementAndGet();
if (runningTests == 0) {
// stop after some time if no new test are started
timer = new Timer();
timer.schedule(new StopEmbeddedContainer(), 10000);
}
}
public int getPort() {
return tomEE.getPort();
}
/**
* creates a new WebClient that can request data from the specified path
*/
public WebClient getWebClient(String path, MediaType mediatype) {
WebClient client = WebClient.create("http://localhost:" + tomEE.getPort() + "/", Collections.singletonList(new JohnzonProvider()),
EmbeddedTomEE.USERNAME, EmbeddedTomEE.PASSWORD, null)
.path(path).accept(mediatype);
return client;
}
private static class StopEmbeddedContainer extends TimerTask {
#Override
public void run() {
tomEE.stop();
}
}
}
Here is an example of how a Test would look
public class ExampleTest {
#Rule
public EmbeddedTomEERule rule = new EmbeddedTomEERule();
#Test
public void doTest() {
WebClient client = rule.getWebClient("some-endpoint", MediaType.APPLICATION_JSON_TYPE);
Output dto = client.get(Input.class);
}
}
This type of test allows you to test your application at the HTTP layer, and it allows you to place breakpoints in both test and the server code. Technically it may be a stretch to call this a Unit test, but I prefer this type of test when testing more that one component. Since you need a fully functional TomEE you will need to provide a number of external dependencies, in my case it looked like this:
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>${derby.db.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>openejb-core</artifactId>
<version>${openejb-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>openejb-cxf-rs</artifactId>
<version>${openejb-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>openejb-server</artifactId>
<version>${openejb-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>openejb-rest</artifactId>
<version>${openejb-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>tomee-embedded</artifactId>
<version>${openejb-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>

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;
}
}

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

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();
}
}