私は次のクラスにデシリアライズする必要があるjson文字列を持っています
class Data <T> {
int found;
Class<T> hits
}
どうすればいいのですか?これが通常の方法です
mapper.readValue(jsonString, Data.class);
しかし、どのように私はTが何の略であるかについて言及しますか
私は次のクラスにデシリアライズする必要があるjson文字列を持っています
class Data <T> {
int found;
Class<T> hits
}
どうすればいいのですか?これが通常の方法です
mapper.readValue(jsonString, Data.class);
しかし、どのように私はTが何の略であるかについて言及しますか
回答:
TypeReference
使用するジェネリック型ごとにオブジェクトを作成し、それを逆シリアル化に使用する必要があります。例えば -
mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
Data<T>
それはタイプではありません。実際のクラスを指定する必要があります。それ以外はと同じData<Object>
です。
TypeReference
何ですか?それがありますかcom.fasterxml.jackson.core.type
?
それを行うことはできません:のように、完全に解決された型を指定する必要があります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);
}
TypeReference
:return mapper.readValue(json, clazz);
正確には何の問題はここですか?
TypeFactory
..を使用する必要があります。私の回答を編集します。
最初に行うのはシリアライズで、次にデシリアライズを行うことができます。
したがって、シリアライズする場合は、を使用@JsonTypeInfo
して、クラス情報をjsonデータに書き込むようにしてください。あなたができることはこのようなものです:
Class Data <T> {
int found;
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
Class<T> hits
}
次に、逆シリアル化すると、Jacksonがデータを逆シリアル化して、変数ヒットが実際に実行時のクラスになることを確認します。
クラスData <>の場合
ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class, Data.class, Parameter.class);
Data<Parameter> dataParam = mapper.readValue(jsonString,type)
Utilクラスに静的メソッドを記述するだけです。ファイルからJsonを読み取っています。あなたはまたreadValueに文字列を与えることができます
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);
逆シリアル化が必要なJSON文字列には、パラメーターに関する型情報が含まれている必要がありますT
。
パラメーターの型に関する型情報が表示されるように、パラメーターT
としてクラスに渡すことができるすべてのクラスにジャクソンアノテーションを配置する必要がありData
ます。T
を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 2.5から、それを解決するためのエレガントな方法は、
TypeFactory.constructParametricType(Class parametrized、Class ... parameterClasses)メソッドを使用することJavaType
です。
に逆シリアル化したい場合Data<String>
、次のことができます:
// the json variable may be a String, an InputStream and so for...
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class);
Data<String> data = mapper.readValue(json, type);
クラスが複数のパラメーター化された型を宣言した場合は、それほど難しくはないことに注意してください。
class Data <T, U> {
int found;
Class<T> hits;
List<U> list;
}
私たちはできる:
JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class, Integer);
Data<String, Integer> data = mapper.readValue(json, type);
public class Data<T> extends JsonDeserializer implements ContextualDeserializer {
private Class<T> cls;
public JsonDeserializer createContextual(DeserializationContext ctx, BeanProperty prop) throws JsonMappingException {
cls = (Class<T>) ctx.getContextualType().getRawClass();
return this;
}
...
}
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)
Jacksonで汎用JSON文字列をJavaオブジェクトに逆シリアル化するには、次のものが必要です。
JSONクラスを定義します。
属性マッピングを実行します。
最終的なコード、テスト済み、すぐに使用できるもの:
static class MyJSON {
private Map<String, Object> content = new HashMap<>();
@JsonAnySetter
public void setContent(String key, Object value) {
content.put(key, value);
}
}
String json = "{\"City\":\"Prague\"}";
try {
MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class);
String jsonAttVal = myPOJO.content.get("City").toString();
System.out.println(jsonAttVal);
} catch (IOException e) {
e.printStackTrace();
}
重要:
@JsonAnySetter
アノテーションは必須です。これにより、一般的なJSON解析とポピュレーションが保証されます。
ネストされた配列のより複雑なケースについては、Baeldungリファレンスを参照してください:https ://www.baeldung.com/jackson-mapping-dynamic-object