Jersey + Jackson JSON 日付形式のシリアル化 - 形式を変更する方法、またはカスタム JacksonJsonProvider を使用する方法

StackOverflow https://stackoverflow.com/questions/4428109

質問

私は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;
        }
    }
}
役に立ちましたか?

解決

その価値については、その数は標準のJavaタイムスタンプ(JDKクラスで使用)です。 Unixは秒、Java Millisecondsを保存します。そのため、少し大きい価値があります。

ObjectMapperをジャージーに挿入する方法については、いくつかのドキュメントがあることを願っています(提供されたオブジェクトを注入するための通常の方法に従う必要があります)。ただし、JacksonjaxrsproviderをオーバーライドしてObjectMapperを指定/構成して登録することもできます。これはジャージ自体が行うことであり、それを行うには複数の方法があります。

他のヒント

私はResteasyで「JAX-RS方式」でそれを行うことができたので、Jerseyのようなすべての準拠実装で動作するはずです(最近JEE7サーバーWildfly 8で正常にテストされました。いくつかの変更があったため、Jackson部分にいくつかの変更が必要なだけでした) API)。

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

}

このようにして、jackson を通じて行われるすべての操作に、選択した ObjectMapper が与えられます。

編集:最近、RestEasy 2.0.1 (したがって Jackson 1.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> 

独自のObjectMapperを構成するには、Contextresolverを実装する独自のクラスを注入する必要がありますu003CObjectMapper>

ジャージーにこれを拾わせる方法は、IOC(春、ガイース)に依存するようになります。私は春を使用しています、そして私のクラスは次のように見えます:

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

サーバー上のJoda DateTimeオブジェクトを使用することを選択し、ISO8601にシリアル化する場合は、使用できます ジャクソンのジョダモジュール. 。ジャージープロバイダーを次のように登録できます。

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

で利用可能な詳細 ジャージーのウェブサイト.

同じ問題がありました(Jersey+Jackson+JSONを使用)、クライアントは日付を送信していましたが、データがオブジェクトにマッピングされたときにサーバーで変更されていました。

このリンクを読むことで、これを解決するために他のアプローチに従いました。 http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html, 、受け取った日付がタイムスタンプであることに気付いたとき(彼の質問ではアドリンと同じです。 "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;
      }
}

それがあなたにも役立つことを願っています。

以下のコードが私のために働いた-Jax -Rs1.1、Jersy1.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);
  }
}

これで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; 
        } 
}

json-io(https://github.com/jdereg/json-io)JSON Serialization Libraryの完全なJavaです。 JSON文字列を書くためにそれを使用すると、設定できます どうやって 日付はフォーマットされています。デフォルトでは、日付は長く書かれています(上記のように、1970年1月1日以降のミリ秒です)。ただし、フォーマット文字列またはjava dateformatterを提供し、希望する形式で日付を書くことができます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top