ジャクソンとジェネリック型参照


107

次のように、汎用メソッドにjackson jsonライブラリを使用したいと思います。

public MyRequest<T> tester() {
    TypeReference<MyWrapper<T>> typeRef = new TypeReference<MyWrapper<T>>();  
    MyWrapper<T> requestWrapper = (MyWrapper<T>) JsonConverter.fromJson(jsonRequest, typeRef);
    return requestWrapper.getRequest();
}

...

public class MyWrapper<T> {

    private MyRequest<T> request;

    public MyRequest<T> getRequest() {
        return request;
    }

    public void setRequest(MyRequest<T> request) {
        this.request = request;
    }
}


 public class MyRequest{
     private List<T> myobjects;

     public void setMyObjects(List<T> ets) {
         this.myobjects = ets;
     }

     @NotNull
     @JsonIgnore
     public T getMyObject() {
         return myobjects.get(0);
     }
}

ここで問題は、リクエストオブジェクトの内部にあるgetMyObject()を呼び出すと、入れ子になったカスタムオブジェクトがLinkedHashMapとして返されることです。Tオブジェクトを返す必要があることを指定する方法はありますか?たとえば、タイプがCustomerのオブジェクトを送信した場合、Customerはそのリストから返されますか?。

ありがとう。


GETT()の実装を追加してください
ジム・ギャリソン

この質問はstackoverflow.com/questions/6062011/…に似ていますが、TypeFactoryを使用してタイプを指定することを提案しています。ただし、コンパイル時にタイプがわかりません...
techzen

TypeFactoryには、静的クラスを必要としないメソッドがあります。createCollectionTypeなど。
StaxMan 2011

完全なコードを共有してください。私も同じ問題に直面しています。
AZ_ 2013年

TypeReference抽象的ではありませんか?
カイルデラニー

回答:


194

これは、Java型消去のよく知られた問題です。Tは単なる型変数であり、実際のクラスを、通常はClass引数として示す必要があります。そのような情報がなければ、可能な最善の方法は境界を使用することです。プレーンTは「T extends Object」とほぼ同じです。そして、ジャクソンはJSONオブジェクトをマップとしてバインドします。

この場合、テスターメソッドはクラスにアクセスできる必要があり、

JavaType type = mapper.getTypeFactory().
  constructCollectionType(List.class, Foo.class)

その後

List<Foo> list = mapper.readValue(new File("input.json"), type);

16
それは機能します:私は次のことをしました:JavaType topMost = mapper.getTypeFactory()。constructParametricType(MyWrapper.class、ActualClassRuntime.class); そして、readValueを実行し、それは最終的に機能しました:)
techzen '28 / 07/28

はい、それは機能します-Map / Collectionタイプ以外のジェネリックタイプを作成するためのメソッドを指摘してくれてありがとう!
StaxMan 2011

1
@StaxManは、今後、この種のものにClassMateを使用する方が良いでしょうか?
husayt 2014年

2
@husaytはい、技術的にはjava-classmate libが優れています。しかし、それをジャクソンと統合することは、ジャクソン自身の型の抽象化がAPIの統合された部分であるという理由だけで少しトリッキーです。長期的には、埋め込みまたはdepを介して、Jacksonにクラスメートコードを使用させる適切な方法を見つけるのは素晴らしいことです。
StaxMan 2014年

1
ジャクソンはジェネリックのギャップのように感じるものをカバーする必要があるべきではないように感じますが、どちらにしてもそれは非常にうまくいきます。
エイドリアンベイカー、

6

「JavaType」は機能します!! 私は、json StringのリストをArrayList javaオブジェクトに非整列化(デシリアライズ)しようとしていて、解決策を見つけるのに日々苦労していました。
以下は、最終的に私に解決策を与えたコードです。コード:

JsonMarshallerUnmarshaller<T> {
    T targetClass;

    public ArrayList<T> unmarshal(String jsonString) {
        ObjectMapper mapper = new ObjectMapper();

        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
        mapper.getDeserializationConfig()
            .withAnnotationIntrospector(introspector);

        mapper.getSerializationConfig()
            .withAnnotationIntrospector(introspector);
        JavaType type = mapper.getTypeFactory().
            constructCollectionType(
                ArrayList.class, 
                targetclass.getClass());

        try {
            Class c1 = this.targetclass.getClass();
            Class c2 = this.targetclass1.getClass();
            ArrayList<T> temp = (ArrayList<T>) 
                mapper.readValue(jsonString,  type);
            return temp ;
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null ;
    }  
}

TargetClassを初期化する方法は?
AZ_ 2013年

小さな例を見せてください。Class <?>ターゲットを渡してから、target.getClassName()を取得しています。
AZ_ 2013年

1
次のようにコンストラクタを追加します。JsonMarshallerUnmarshaller <T> {private Class <T> targetClass; JsonMarshallerUnmarshaller(Class <T> c){targetClass = c; あらゆる場所でgetClassを実行する代わりに、このクラスを使用するように 'unmarshal'関数に適切な変更を加えます。
rushidesai1 2013年

いくつかの注意事項:すべての例外がIOException(1つのキャッチのみが必要です)のサブタイプであり、デフォルトのアノテーションイントロスペクターがすでにJacksonAnnotationIntrospector存在しているためObjectMapper、コードを大幅に簡略化できます。
StaxMan 2015年

したがって、このコードはコンパイルすることすらできません。代わりに貼り付けるライブの例がありますか?
2016年

0

rushidesai1の回答実際の例を含むように変更しました

JsonMarshaller.java

import java.io.*;
import java.util.*;

public class JsonMarshaller<T> {
    private static ClassLoader loader = JsonMarshaller.class.getClassLoader();

    public static void main(String[] args) {
        try {
            JsonMarshallerUnmarshaller<Station> marshaller = new JsonMarshallerUnmarshaller<>(Station.class);
            String jsonString = read(loader.getResourceAsStream("data.json"));
            List<Station> stations = marshaller.unmarshal(jsonString);
            stations.forEach(System.out::println);
            System.out.println(marshaller.marshal(stations));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("resource")
    public static String read(InputStream ios) {
        return new Scanner(ios).useDelimiter("\\A").next(); // Read the entire file
    }
}

出力

Station [id=123, title=my title, name=my name]
Station [id=456, title=my title 2, name=my name 2]
[{"id":123,"title":"my title","name":"my name"},{"id":456,"title":"my title 2","name":"my name 2"}]

JsonMarshallerUnmarshaller.java

import java.io.*;
import java.util.List;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;

public class JsonMarshallerUnmarshaller<T> {
    private ObjectMapper mapper;
    private Class<T> targetClass;

    public JsonMarshallerUnmarshaller(Class<T> targetClass) {
        AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();

        mapper = new ObjectMapper();
        mapper.getDeserializationConfig().with(introspector);
        mapper.getSerializationConfig().with(introspector);

        this.targetClass = targetClass;
    }

    public List<T> unmarshal(String jsonString) throws JsonParseException, JsonMappingException, IOException {
        return parseList(jsonString, mapper, targetClass);
    }

    public String marshal(List<T> list) throws JsonProcessingException {
        return mapper.writeValueAsString(list);
    }

    public static <E> List<E> parseList(String str, ObjectMapper mapper, Class<E> clazz)
            throws JsonParseException, JsonMappingException, IOException {
        return mapper.readValue(str, listType(mapper, clazz));
    }

    public static <E> List<E> parseList(InputStream is, ObjectMapper mapper, Class<E> clazz)
            throws JsonParseException, JsonMappingException, IOException {
        return mapper.readValue(is, listType(mapper, clazz));
    }

    public static <E> JavaType listType(ObjectMapper mapper, Class<E> clazz) {
        return mapper.getTypeFactory().constructCollectionType(List.class, clazz);
    }
}

Station.java

public class Station {
    private long id;
    private String title;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return String.format("Station [id=%s, title=%s, name=%s]", id, title, name);
    }
}

data.json

[{
  "id": 123,
  "title": "my title",
  "name": "my name"
}, {
  "id": 456,
  "title": "my title 2",
  "name": "my name 2"
}]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.