Reputation: 2445
I'm struggling between POM dependencies and Jersey modules registration in order to produce both XML and/or JSON response based on Accept request header.
Here the dependencies in the POM
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jersey.version>2.25.1</jersey.version>
<jackson.version>2.8.8</jackson.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.1.2</version>
</dependency>
....
</dependencies>
A simple annotated bean
@XmlRootElement
public class SysInfo {
@XmlElement
private int nrOfProcessors;
@XmlElement
private long freePhysicalMemorySize;
@XmlElement
private long totalPhysicalMemorySize;
@XmlElement
private String javaHome;
@XmlElement
private String javaVersion;
@XmlElement
private String osArch;
@XmlElement
private String osName;
@XmlElement
private double processCpuLoad;
@XmlElement
private double systemCpuLoad;
public SysInfo() { }
public int getNrOfProcessors() {
return nrOfProcessors;
}
public void setNrOfProcessors(int nrOfProcessors) {
this.nrOfProcessors = nrOfProcessors;
}
public long getFreePhysicalMemorySize() {
return freePhysicalMemorySize;
}
public void setFreePhysicalMemorySize(long freePhysicalMemorySize) {
this.freePhysicalMemorySize = freePhysicalMemorySize;
}
public long getTotalPhysicalMemorySize() {
return totalPhysicalMemorySize;
}
public void setTotalPhysicalMemorySize(long totalPhysicalMemorySize) {
this.totalPhysicalMemorySize = totalPhysicalMemorySize;
}
public String getJavaHome() {
return javaHome;
}
public void setJavaHome(String javaHome) {
this.javaHome = javaHome;
}
public String getJavaVersion() {
return javaVersion;
}
public void setJavaVersion(String javaVersion) {
this.javaVersion = javaVersion;
}
public String getOsArch() {
return osArch;
}
public void setOsArch(String osArch) {
this.osArch = osArch;
}
public String getOsName() {
return osName;
}
public void setOsName(String osName) {
this.osName = osName;
}
public double getProcessCpuLoad() {
return processCpuLoad;
}
public void setProcessCpuLoad(double processCpuLoad) {
this.processCpuLoad = processCpuLoad;
}
public double getSystemCpuLoad() {
return systemCpuLoad;
}
public void setSystemCpuLoad(double systemCpuLoad) {
this.systemCpuLoad = systemCpuLoad;
}
}
The related resource
@Path("/cat")
public class SystemInfoResource {
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public SysInfo fetchSystemProperties() throws Exception {
SysInfo result = new SysInfo();
try {
OperatingSystemMXBean operatingSystemMXBean =
(OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
result.setProcessCpuLoad(operatingSystemMXBean.getProcessCpuLoad());
result.setSystemCpuLoad(operatingSystemMXBean.getSystemCpuLoad());
result.setTotalPhysicalMemorySize(operatingSystemMXBean.getTotalPhysicalMemorySize());
result.setFreePhysicalMemorySize(operatingSystemMXBean.getFreePhysicalMemorySize());
result.setNrOfProcessors(operatingSystemMXBean.getAvailableProcessors());
} catch (Exception ignore) {
}
result.setJavaHome(System.getProperty("java.home"));
result.setJavaVersion(System.getProperty("java.versione"));
result.setOsArch(System.getProperty("os.arch"));
result.setOsName(System.getProperty("os.name"));
return result;
}
}
The snippet from configuration and modules registration
this.config = new ResourceConfig();
this.config.register(LoggingFeature.class);
this.config.register(JacksonFeature.class);
this.config.register(new JacksonObjectMapperProvider());
...
this.config.register(SystemInfoResource.class);
Where JacksonObjectMapperProvider is the following class
public class JacksonObjectMapperProvider implements ContextResolver<ObjectMapper> {
final private ObjectMapper defaultObjectMapper;
public JacksonObjectMapperProvider() {
defaultObjectMapper = createDefaultMapper();
}
@Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
private static ObjectMapper createDefaultMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
return mapper;
}
}
When I call the resource with Accept = "application/json" everything works. But when I specify Accept = "application/xml" grizzly responds with this exception:
giu 21, 2017 12:09:03 PM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
GRAVE: MessageBodyWriter not found for media type=application/xml;charset=UTF-8, type=class com.example.dmc.core.models.SysInfo, genericType=class com.example.dmc.core.models.SysInfo.
2017-06-21 12:09:03 [grizzly-http-server-1] ERROR c.n.d.j.e.DefaultExceptionMapper - Error handling a request: 80fdaf04b7bfc5d1
javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:90)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.logging.LoggingInterceptor.aroundWriteTo(LoggingInterceptor.java:225)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1130)
at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:711)
at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:444)
at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:434)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:329)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:384)
at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
at java.lang.Thread.run(Unknown Source)
Caused by: org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/xml;charset=UTF-8, type=class com.example.dmc.core.models.SysInfo, genericType=class com.example.dmc.core.models.SysInfo.
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:247)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:106)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:86)
... 21 common frames omitted
Any help?
Regards, Luca
Upvotes: 0
Views: 999
Reputation: 208994
Normally it should just work, meaning all the providers required for JAXB support should be automatically registered through auto-discovery. For some reason the auto-discovery isn't working for you. The only things I can think of that would cause it not to work is if you explicitly disable it, or you are building an uber jar, and the META-INF service files don't get included.
In any case, if you want to manually register the providers yourself (that would otherwise have been registed by the AutoDiscoverable), you can do so. Just register the JaxbMessagingBinder
and JaxbParamConverterBinder
(as instances - not classes) with your ResourceConfig
Upvotes: 1