2013-07-01 10 views
34

次の質問が乱雑またはそれらは全く答えていないのどちらかであるので、これは重複して質問です:ジャクソンは本当にjsonを汎用タイプにデシリアライズできませんか?

deserializing-a-generic-type-with-jackson

jackson-deserialize-into-runtime-specified-class

jackson-deserialize-using-generic-class

jackson-deserialize-generic-class-variable

私はこのことを願っています最終的には、このことを明確にする答えが見つけられます。

モデルを持つ:

public class AgentResponse<T> { 

    private T result; 

    public AgentResponse(T result) { 
     this.result = result; 
    } 
    public T getResult() { 
     return result; 
    } 
} 

JSON入力:

mapper.readValue(out, new TypeReference<AgentResponse<Map<String, Integer>>>() {}); 

または

JavaType javaType = mapper.getTypeFactory().constructParametricType(AgentResponse.class, Map.class); 
mapper.readValue(out, javaType); 

{"result":{"first-client-id":3,"test-mail-module":3,"third-client-id":3,"second-client-id":3}} 

と2は、ジェネリック型をデシリアライズする方法をお勧めします

ジャクソンはジェネリック型Tを扱うことは決してできません。JavaTypeからのマップですが、型の削除によってオブジェクト型のコンストラクタ引数が見つかり、エラーがスローされます。これはジャクソンのバグですか?何か間違っていますか? TypeReferenceまたはJavaTypeの明示的な仕様は何ですか?

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.fg.mail.smtp.AgentResponse<java.util.Map<java.lang.String,java.lang.Integer>>]: can not instantiate from JSON object (need to add/enable type information?) 
at [Source: [email protected]; line: 1, column: 2] 
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) 
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:984) 
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:276) 
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121) 
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888) 
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2064) 
+0

あなたもリスト – fge

+0

を郵送ジャクソン、ユーザーにその質問を投稿する必要があり、あなたが本当にしようとすると_all_そのJSONまたはちょうどこのJSONの 'result'メンバー値をデシリアライズしますか? – fge

+0

私は、AgentResponseにJSON入力を逆シリアル化しています。どのように、なぜそれを部分的に非直列化するのか分かりません。それはあなたが私の一日保存し、ちょうど一般的な結果があるので、私は質問を修正 – lisak

答えて

49

オブジェクトを構築する方法をジャクソンに伝えるために、コンストラクタにアノテーションを追加する必要があります。以下は私の仕事:

public class AgentResponse<T> { 

    private T result; 

    @JsonCreator 
    public AgentResponse(@JsonProperty("result") T result) { 
     this.result = result; 
    } 
    public T getResult() { 
     return result; 
    } 
} 

@JsonCreator注釈がなければ、ジャクソンはこのコンストラクタを呼び出すために知ることができません。 @JsonPropertyアノテーションがないと、Jacksonはコンストラクタの最初の引数がresultプロパティにマップされていることを知らない。

+3

マンなどのオブジェクト、コレクション、マップであってもよい状況と結果値を持つだけで応答、だ、私はジャクソンがダウンすべての方法をスタックデバッグました私はそれがコンストラクタ引数を見つけたことを知ったので、それは一般的な問題だと思った。実際のところ、実際の問題は、JVMが提供していないコンストラクタの引数名をjacksonが知ることができなかったことです。私はジェネリック薬を使わないで最初に試してみるべきです...ありがとう! – lisak

+4

そして、あなたは直接クラスに注釈を付けることができないか望まない場合は、あなたの代わりにミックスインに注釈を付けることができます。http://wiki.fasterxml.com/JacksonMixInAnnotations – dnault

4

私は同じアプローチを使用しようとしましたが、私はモデルクラスに注釈を付けませんでした。それは私のためにうまくいった。

これは私のモデルクラス

public class BasicMessage<T extends Serializable> implements Message<T> { 
    private MessageHeader messageHeader = new MessageHeader(); 
    private T payload; 
    public MessageHeader getHeaders() { 
     return messageHeader; 
    } 

    public Object getHeader(String key) { 
     return messageHeader.get(key); 
    } 

    public Object addHeader(String key, Object header) { 
     return messageHeader.put(key, header); 
    } 

    public T getPayload() { 
     return payload; 
    } 

    public void setPayload(T messageBody) { 
     this.payload = messageBody; 
    } 
} 

であると私はjsonStringが文字列でBasicMessageObjectが含まれているペイロード

public static <T extends Serializable> BasicMessage<T> getConcreteMessageType(String jsonString, Class<T> classType) { 
     try { 
      ObjectMapper mapper = new ObjectMapper(); 
      JavaType javaType = mapper.getTypeFactory().constructParametricType(BasicMessage.class, classType); 
      return mapper.readValue(jsonString, javaType); 
     } catch (IOException e) { 

     } 
} 

をデシリアライズするために、以下の方法を使用していました。

+0

+1 ...まだあなたが作成したオブジェクトの不変性を失うだろう。それともプライベートセッターでも可能ですか? – Karussell

1

デシリアライズする必要があるJSON文字列には、パラメータTの型情報が含まれている必要があります。
パラメーターTとしてクラスAgentResponseに渡すことができるすべてのクラスにジャクソン注釈を付ける必要があります。その結果、パラメータータイプTに関するタイプ情報は、ジャクソンのJSONストリングとの間で読み書きできます。

は、私たちはTは抽象クラスResultを拡張するすべてのクラスであることを仮定しよう。パラメータTとして渡すことができるクラス(又はそれらの共通のスーパータイプ)のそれぞれが注釈されたら

public class AgentResponse<T extends Result> { 
    public Hits<T> hits; 
} 

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) 
@JsonSubTypes({ 
     @JsonSubTypes.Type(value = ImageResult.class, name = "ImageResult"), 
     @JsonSubTypes.Type(value = NewsResult.class, name = "NewsResult")}) 
public abstract class Result { 

} 

public class ImageResult extends Result { 

} 

public class NewsResult extends Result { 

} 

、ジャクソンはJSONにおけるパラメータTに関する情報を含むことになります。このようなJSONはコンパイル時にパラメータTを知らなくても逆シリアル化できます。
このJackson documentation linkポリモーフィックデシリアライズについての協議が、同様にこの質問のために参照することが有用です。

関連する問題