使用ObjectMapper + JavaTimeModule将JacksonJsonProvider注册到Jersey 2客户端 [英] Registering JacksonJsonProvider with ObjectMapper + JavaTimeModule to Jersey 2 Client

查看:390
本文介绍了使用ObjectMapper + JavaTimeModule将JacksonJsonProvider注册到Jersey 2客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试封送包含ISO格式时间戳的响应,

I'm trying to marshal response containing ISO formatted timestamp like that:

{
...
    "time" : "2014-07-02T04:00:00.000000Z"
...
}

进入我的域模型对象中的ZonedDateTime字段.如果我使用以下代码段中注释的解决方案,最终会奏效.SO上有很多类似的问题,但我想得到一个具体的答案 将JacksonJsonProviderObjectMapper + JavaTimeModule结合使用的另一种方法有什么问题?

into ZonedDateTime field in my domain model object. Eventually it works if I use solution that is commented in following snippet.There are many similar questions on SO but I would like to get a specific answer what is wrong with another approach which uses JacksonJsonProvider with ObjectMapper + JavaTimeModule?

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        JacksonJsonProvider provider = new JacksonJsonProvider(mapper);
        Client client = ClientBuilder.newBuilder()
//                .register(new ObjectMapperContextResolver(){
//                    @Override
//                    public ObjectMapper getContext(Class<?> type) {
//                        ObjectMapper mapper = new ObjectMapper();
//                        mapper.registerModule(new JavaTimeModule());
//                        return mapper;
//                    }
//                })
                .register(provider)
                .register(JacksonFeature.class)
                .build();

我得到的错误:

javax.ws.rs.client.ResponseProcessingException: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.ZonedDateTime: no String-argument constructor/factory method to deserialize from String value ('2017-02-24T20:46:05.000000Z')
 at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@53941c2f

项目依赖项是:

compile 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.8.7'
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.7'
compile 'com.fasterxml.jackson.core:jackson-core:2.8.7'
compile 'com.fasterxml.jackson.core:jackson-databind:2.8.7'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.8.7'
compile 'org.glassfish.jersey.core:jersey-client:2.25.1'

编辑

反序列化发生在这里:

CandlesResponse<BidAskCandle> candlesResponse = webTarget.request()
                .header(HttpHeaders.AUTHORIZATION,"Bearer "+token)
                .accept(MediaType.APPLICATION_JSON)
                .get(new GenericType<CandlesResponse<BidAskCandle>>(){});

推荐答案

最终,如果我使用以下代码段中注释的解决方案,它就可以工作.

Eventually it works if I use solution that is commented in following snippet.

首先,您在列表中也缺少一个依赖项,这就是问题所在.

First of all, you are missing a dependency in your list, that you also have, which is the problem.

jersey-media-json-jackson

此模块取决于具有JacksonJsonProvider的本地Jackson模块.注册JacksonFeature(与jersey-media-json-jackson一起提供)时,它会注册自己的JacksonJaxbJsonProvider,它似乎优先于您提供的任何内容.

This module depends on the native Jackson module that has the JacksonJsonProvider. When you register the JacksonFeature (that comes with jersey-media-json-jackson), it registers its own JacksonJaxbJsonProvider, which seems to take precedence over any that you provide.

使用ContextResolver时,JacksonJsonProvider实际上会查找该ContextResolver并使用它来解析ObjectMapper.这就是为什么它起作用.无论您使用JacksonFeature还是注册了自己的JacksonJsonProvider(未为其配置ObjectMapper),ContextResovler都可以使用.

When you use the ContextResolver, the JacksonJsonProvider actually looks-up that ContextResolver and uses it to resolve the ObjectMapper. That's why it works. Whether you used the JacksonFeature or registered your own JacksonJsonProvider (without configuring an ObjectMapper for it) the ContextResovler would work.

关于jersey-media-json-jackson模块的另一件事,它参与了Jersey的 auto-discoverable 机制,将其注册为JacksonFeature.因此,即使您没有显式注册它,它仍然会被注册.避免被注册的唯一方法是:

Another thing about the jersey-media-json-jackson module, it that it participates in Jersey's auto-discoverable mechanism, which registers it's JacksonFeature. So even if you didn't explicitly register it, it would still be registered. The only ways to avoid it being registered are to:

  1. 停用自动发现功能(如上一个链接中所述)
  2. 请勿使用jersey-media-json-jackson.只需使用Jackson的本机模块jackson-jaxrs-json-provider.不过,关于这一点的事情是,jersey-media-json-jackson在本机模块的顶部添加了一些功能,因此您将失去这些功能.
  3. 尚未测试,但似乎如果使用JacksonJaxbJsonProvider而不是JacksonJsonProvider,则可能有效.如果您查看

  1. Disable the auto-discovery (as mention in the previous link)
  2. Don't use the jersey-media-json-jackson. Just use the Jackson native module jackson-jaxrs-json-provider. Thing about this though is that, the jersey-media-json-jackson adds a couple features on top of the the native module, so you would lose those.
  3. Haven't tested, but it seems that if you use JacksonJaxbJsonProvider instead of JacksonJsonProvider, it might work. If you look at the source for the JacksonFeature, you will see that it checks for an already registered JacksonJaxbJsonProvider. If there is one, it won't register it's own.

对此我不确定的一件事是自动发现.它的注册顺序(如果会影响它是否捕获了您注册的JacksonJaxbJsonProvider).您可以测试的东西.

The one thing I'm not sure about with this is the auto-discoverable. The order in which it is registered, if it will affect whether or not it catches your registered JacksonJaxbJsonProvider. Something you can test out.

这篇关于使用ObjectMapper + JavaTimeModule将JacksonJsonProvider注册到Jersey 2客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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