Jersey + Grizzly HTTP + Jackson(未找到媒体类型 =application/xml 的 MessageBodyWriter)

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

我在 POM 依赖项和 Jersey 模块注册之间挣扎,以便根据接受请求 header.[=17 生成 XML and/or JSON 响应=]

这里是 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>

一个简单的注释 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;
    }
}

相关资源

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

配置和模块注册的片段

this.config = new ResourceConfig();
this.config.register(LoggingFeature.class);
this.config.register(JacksonFeature.class);

this.config.register(new JacksonObjectMapperProvider());
...
this.config.register(SystemInfoResource.class);

其中JacksonObjectMapperProvider是下面的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;
    }
}

当我使用 Accept = "application/json" 调用资源时,一切正常。但是当我指定 Accept = "application/xml" grizzly 响应这个异常:

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.run(ServerRuntime.java:329)
        at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
        at org.glassfish.jersey.internal.Errors.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.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

有什么帮助吗?

此致, 卢卡

通常它应该可以正常工作,这意味着 JAXB 支持所需的所有提供程序都应该通过 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 自动注册。

无论如何,如果您想自己手动注册提供程序(否则会是 registed by the AutoDiscoverable),您可以这样做。只需使用您的 ResourceConfig

注册 JaxbMessagingBinderJaxbParamConverterBinder(作为 实例 - 而不是 类)