41

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

"CreationDate":1292236718456

起初我以为它是一个 UNIX 时间戳……但它太长了。我的客户端 JS 库在反序列化这种格式时遇到问题(它支持一堆不同的日期格式,但我想不支持这种格式)。我想更改格式,以便我的库可以使用它(例如 ISO)。我该怎么做......我找到了一段可以提供帮助的代码,但是......我应该把它放在哪里,因为我不控制 Jackson 序列化程序实例化(Jersey 可以)?

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;
        }
    }
}
4

8 回答 8

35

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

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

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 中返回新创建的类

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;
      }

}

这样,通过杰克逊进行的所有操作都被赋予了您选择的 ObjectMapper。

编辑:我最近发现,如果您决定扩展 JacksonConfigurator 以添加自定义映射,则使用 RestEasy 2.0.1(以及 Jackson 1.5.3)会出现奇怪的行为。

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> 
于 2011-03-08T15:40:36.867 回答
16

要配置您自己的 ObjectMapper,您需要注入您自己的实现 ContextResolver<ObjectMapper> 的类

究竟如何让球衣捡起来取决于你的国际奥委会(春天,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;
    }
}
于 2011-01-29T06:20:27.303 回答
6

值得一提的是,这个数字是标准的 Java 时间戳(由 JDK 类使用);Unix 存储秒,Java 毫秒,这就是它的值更大的原因。

我希望有一些关于如何将 ObjectMapper 注入 Jersey 的文档(它应该遵循通常的方式来注入提供的对象)。但或者,您可以覆盖 JacksonJaxRsProvider 以指定/配置 ObjectMapper 并注册它;这就是泽西岛本身所做的事情,并且有多种方法可以做到这一点。

于 2010-12-13T17:31:43.993 回答
1

如果您选择在服务器上使用 Joda DateTime 对象并希望序列化为 ISO8601,您可以使用Jackson 的 JodaModule。您可以按如下方式注册 Jersey Provider:

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;
  }
}

更多信息请访问泽西岛的网站

于 2013-10-14T18:20:39.853 回答
1

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

当我意识到收到的日期是时间戳相同正如阿德林在他的问题中一样"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;
      }
}

我希望它也能对你有所帮助。

于 2014-08-29T07:28:33.223 回答
1

下面的代码对我有用 - 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.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);
  }
}
于 2018-06-29T11:03:17.880 回答
-1

用这个重写 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; 
        } 
}
于 2012-04-05T14:15:54.237 回答
-1

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

于 2014-02-24T19:01:59.740 回答