简体   繁体   中英

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM