java 使用 ObjectMapper + JavaTimeModule 向 Jersey 2 客户端注册 JacksonJsonProvider
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42468133/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Registering HymansonJsonProvider with ObjectMapper + JavaTimeModule to Jersey 2 Client
提问by libnull-dev
I'm trying to marshal response containing ISO formatted timestamp like that:
我正在尝试封送包含 ISO 格式时间戳的响应,如下所示:
{
...
"time" : "2014-07-02T04:00:00.000000Z"
...
}
into ZonedDateTimefield 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 HymansonJsonProviderwith ObjectMapper + JavaTimeModule?
进入ZonedDateTime我的域模型对象中的字段。最终,如果我使用在以下代码段中注释的解决方案,它会起作用。SO 上有许多类似的问题,但我想得到一个具体的答案,另一种使用HymansonJsonProviderwith 的方法有ObjectMapper + JavaTimeModule什么问题?
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
HymansonJsonProvider provider = new HymansonJsonProvider(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(HymansonFeature.class)
.build();
Error I get:
我得到的错误:
javax.ws.rs.client.ResponseProcessingException: com.fasterxml.Hymanson.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
Project dependencies are:
项目依赖是:
compile 'com.fasterxml.Hymanson.datatype:Hymanson-datatype-jdk8:2.8.7'
compile 'com.fasterxml.Hymanson.datatype:Hymanson-datatype-jsr310:2.8.7'
compile 'com.fasterxml.Hymanson.core:Hymanson-core:2.8.7'
compile 'com.fasterxml.Hymanson.core:Hymanson-databind:2.8.7'
compile 'com.fasterxml.Hymanson.core:Hymanson-annotations:2.8.7'
compile 'org.glassfish.jersey.core:jersey-client:2.25.1'
edit
编辑
Deserialization happens in here:
反序列化发生在这里:
CandlesResponse<BidAskCandle> candlesResponse = webTarget.request()
.header(HttpHeaders.AUTHORIZATION,"Bearer "+token)
.accept(MediaType.APPLICATION_JSON)
.get(new GenericType<CandlesResponse<BidAskCandle>>(){});
回答by Paul Samsotha
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-Hymanson
jersey-media-json-Hymanson
This module depends on the native Hymanson module that has the HymansonJsonProvider. When you register the HymansonFeature(that comes with jersey-media-json-Hymanson), it registers its own HymansonJaxbJsonProvider, which seems to take precedence over any that you provide.
此模块依赖于具有HymansonJsonProvider. 当您注册HymansonFeature(随jersey-media-json-Hymanson)时,它会注册自己的HymansonJaxbJsonProvider,这似乎优先于您提供的任何内容。
When you use the ContextResolver, the HymansonJsonProvideractually looks-up that ContextResolverand uses it to resolve the ObjectMapper. That's why it works. Whether you used the HymansonFeatureor registered your own HymansonJsonProvider(without configuring an ObjectMapperfor it) the ContextResovlerwould work.
当您使用 时ContextResolver,HymansonJsonProvider实际上会查找ContextResolver并使用它来解析ObjectMapper. 这就是它起作用的原因。无论您是使用HymansonFeature还是注册自己的HymansonJsonProvider(不ObjectMapper为其配置),ContextResovler都可以使用。
Another thing about the jersey-media-json-Hymansonmodule, it that it participates in Jersey's auto-discoverablemechanism, which registers it's HymansonFeature. 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-Hymanson模块的另一件事,它参与 Jersey 的自动发现机制,该机制将其注册为HymansonFeature. 所以即使你没有明确注册它,它仍然会被注册。避免它被注册的唯一方法是:
- Disable the auto-discovery (as mention in the previous link)
- Don't use the
jersey-media-json-Hymanson. Just use the Hymanson native moduleHymanson-jaxrs-json-provider. Thing about this though is that, thejersey-media-json-Hymansonadds 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
HymansonJaxbJsonProviderinstead ofHymansonJsonProvider, it might work. If you look at the source for theHymansonFeature, you will see that it checks for an already registeredHymansonJaxbJsonProvider. If there is one, it won't register it's own.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
HymansonJaxbJsonProvider. Something you can test out.
- 禁用自动发现(如上一个链接中所述)
- 不要使用
jersey-media-json-Hymanson. 只需使用 Hymanson 本机模块Hymanson-jaxrs-json-provider。不过,关于这一点的问题是,它jersey-media-json-Hymanson在本机模块之上添加了一些功能,因此您会丢失这些功能。 尚未测试,但似乎如果您使用
HymansonJaxbJsonProvider而不是HymansonJsonProvider,它可能会起作用。如果您查看 的源HymansonFeature,您将看到它检查已注册的HymansonJaxbJsonProvider. 如果有,它不会注册它自己的。我不确定的一件事是自动发现。它注册的顺序,如果它会影响它是否会捕获您注册的
HymansonJaxbJsonProvider. 你可以测试的东西。
回答by Mircea Stanciu
From my pet project:
从我的宠物项目:
<dependency>
<groupId>com.fasterxml.Hymanson.datatype</groupId>
<artifactId>Hymanson-datatype-jsr310</artifactId>
<version>${Hymanson.version}</version>
</dependency>
public WebTarget getTarget(URI uri) {
Client client = ClientBuilder
.newClient()
.register(HymansonConfig.class);
return client.target(uri);
}
where
在哪里
@Provider
public class HymansonConfig implements ContextResolver<ObjectMapper> {
private final ObjectMapper objectMapper;
public HymansonConfig() {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
@Override
public ObjectMapper getContext(Class<?> aClass) {
return objectMapper;
}
}
回答by Darshan Mehta
Hymanson configuration looks fine, I tried the following and was able to deserialize the value:
Hymanson 配置看起来不错,我尝试了以下操作并能够反序列化该值:
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
Model model = mapper.readValue("{\"time\" : \"2014-07-02T04:00:00.000000Z\"}", Model.class);
System.out.println(model.getTime());
}
}
class Model{
private ZonedDateTime time;
public ZonedDateTime getTime() {
return time;
}
public void setTime(ZonedDateTime time) {
this.time = time;
}
}
I can reproduce it by commenting out mapper.registerModule(new JavaTimeModule());. So, it looks like jersey client is not using custom mapperinstance. Could you try configuring it as described here.
我可以通过注释来重现它mapper.registerModule(new JavaTimeModule());。所以,看起来 jersey 客户端没有使用自定义mapper实例。您可以尝试按照此处所述进行配置吗?

