Luca Sepe
Luca Sepe

Reputation: 2445

Jersey + Grizzly HTTP + Jackson (MessageBodyWriter not found for media type=application/xml)

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

Answers (1)

Paul Samsotha
Paul Samsotha

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

Related Questions