Java 泽西岛+;Jackson JSON日期格式序列化-如何更改格式或使用自定义JacksonJsonProvider
我正在使用Jersey+Jackson为我的应用程序提供RESTJSON服务层。我遇到的问题是默认的日期序列化格式如下所示:Java 泽西岛+;Jackson JSON日期格式序列化-如何更改格式或使用自定义JacksonJsonProvider,java,serialization,jersey,jax-rs,jackson,Java,Serialization,Jersey,Jax Rs,Jackson,我正在使用Jersey+Jackson为我的应用程序提供RESTJSON服务层。我遇到的问题是默认的日期序列化格式如下所示: "CreationDate":1292236718456 起初我以为这是一个UNIX时间戳。。。但这太长了。我的客户端JS库在反序列化这种格式时遇到问题(它支持多种不同的日期格式,但我想不是这种格式)。我想更改格式,以便我的库可以使用它(例如ISO)。我该怎么做。。。我找到了一段代码可以帮上忙但是。。。我应该把它放在哪里,因为我不控制Jackson序列化程序实例化(Je
"CreationDate":1292236718456
起初我以为这是一个UNIX时间戳。。。但这太长了。我的客户端JS库在反序列化这种格式时遇到问题(它支持多种不同的日期格式,但我想不是这种格式)。我想更改格式,以便我的库可以使用它(例如ISO)。我该怎么做。。。我找到了一段代码可以帮上忙但是。。。我应该把它放在哪里,因为我不控制Jackson序列化程序实例化(Jersey控制)
我还为customJacksonJsonProvider找到了这段代码-问题是。。如何让我所有的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来指定/配置ObjectMapper并注册它;Jersey本身就是这样做的,有多种方法可以做到这一点。要配置您自己的ObjectMapper,您需要注入实现ContextResolver的类
确切地说,如何让泽西队接手这项比赛将取决于你的国际奥委会(春季,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;
}
}
导入javax.ws.rs.ext.ContextResolver;
导入javax.ws.rs.ext.Provider;
导入org.codehaus.jackson.map.ObjectMapper;
导入org.codehaus.jackson.map.SerializationConfig.Feature;
导入org.codehaus.jackson.map.desr.CustomDeserializerFactory;
导入org.codehaus.jackson.map.desr.StdDeserializerProvider;
导入org.codehaus.jackson.map.ser.CustomSerializerFactory;
导入org.springframework.stereotype.Component;
//告诉斯普林找这个。
@组成部分
//告诉spring它是一个提供者(类型由实现决定)
@提供者
公共类ObjectMapperProvider实现ContextResolver{
@凌驾
公共对象映射器getContext(类类型){
//创建objectMapper。
ObjectMapper ObjectMapper=新的ObjectMapper();
//在这里配置对象映射器,例如。
configure(SerializationConfig.Feature.WRITE_DATES_作为时间戳,false);
返回对象映射器;
}
}
我设法用Resteasy的“JAX-RS方式”实现了这一点,因此它应该适用于像Jersey这样的所有兼容实现(最近在JEE7服务器Wildfly 8上成功测试,它只需要对Jackson部分进行一些更改,因为它们更改了一些API)
您必须定义ContextResolver(检查生成的内容是否包含正确的内容类型):
如果您只是这样做(当然,将扩展类放在RestApplication中),那么将使用父类的映射器,也就是说,您将丢失自定义映射。为了使它正常工作,我不得不做一些对我来说似乎无用的事情:
public class MyJacksonConfigurator extends JacksonConfigurator implements ContextResolver<ObjectMapper>
公共类MyJacksonConfigurator扩展JacksonConfigurator实现ContextResolver
使用以下命令重新编写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;
}
}
导入javax.ws.rs.core.MediaType;
导入javax.ws.rs.ext.Provider;
导入org.codehaus.jackson.jaxrs.JacksonJsonProvider;
导入org.codehaus.jackson.map.ObjectMapper;
导入org.codehaus.jackson.map.SerializationConfig;
@提供者
公共类MessageBodyWriterJSON扩展JacksonJsonProvider{
public MessageBodyWriterJSON(){
}
@凌驾
公共对象映射器locateMapper(类类型,MediaType,MediaType)
{
ObjectMapper mapper=super.locateMapper(类型,mediaType);
//日期时间采用ISO格式“2012-04-07T17:00:00.000+0000”而不是“长”格式
configure(SerializationConfig.Feature.WRITE_DATES_为时间戳,false);
返回映射器;
}
}
如果您选择使用服务器上的Joda DateTime对象并希望序列化为ISO8601,则可以使用。您可以按如下方式注册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;
}
}
导入javax.ws.rs.ext.ContextResolver;
导入javax.ws.rs.ext.Provider;
导入com.fasterxml.jackson.databind.ObjectMapper;
导入com.fasterxml.jackson.databind.SerializationFeature;
导入com.fasterxml.jackson.datatype.joda.JodaModule;
@提供者
公共类MyObjectMapperProvider实现ContextResolver{
最终对象映射器对象映射器;
公共MyObjectMapperProvider(){
objectMapper=新的objectMapper();
/*注册JodaModule以处理Joda DateTime对象*/
registerModule(新的JodaModule());
/*我们希望日期被视为ISO8601,而不是时间戳*/
configure(SerializationFeature.WRITE_DATES_作为时间戳,false);
}
@凌驾
公共对象映射器getContext(类arg0){
返回对象映射器;
}
}
有关的更多信息。json io()是一个完整的Java到/从json序列化库。使用它编写JSON字符串时,可以设置日期的格式。默认情况下,日期写得一样长(如上所述,从1970年1月1日起为毫秒)。但是,您可以给它一个格式字符串或Java DateFormatter,并让它以您想要的任何格式写入日期。我也遇到了同样的问题(使用Jersey+Jackson+Json),客户机正在发送日期,但当数据映射到对象时,它在服务器中被更改
当我意识到收到的日期是一个时间戳时(与Adrin的问题相同:“creationDate”:1292236718456
),我采用了另一种方法来解决这个问题
在我的VO类中,我将此注释添加到属性@XmlJavaTypeAdapter
和al中
import javax.ws.rs.core.MediaType;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class MyJacksonConfigurator extends JacksonConfigurator
public class MyJacksonConfigurator extends JacksonConfigurator implements ContextResolver<ObjectMapper>
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;
}
}
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;
}
}
@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;
}
}
import java.text.SimpleDateFormat;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JsonProvider extends JacksonJaxbJsonProvider {
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);
}
}