Configure Wildfly 10 to use Jackson (as JSON provider) - rest

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>

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

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

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 {

Jersey returns 500 when trying to return an XML response

I'm trying to create my own RESTful WS application using Jersey 2.12 based from this article. I want to return an XML representation of a class depending on the id been passed from the url, however, I'm getting a 500 response code when trying from either Advanced Rest Client Application (google chrome app) or browser. Below are the details:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>WS_RESTful_Practice</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<!-- Register resources and providers under com.vogella.jersey.first package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>test.services</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
TestRestModel.java
package test.model;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class TestRestModel{
/**
*
*/
private static final long serialVersionUID = -8391589100962515747L;
private String name;
private String content;
public TestRestModel(String name, String content){
this.name = name;
this.content = content;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
TestResource.java
package test.services;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import test.dao.TestModelDao;
import test.model.TestRestModel;
#Path("/test")
public class TestResource {
#GET
#Path("{id}")
public Response getModel(#PathParam("id") String id){
return Response.ok().entity(TestModelDao.instance.getModel().get(id)).build();
}
}
TestModelDao.java
package test.dao;
import java.util.HashMap;
import java.util.Map;
import test.model.TestRestModel;
public enum TestModelDao {
instance;
private Map<String, TestRestModel> container = new HashMap<String, TestRestModel>();
private TestModelDao(){
TestRestModel model = new TestRestModel("a", "this is first");
container.put("1", model);
model = new TestRestModel("b", "this is second");
container.put("2", model);
model = new TestRestModel("c", "this is third");
container.put("3", model);
}
public Map<String, TestRestModel> getModel(){
return container;
}
}
I'm totally new to Jersey and REST. And I don't know how to log error from Jersey yet.
This happens when you don't provide a default no arg constructor to your JAXB bean. So in your case you should amend the class by adding one:
public TestRestModel(){
}
This is due to a requirement in the JSR-222:
existing types, authored by users, are required to provide a no arg
constructor. The no arg constructor is used by an unmarshaller during
unmarshalling to create an instance of the type.
Stuff below is not the answer, but will probably help Johne to find out, whats up.
Out of the comments I've extract, that the main problem is, that you don't have any noticeable debug output in your console. So you are not able to find the issue by yourself, rather than give us some logs which would help to find out, what the exact problem could be.
Therefore pls implement an ExceptionMapper first, which will force console output of the stacktrace:
Example:
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class HelpMeExceptionMapper implements ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception e) {
e.printStackTrace();
return Response
.status(Status.INTERNAL_SERVER_ERROR)
.type(MediaType.APPLICATION_JSON)
.entity(e.getCause())
.build();
}
}
The ExceptionMapper has to be in a subpackage of your resource-config/providers path test.services:
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>test.services</param-value>
</init-param>
As i didn't implement your/vogellas code i would like to recommend you, to debug this step by step to find out whats up.
I reckon, that you miss to import something. But who knows ...
Have a nice day ...
To the ones with the same problem, I had something like it but in my case it was a List that i wanted in my response. The source of the problem was that the object had a lazy load relationship and when I used GenericEntity> to return my list the same problem as occurred to me.
Just change to null the relationship or bring the lazy load relation to the object before create GenericEntity> and it will be fine.
We need to understand this problem first
Jersey returns 500 when trying to return an XML response. This issue is coming because of missing dependency in pom.xml and that is:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.2.11</version>
</dependency>
But this is not enough. This will resolve the 500 Error but one more error will come, while using endpoint.
javax.servlet.ServletException: org.glassfish.jersey.server.ContainerException: java.lang.NoClassDefFoundError: com/sun/xml/bind/v2/model/annotation/AnnotationReader
To resolve this you need to add following dependencies too into pom.xml
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.1</version>
</dependency>
So this is the complete solution, to make your Jersey webApp work