使用ObjectMapper + JavaTimeModule将JacksonJsonProvider注册到Jersey 2客户端 [英] Registering JacksonJsonProvider with ObjectMapper + JavaTimeModule to Jersey 2 Client
问题描述
我正在尝试封送包含ISO格式时间戳的响应,
I'm trying to marshal response containing ISO formatted timestamp like that:
{
...
"time" : "2014-07-02T04:00:00.000000Z"
...
}
进入我的域模型对象中的ZonedDateTime
字段.如果我使用以下代码段中注释的解决方案,最终会奏效.SO上有很多类似的问题,但我想得到一个具体的答案
将JacksonJsonProvider
与ObjectMapper + 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:
- 停用自动发现功能(如上一个链接中所述)
- 请勿使用
jersey-media-json-jackson
.只需使用Jackson的本机模块jackson-jaxrs-json-provider
.不过,关于这一点的事情是,jersey-media-json-jackson
在本机模块的顶部添加了一些功能,因此您将失去这些功能. -
尚未测试,但似乎如果使用
JacksonJaxbJsonProvider
而不是JacksonJsonProvider
,则可能有效.如果您查看
- Disable the auto-discovery (as mention in the previous link)
- Don't use the
jersey-media-json-jackson
. Just use the Jackson native modulejackson-jaxrs-json-provider
. Thing about this though is that, thejersey-media-json-jackson
adds a couple features on top of the the native module, so you would lose those. Haven't tested, but it seems that if you use
JacksonJaxbJsonProvider
instead ofJacksonJsonProvider
, it might work. If you look at the source for theJacksonFeature
, you will see that it checks for an already registeredJacksonJaxbJsonProvider
. 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屋!