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。