web-dev-qa-db-ja.com

ジャクソン-ジェネリッククラスを使用した逆シリアル化

Json文字列があり、次のクラスにシリアル化解除する必要があります

class Data <T> {
    int found;
    Class<T> hits
}

どうすればいいのですか?これは通常の方法です

mapper.readValue(jsonString, Data.class);

しかし、Tが何を表すのかをどのように言及すればよいのでしょうか?

107
gnjago

使用するジェネリック型ごとにTypeReferenceオブジェクトを作成し、逆シリアル化に使用する必要があります。例えば、

mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
172
Eser Aygün

それはできません。Data<MyType>のような完全に解決されたタイプを指定する必要があります。 Tは単なる変数であり、無意味です。

しかし、静的にではなく、Tが知られることを意味する場合、TypeReferenceに相当するものを動的に作成する必要があります。参照されている他の質問では、すでにこれに言及している場合がありますが、次のようになります。

public Data<T> read(InputStream json, Class<T> contentClass) {
   JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass);
   return mapper.readValue(json, type);
}
61
StaxMan

最初に行うのはシリアル化で、その後で逆シリアル化を行うことができます。
したがって、シリアライズするときは、@JsonTypeInfoを使用して、jacksonがjsonデータにクラス情報を書き込む必要があります。あなたができることはこのようなものです:

Class Data <T> {
    int found;
    @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
    Class<T> hits
}

その後、デシリアライズすると、jacksonがデータをデシリアライズして、実行時に変数が実際にヒットするクラスにデシリアライズすることがわかります。

25
CharlieQ

クラスData <>の場合

ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class, Data.class, Parameter.class);
Data<Parameter> dataParam = mapper.readValue(jsonString,type)
11
Devesh

Utilクラスに静的メソッドを記述するだけです。ファイルからJsonを読んでいます。 readValueにもStringを与えることができます

public static <T> T convertJsonToPOJO(String filePath, Class<?> target) throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(new File(filePath), objectMapper .getTypeFactory().constructCollectionType(List.class, Class.forName(target.getName())));
}

使用法:

List<TaskBean> list =  Util.<List<TaskBean>>convertJsonToPOJO("E:/J2eeWorkspaces/az_workspace_svn/az-client-service/dir1/dir2/filename.json", TaskBean.class);
9
AZ_

ジェネリック型の型を知っている別のクラスにラップできます。

例えば、

class Wrapper {
 private Data<Something> data;
}
mapper.readValue(jsonString, Wrapper.class);

ここで何かが具体的なタイプです。具象型ごとにラッパーが必要です。それ以外の場合、ジャクソンはどのオブジェクトを作成するかを知りません。

6
monkjack

デシリアライズする必要があるJSON文字列には、パラメータTに関するタイプ情報が含まれている必要があります。
パラメーターTからクラスDataに渡すことができるすべてのクラスにJacksonアノテーションを付ける必要があります。そうすると、パラメータータイプTに関するタイプ情報を読み取ることができます/ JacksonによってJSON文字列に書き込まれます。

Tは、抽象クラスResultを拡張する任意のクラスとすることができます。

class Data <T extends Result> {
    int found;
    Class<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 {

}

パラメーターTとして渡すことができる各クラス(または共通のスーパータイプ)に注釈が付けられると、JacksonはパラメーターTに関する情報をJSONに含めます。このようなJSONは、コンパイル時にパラメーターTを知らなくても逆シリアル化できます。
この Jackson documentation link は、多相デシリアライゼーションについて説明していますが、この質問を参照するのにも役立ちます。

4
Sanjeev Sachdev

scalaを使用していて、コンパイル時にジェネリック型を知っているが、すべてのAPIレイヤーのすべての場所でTypeReferenceを手動で渡したくない場合は、次のコードを使用できます(jackson 2.9.5 ):

def read[T](entityStream: InputStream)(implicit typeTag: WeakTypeTag[T]): T = {

    //nathang: all of this *crazy* scala reflection allows us to handle List[Seq[Map[Int,Value]]]] without passing
    // new TypeReference[List[Seq[Map[Int,Value]]]]](){} to the function

    def recursiveFindGenericClasses(t: Type): JavaType = {
      val current = typeTag.mirror.runtimeClass(t)

      if (t.typeArgs.isEmpty) {
        val noSubtypes = Seq.empty[Class[_]]
        factory.constructParametricType(current, noSubtypes:_*)
      }

      else {
        val genericSubtypes: Seq[JavaType] = t.typeArgs.map(recursiveFindGenericClasses)
        factory.constructParametricType(current, genericSubtypes:_*)
      }

    }

    val javaType = recursiveFindGenericClasses(typeTag.tpe)

    json.readValue[T](entityStream, javaType)
  }

次のように使用できます。

read[List[Map[Int, SomethingToSerialize]]](inputStream)
0
nathan g