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 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 HymansonJsonProvider
with ObjectMapper + JavaTimeModule
?
进入ZonedDateTime
我的域模型对象中的字段。最终,如果我使用在以下代码段中注释的解决方案,它会起作用。SO 上有许多类似的问题,但我想得到一个具体的答案,另一种使用HymansonJsonProvider
with 的方法有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 HymansonJsonProvider
actually looks-up that ContextResolver
and uses it to resolve the ObjectMapper
. That's why it works. Whether you used the HymansonFeature
or registered your own HymansonJsonProvider
(without configuring an ObjectMapper
for it) the ContextResovler
would work.
当您使用 时ContextResolver
,HymansonJsonProvider
实际上会查找ContextResolver
并使用它来解析ObjectMapper
. 这就是它起作用的原因。无论您是使用HymansonFeature
还是注册自己的HymansonJsonProvider
(不ObjectMapper
为其配置),ContextResovler
都可以使用。
Another thing about the jersey-media-json-Hymanson
module, 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-Hymanson
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
HymansonJaxbJsonProvider
instead 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 mapper
instance. Could you try configuring it as described here.
我可以通过注释来重现它mapper.registerModule(new JavaTimeModule());
。所以,看起来 jersey 客户端没有使用自定义mapper
实例。您可以尝试按照此处所述进行配置吗?