Jersey + Jackson JSONdate格式序列化 – 如何更改格式或使用自定义的JacksonJsonProvider

我正在使用Jersey + Jackson为我的应用程序提供REST JSON服务层。 我遇到的问题是默认的date序列化格式如下所示:

"CreationDate":1292236718456 

起初我以为这是一个UNIX时间戳,但是这太长了。 我的客户端JS库有反序列化这种格式的问题(它支持一堆不同的date格式,但不是我想这个)。 我想改变格式,以便它可以被我的库(例如ISO)消耗。 我该怎么做…我发现了一段代码可以帮助,但是…我把它放在哪里,因为我不控制jackson串行器实例化(泽西岛)?

 objectMapper.configure( SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); 

我也发现这个代码为自定义JacksonJsonProvider – 问题是..我如何使所有我的POJO类使用它?

 @Provider public class MessageBodyWriterJSON extends JacksonJsonProvider { 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; } } } 

这个数字是标准的Java时间戳(由JDK类使用)。 Unix存储秒,Java毫秒,这就是为什么它有点大的价值。

我希望有一些关于如何将ObjectMapper注入到Jersey中的文档(它应该按照通常的方式注入提供的对象)。 但是也可以重写JacksonJaxRsProvider来指定/configurationObjectMapper并注册它; 这就是泽西本身所做的事情,有多种方式可以做到。

我设法以Resteasy的“JAX-RS方式”来实现它,所以它应该适用于像Jersey这样的每一个兼容的实现(最近在JEE7服务器Wildfly 8上成功testing过,它只需要对Jackson部分进行一些更改,因为它们改变了一些蜜蜂)。

您必须定义一个ContextResolver(检查Produces包含正确的内容types):

 import javax.ws.rs.ext.ContextResolver; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.DeserializationConfig; import javax.ws.rs.ext.Provider; import javax.ws.rs.Produces; import java.text.SimpleDateFormat; @Provider @Produces("application/json") public class JacksonConfigurator implements ContextResolver<ObjectMapper> { private ObjectMapper mapper = new ObjectMapper(); public JacksonConfigurator() { 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; } } 

然后你必须在你的javax.ws.rs.core.Application的getClasses中返回新创build的类

 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(JacksonConfigurator.class); return classes; } } 

这样通过jackson所做的所有操作都被赋予您所select的ObjectMapper。

编辑:我最近发现在我的开支,使用RestEasy 2.0.1(和jackson1.5.3),有一个奇怪的行为,如果你决定扩展JacksonConfigurator添加自定义映射。

 import javax.ws.rs.core.MediaType; @Provider @Produces(MediaType.APPLICATION_JSON) public class MyJacksonConfigurator extends JacksonConfigurator 

如果你这样做(当然,将扩展类放在RestApplication中),则会使用父类的映射器,即丢失了自定义映射。 为了使其正确工作,我必须做一些对我来说似乎毫无用处的东西:

 public class MyJacksonConfigurator extends JacksonConfigurator implements ContextResolver<ObjectMapper> 

要configuration你自己的ObjectMapper,你需要注入你自己的实现ContextResolver <ObjectMapper>的类

究竟如何让jersey拿起这将取决于你的国际奥委会(春季,guice)。 我使用spring,而我的类看起来像这样:

 import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig.Feature; import org.codehaus.jackson.map.deser.CustomDeserializerFactory; import org.codehaus.jackson.map.deser.StdDeserializerProvider; import org.codehaus.jackson.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; } } 

我有同样的问题(使用Jersey + Jackson + Json),客户端发送一个date,但是当数据映射到对象时,服务器正在更改它。

我遵循其他的方法来解决这个问题,通过阅读这个链接: http : //blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html ,当我意识到收到的date是TimeStamp(相同作为Adrin在他的问题: "creationDate":1292236718456

在我的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; } } 

我希望它也可以帮助你。

用这个重写MessageBodyWriterJSON

 import javax.ws.rs.core.MediaType; import javax.ws.rs.ext.Provider; import org.codehaus.jackson.jaxrs.JacksonJsonProvider; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; @Provider public class MessageBodyWriterJSON extends JacksonJsonProvider { 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; } } 

如果您select使用服务器上的Joda DateTime对象,并想要序列化为ISO8601,则可以使用Jackson的JodaModule 。 您可以按如下方式注册Jersey提供者:

 import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.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; } } 

有关泽西岛网站上的更多信息。

json-io( https://github.com/jdereg/json-io )是JSON序列化库的完整Java。 使用它来编写JSONstring时,可以设置如何格式化date。 默认情况下,date被写出(如上所述,这是从1970年1月1日起的毫秒)。 但是,您可以给它一个格式string或Java DateFormatter,并以您希望的任何格式写入date。