Java Jersey + Jackson JSON 日期格式序列化 - 如何更改格式或使用自定义 JacksonJsonProvider
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4428109/
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
Jersey + Hymanson JSON date format serialization - how to change the format or use custom HymansonJsonProvider
提问by adrin
I am using Jersey + Hymanson to provide REST JSON services layer for my application. The problem I have is that the default Date serialization format looks like that:
我正在使用 Jersey + Hymanson 为我的应用程序提供 REST JSON 服务层。我遇到的问题是默认的日期序列化格式如下所示:
"CreationDate":1292236718456
At first I thought it is a UNIX timestamp... but it is too long for that. My client-side JS library has problems deserializing this format (it supports a bunch of different date formats but not this one I suppose). I want to change the format so that it can be consumable by my library (to ISO for example). How do I do that... I found a piece of code that could help but... where do I put it as I don't control the Hymanson serializer instantiation (Jersey does)?
起初我以为这是一个 UNIX 时间戳……但它太长了。我的客户端 JS 库在反序列化这种格式时遇到了问题(它支持一堆不同的日期格式,但我认为不支持这种格式)。我想更改格式,以便我的库可以使用它(例如 ISO)。我该怎么做……我找到了一段可以提供帮助的代码,但是……我应该把它放在哪里,因为我不控制 Hymanson 序列化程序实例化(泽西岛可以)?
objectMapper.configure(
SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
I also found this code for custom HymansonJsonProvider
- the question is .. how do I make all my POJO classes use it?
我还发现了这个自定义代码HymansonJsonProvider
- 问题是..如何让我的所有 POJO 类都使用它?
@Provider
public class MessageBodyWriterJSON extends HymansonJsonProvider {
private static final String DF = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
@Override
public boolean isWriteable(Class arg0, Type arg1, Annotation[] arg2,
MediaType arg3) {
return super.isWriteable(arg0, arg1, arg2,
arg3);
}
@Override
public void writeTo(Object target, Class arg1, Type arg2, Annotation[] arg3,
MediaType arg4, MultivaluedMap arg5, OutputStream outputStream)
throws IOException, WebApplicationException {
SimpleDateFormat sdf=new SimpleDateFormat(DF);
ObjectMapper om = new ObjectMapper();
om.getDeserializationConfig().setDateFormat(sdf);
om.getSerializationConfig().setDateFormat(sdf);
try {
om.writeValue(outputStream, target);
} catch (JsonGenerationException e) {
throw e;
} catch (JsonMappingException e) {
throw e;
} catch (IOException e) {
throw e;
}
}
}
采纳答案by StaxMan
For what it's worth, that number is standard Java timestamp (used by JDK classes); Unix stores seconds, Java milliseconds, which is why it's bit larger value.
就其价值而言,该数字是标准 Java 时间戳(由 JDK 类使用);Unix 存储秒,Java 毫秒,这就是为什么它的值更大一些。
I would hope there are some documents as to how to inject ObjectMapper into Jersey (it should follow the usual way to inject provided object). But alternatively you could override HymansonJaxRsProvider to specify/configure ObjectMapper and register that; this is what Jersey itself does, and there are multiple ways to do it.
我希望有一些关于如何将 ObjectMapper 注入 Jersey 的文档(它应该按照通常的方式注入提供的对象)。但是,您也可以覆盖 HymansonJaxRsProvider 来指定/配置 ObjectMapper 并注册它;这就是 Jersey 本身所做的,并且有多种方法可以做到。
回答by Mark
To configure your own ObjectMapper, you need to inject your own class that implements ContextResolver<ObjectMapper>
要配置您自己的 ObjectMapper,您需要注入您自己的实现 ContextResolver<ObjectMapper> 的类
Exactly how to get jersey to pick this up will kind of depend on your IOC (spring, guice). I use spring, and my class looks something like this:
究竟如何让球衣捡起来取决于你的国际奥委会(春季,吉斯)。我使用 spring,我的班级看起来像这样:
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.codehaus.Hymanson.map.ObjectMapper;
import org.codehaus.Hymanson.map.SerializationConfig.Feature;
import org.codehaus.Hymanson.map.deser.CustomDeserializerFactory;
import org.codehaus.Hymanson.map.deser.StdDeserializerProvider;
import org.codehaus.Hymanson.map.ser.CustomSerializerFactory;
import org.springframework.stereotype.Component;
// tell spring to look for this.
@Component
// tell spring it's a provider (type is determined by the implements)
@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
@Override
public ObjectMapper getContext(Class<?> type) {
// create the objectMapper.
ObjectMapper objectMapper = new ObjectMapper();
// configure the object mapper here, eg.
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
}
回答by Riccardo Cossu
I managed to do it in Resteasy "the JAX-RS way", so it should work on every compliant implementation like Jersey (recently successfully tested on JEE7 server Wildfly 8, it just required a few changes to the Hymanson part because they changed a few APIs).
我设法在 Resteasy“JAX-RS 方式”中做到了,所以它应该适用于每个兼容的实现,比如 Jersey(最近在 JEE7 服务器 Wildfly 8 上成功测试,它只需要对 Hymanson 部分进行一些更改,因为他们更改了一些蜜蜂)。
You must define a ContextResolver (check that Produces contains the correct content-type):
您必须定义一个 ContextResolver(检查 Produces 包含正确的内容类型):
import javax.ws.rs.ext.ContextResolver;
import org.codehaus.Hymanson.map.ObjectMapper;
import org.codehaus.Hymanson.map.SerializationConfig;
import org.codehaus.Hymanson.map.DeserializationConfig;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.Produces;
import java.text.SimpleDateFormat;
@Provider
@Produces("application/json")
public class HymansonConfigurator implements ContextResolver<ObjectMapper> {
private ObjectMapper mapper = new ObjectMapper();
public HymansonConfigurator() {
SerializationConfig serConfig = mapper.getSerializationConfig();
serConfig.setDateFormat(new SimpleDateFormat(<my format>));
DeserializationConfig deserializationConfig = mapper.getDeserializationConfig();
deserializationConfig.setDateFormat(new SimpleDateFormat(<my format>));
mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
}
@Override
public ObjectMapper getContext(Class<?> arg0) {
return mapper;
}
}
Then you must return the newly created class in your javax.ws.rs.core.Application's getClasses
然后你必须在你的 javax.ws.rs.core.Application 的 getClasses 中返回新创建的类
import javax.ws.rs.core.Application;
public class RestApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
// your classes here
classes.add(HymansonConfigurator.class);
return classes;
}
}
this way all operation made through Hymanson are given the ObjectMapper of your choice.
这样,所有通过 Hymanson 进行的操作都会获得您选择的 ObjectMapper。
EDIT: I recently found out at my expenses that using RestEasy 2.0.1 (and thus Hymanson 1.5.3) there is a strange behaviour if you decide to extend the HymansonConfigurator to add custom mappings.
编辑:我最近发现使用 RestEasy 2.0.1(以及 Hymanson 1.5.3)如果您决定扩展 HymansonConfigurator 以添加自定义映射,则会出现奇怪的行为。
import javax.ws.rs.core.MediaType;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class MyHymansonConfigurator extends HymansonConfigurator
If you just do like this (and of course put the extended class in RestApplication) the mapper of the parent class is used, that is you lose the custom mappings. To make it correctly work I had to do something that seems useless to me otherwise:
如果您只是这样做(当然将扩展类放在 RestApplication 中),则使用父类的映射器,即您丢失了自定义映射。为了使其正常工作,我必须做一些对我来说似乎无用的事情:
public class MyHymansonConfigurator extends HymansonConfigurator implements ContextResolver<ObjectMapper>
回答by user699634
Re-write the MessageBodyWriterJSON with this
用这个重写 MessageBodyWriterJSON
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.codehaus.Hymanson.jaxrs.HymansonJsonProvider;
import org.codehaus.Hymanson.map.ObjectMapper;
import org.codehaus.Hymanson.map.SerializationConfig;
@Provider
public class MessageBodyWriterJSON extends HymansonJsonProvider {
public MessageBodyWriterJSON (){
}
@Override
public ObjectMapper locateMapper(Class<?> type, MediaType mediaType)
{
ObjectMapper mapper = super.locateMapper(type, mediaType);
//DateTime in ISO format "2012-04-07T17:00:00.000+0000" instead of 'long' format
mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
return mapper;
}
}
回答by lorcan
If you choose to work with Joda DateTime objects on your server and want to serialize to ISO8601 you could use Hymanson's JodaModule. You can register a Jersey Provider as follows:
如果您选择在服务器上使用 Joda DateTime 对象并希望序列化为 ISO8601,则可以使用Hymanson 的 JodaModule。您可以按如下方式注册泽西岛提供商:
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.Hymanson.databind.ObjectMapper;
import com.fasterxml.Hymanson.databind.SerializationFeature;
import com.fasterxml.Hymanson.datatype.joda.JodaModule;
@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper objectMapper;
public MyObjectMapperProvider() {
objectMapper = new ObjectMapper();
/* Register JodaModule to handle Joda DateTime Objects. */
objectMapper.registerModule(new JodaModule());
/* We want dates to be treated as ISO8601 not timestamps. */
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
@Override
public ObjectMapper getContext(Class<?> arg0) {
return objectMapper;
}
}
More information available on Jersey's website.
泽西岛的网站上提供了更多信息。
回答by John DeRegnaucourt
json-io (https://github.com/jdereg/json-io) is a complete Java to / from JSON serialization library. When using it to write the JSON string, you can set howdates are formatted. By default, dates are written out as long (as above, which is milliseconds since Jan 1, 1970). However, you can give it a format String or Java DateFormatter and have the dates written in whatever format you wish.
json-io ( https://github.com/jdereg/json-io) 是一个完整的 Java 到/从 JSON 序列化库。当用它来写JSON字符串,您可以设置如何日期的格式。默认情况下,日期的写出时间一样长(如上所示,自 1970 年 1 月 1 日以来的毫秒数)。但是,您可以给它一个格式 String 或 Java DateFormatter,并以您希望的任何格式写入日期。
回答by Ignacio Rubio
I had the same problem (using Jersey+Hymanson+Json), the client was sending a date, but it was being changed in the server when the data was mapped into the object.
我遇到了同样的问题(使用 Jersey+Hymanson+Json),客户端正在发送一个日期,但是当数据映射到对象时,它在服务器中被更改。
I followed other approach to solve this, by reading this link: http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html, when I realized that the date received was a TimeStamp (the same as Adrin in his question: "creationDate":1292236718456
)
我按照其他方法来解决这个问题,通过阅读这个链接:http: //blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html,当我意识到收到的日期是一个时间戳(相同如Adrin在他的问题:"creationDate":1292236718456
)
In my VO class I added this annotation to the attribute @XmlJavaTypeAdapter
and also implemented an inner class wich extended XmlAdapter
:
在我的 VO 类中,我将此注释添加到属性中@XmlJavaTypeAdapter
,并实现了一个扩展的内部类XmlAdapter
:
@XmlRootElement
public class MyClassVO {
...
@XmlJavaTypeAdapter(DateFormatterAdapter.class)
Date creationDate;
...
private static class DateFormatterAdapter extends XmlAdapter<String, Date> {
@Override
public Date unmarshal(final String v) throws Exception {
Timestamp stamp = new Timestamp(new Long(v));
Date date = new Date(stamp.getTime());
return date;
}
}
I hope it could help to you also.
我希望它也能对你有所帮助。
回答by Prasobh.Kollattu
Below code worked for me - JAX-RS 1.1, Jersy 1.8
下面的代码对我有用 - JAX-RS 1.1, Jersy 1.8
import java.text.SimpleDateFormat;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.codehaus.Hymanson.jaxrs.HymansonJaxbJsonProvider;
import org.codehaus.Hymanson.map.DeserializationConfig;
import org.codehaus.Hymanson.map.ObjectMapper;
import org.codehaus.Hymanson.map.SerializationConfig;
import org.codehaus.Hymanson.map.annotate.JsonSerialize.Inclusion;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JsonProvider extends HymansonJaxbJsonProvider {
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
// allow only non-null fields to be serialized
objectMapper.getSerializationConfig().setSerializationInclusion(Inclusion.NON_NULL);
SerializationConfig serConfig = objectMapper.getSerializationConfig();
serConfig.setDateFormat(new SimpleDateFormat(<your date format>));
DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig();
deserializationConfig.setDateFormat(new SimpleDateFormat(<your date format>));
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
}
public JsonProvider() {
super.setMapper(objectMapper);
}
}