无法获得jersey 2应用程序使用自定义jackson XmlMapper [英] Cannot get jersey 2 application to use custom jackson XmlMapper

查看:277
本文介绍了无法获得jersey 2应用程序使用自定义jackson XmlMapper的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Jersey 2.22.1和Jackson 2.6.3编写Web应用程序。我的pom.xml看起来像这样:

I'm writing web application using Jersey 2.22.1 and Jackson 2.6.3. My pom.xml looks like this:

<!-- JERSEY -->
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.22.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>2.22.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.22.1</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>2.22.1</version>
    </dependency>
    <dependency>
        <groupId>asm</groupId>
        <artifactId>asm</artifactId>
        <version>3.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.woodstox</groupId>
        <artifactId>woodstox-core-asl</artifactId>
        <version>4.4.1</version>
    </dependency>
    <!-- JACKSON -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.6.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.6.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.6.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>2.6.3</version>
    </dependency>

目标是使用不同的自定义ObjectMapper进行JSON和XML映射。我创建了两个提供者类:
JSONMapperProvider

The goal is to use different custom ObjectMappers for JSON and XML mapping. I've created two provider classes: JSONMapperProvider

    @Provider
    @Produces(MediaType.APPLICATION_JSON)
    public class JSONMapperProvider implements ContextResolver<ObjectMapper> {
    private static ObjectMapper objectMapper;

    public JSONMapperProvider() {
    init();
    }

    public static void init() {
    if (objectMapper == null) {
        objectMapper = new ObjectMapper();
        // SERIALIZATION
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false)
            .setSerializationInclusion(Include.NON_NULL)
            .setSerializationInclusion(Include.NON_EMPTY);
        // DESERIALIZATION
        objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
            .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        // set up ISO 8601 date/time stamp format:
        ObjectMapperProvider.DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("GMT"));
        objectMapper.setDateFormat(ObjectMapperProvider.DATE_FORMAT_ISO8601);
        // Custom deserializer for date which helps deserialization of date
        // without time
        SimpleModule dateDeserializerModule = new SimpleModule("DateDeserializerModule", Version.unknownVersion());
        dateDeserializerModule.addDeserializer(Date.class, new CustomJsonDateDeserializer());
        //objectMapper.registerModule(dateDeserializerModule);
    }
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
    System.out.println("JSONMapperProvider.getContext() called with type: "
        + type);
    return objectMapper;
    }

    private static class CustomJsonDateDeserializer extends JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonParser jsonparser, DeserializationContext deserializationcontext) throws IOException, JsonProcessingException {
        String date = jsonparser.getText();
        try {
        return DateUtil.parseDate(date);
        } catch (ParseException e) {
        throw new RuntimeException(e);
        }
    }
    }
}

和XMLMapperProvider

and XMLMapperProvider

    @Provider
    @Produces({ MediaType.APPLICATION_XML })
    public class XMLMapperProvider implements ContextResolver<ObjectMapper>     {

    private static ObjectMapper objectMapper;

    public XMLMapperProvider() {
    init();
    }

    public static void init() {
    if (objectMapper == null) {
        JacksonXmlModule module = new JacksonXmlModule();
        module.setDefaultUseWrapper(false);
        objectMapper = new XmlMapper(module);
        // SERIALIZATION
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false)
            .setSerializationInclusion(Include.NON_NULL)
            .setSerializationInclusion(Include.NON_EMPTY);
        // DESERIALIZATION
        objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
            .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        // set up ISO 8601 date/time stamp format:
        ObjectMapperProvider.DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("GMT"));
        objectMapper.setDateFormat(ObjectMapperProvider.DATE_FORMAT_ISO8601);
        // Custom deserializer for date which helps deserialization of date
        // without time
        SimpleModule dateDeserializerModule = new SimpleModule("DateDeserializerModule", Version.unknownVersion());
        dateDeserializerModule.addDeserializer(Date.class, new CustomJsonDateDeserializer());
        objectMapper.registerModule(dateDeserializerModule);
    }
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
    System.out.println("XMLMapperProvider.getContext() called with type: "
        + type);
    return objectMapper;
    }

    private static class CustomJsonDateDeserializer extends JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonParser jsonparser, DeserializationContext deserializationcontext) throws IOException, JsonProcessingException {
        String date = jsonparser.getText();
        try {
        return DateUtil.parseDate(date);
        } catch (ParseException e) {
        throw new RuntimeException(e);
        }
    }
    }
}

两者它们在应用程序资源类中注册的相同包中

Both of them are in same package which is registered in Application resource class

@ApplicationPath("resources")
public class CCRestResources extends ResourceConfig {
    public CCRestResources() {
        register(JacksonFeature.class);
        packages("com.cc.rest.jersey");
    }
}

如果我向@Produces的方法发出GET请求( MediaType.APPLICATION_JSON)一切都很好,我的自定义映射器使用。但是,如果我向emthod提出相同的请求@Produces(MediaType.APPLICATION_XML)应用程序使用一些默认映射器而不是我的自定义映射器。如果您有任何想法,请帮忙。
谢谢!

If I make GET request to method that @Produces(MediaType.APPLICATION_JSON) everything is fine and my custom mapper is used. But if I make same request to emthod that @Produces(MediaType.APPLICATION_XML) application use some default mapper not my custom one. Please help if you have any idea. Thanks!

推荐答案

所以有一些事情。首先,您需要的不仅仅是核心Jackson xml依赖项,您需要实际的 jaxrs提供商

So a few things. First you need more than just the core Jackson xml dependency, you need the actual jaxrs provider

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-xml-provider</artifactId>
    <version>${jackson2.version}</version>
</dependency>

然后你应该排除JAXB提供程序,它是Jersey使用的默认提供程序。 (测试时我没有遇到任何问题,但是如果你不打算使用它,我会把它排除在外)。它由 jersey-server 引入,因此您应该明确声明 jersey-server 并排除 jersey-media-jaxb 来自它

Then you should exclude the JAXB provider, which is the default provider used by Jersey. (I had not problems leaving it while testing, but if you're not going to use it, I would just exclude it). It is pulled in by jersey-server, so you should explicitly declare the jersey-server and exclude the jersey-media-jaxb from it

<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-server</artifactId>
    <version>${jersey2.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-jaxb</artifactId>
        </exclusion>
    </exclusions>
</dependency>

然后你需要注册 JacksonJaxbXMLProvider (或只是 JacksonXMLProvider

Then you will need to register the JacksonJaxbXMLProvider (or just the JacksonXMLProvider if you don't need or plan on using JAXB annotations).

public CCRestResources() {
    register(JacksonFeature.class);
    register(JacksonJaxbXMLProvider.class);
    packages("com.cc.rest.jersey");
}

最后你需要参数化 ContextResolver 作为 XmlMapper 类型,而不是 ObjectMapper 。如图所示此处,提供程序为 XmlMapper 查找 ContextResolver ,而不是 ObjectMapper

Then finally you need to parameterize the ContextResolver as a XmlMapper type, not ObjectMapper. As seen here, the provider looks for a ContextResolver for XmlMapper, not ObjectMapper.

这篇关于无法获得jersey 2应用程序使用自定义jackson XmlMapper的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆