Aşağıdaki sınıfa deSerialize gerekir bir json dize var
class Data <T> {
int found;
Class<T> hits
}
Nasıl yaparım? Bu her zamanki yol
mapper.readValue(jsonString, Data.class);
Fakat T'nin ne anlama geldiğinden nasıl bahsedebilirim?
Aşağıdaki sınıfa deSerialize gerekir bir json dize var
class Data <T> {
int found;
Class<T> hits
}
Nasıl yaparım? Bu her zamanki yol
mapper.readValue(jsonString, Data.class);
Fakat T'nin ne anlama geldiğinden nasıl bahsedebilirim?
Yanıtlar:
TypeReference
Kullandığınız her genel tip için bir nesne oluşturmanız ve bunu serileştirme için kullanmanız gerekir. Örneğin -
mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
Data<T>
, bu bir tür DEĞİL. Gerçek sınıfı belirtmelisiniz; aksi halde aynıdır Data<Object>
.
TypeReference
nedir? değil com.fasterxml.jackson.core.type
mi?
Bunu yapamazsınız: gibi tamamen çözülmüş bir tür belirtmelisiniz Data<MyType>
. T
sadece bir değişkendir ve anlamsızdır.
Ancak T
bunun bilineceğini söylüyorsanız, sadece statik olarak değil, TypeReference
dinamik olarak eşdeğer oluşturmanız gerekir . Referans verilen diğer sorular zaten bundan bahsedebilir, ancak şöyle görünmelidir:
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);
Burada sorun tam olarak nedir?
TypeFactory
.. Cevabımı düzenleyeceğim.
Yaptığınız ilk şey serileştirmek, sonra serileştirmeyi yapabilirsiniz.
serileştirdiğinizde, @JsonTypeInfo
jackson'un sınıf bilgilerini json verilerinize yazmasına izin vermek için kullanmalısınız . Yapabilecekleriniz şöyle:
Class Data <T> {
int found;
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
Class<T> hits
}
Sonra serileştirmeyi kaldırdığınızda, jackson'unuzun değişken isabetlerinizin gerçekte çalışma zamanında olduğu bir sınıfa serileştirilmiş olduğunu göreceksiniz.
Sınıf Verileri için <>
ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructParametrizedType(Data.class, Data.class, Parameter.class);
Data<Parameter> dataParam = mapper.readValue(jsonString,type)
Sadece Util sınıfında statik bir yöntem yazın. Bir dosyadan bir Json okuyorum. String'i readValue öğesine de verebilirsiniz
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())));
}
Kullanımı:
List<TaskBean> list = Util.<List<TaskBean>>convertJsonToPOJO("E:/J2eeWorkspaces/az_workspace_svn/az-client-service/dir1/dir2/filename.json", TaskBean.class);
Genel türünüzün türünü bilen başka bir sınıfa sarabilirsiniz.
Örneğin,
class Wrapper {
private Data<Something> data;
}
mapper.readValue(jsonString, Wrapper.class);
Burada bir şey somut bir tiptir. Reified tip başına bir sargıya ihtiyacınız var. Aksi takdirde Jackson hangi nesneleri yaratacağını bilmiyor.
Deserialize edilmesi gereken JSON dizesi, parametre hakkında tür bilgisini içermelidir T
. Parametre türü hakkında tür bilgilerinin Jackson tarafından JSON dizesine okunabilmesi / yazılabilmesi için , sınıfa
parametre olarak iletilebilen her sınıfa Jackson ek açıklamaları koymanız gerekir .T
Data
T
T
Bunun soyut sınıfı genişleten herhangi bir sınıf olabileceğini varsayalım 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 {
}
Parametre olarak iletilebilen sınıfın her biri (ya da ortak süpertipleri) T
açıklama eklendikten sonra Jackson, JSON'da parametre hakkında bilgi içerir T
. Böyle bir JSON daha sonra T
derleme zamanında parametreyi bilmeden serisini kaldırabilir .
Bu Jackson dokümantasyon bağlantısı Polimorfik Deserializasyon hakkında konuşuyor ancak bu soruya da değinmek faydalı.
Jackson 2.5'ten, parametreleştirilmiş sınıfı ve parametreli türlerini belirleyerek bir Jackson'ı düz olarak tanımlamaya izin veren TypeFactory.constructParametricType (Class parametreli, Class ... parametreClasses) yöntemini kullanarak çözmenin zarif bir yolu
JavaType
.
Sürümü kaldırmak istediğinizi varsayarsak Data<String>
, şunları yapabilirsiniz:
// 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);
Sınıf birden çok parametreli tür bildirirse, bunun daha zor olmayacağını unutmayın:
class Data <T, U> {
int found;
Class<T> hits;
List<U> list;
}
Yapabilirdik :
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 kullanıyorsanız ve derleme zamanında genel türü biliyorsanız, ancak tüm uygulamalarınızda TypeReference'ı manuel olarak geçirmek istemiyorsanız, aşağıdaki kodu kullanabilirsiniz (jackson 2.9.5 ile):
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)
}
Bu şekilde kullanılabilir:
read[List[Map[Int, SomethingToSerialize]]](inputStream)
Genel JSON dizesini Jackson ile Java nesnesine serileştirmek için şunlara ihtiyacınız vardır:
Bir JSON sınıfı tanımlamak için.
Bir öznitelik eşlemesi gerçekleştirin.
Son kod, test edilmiş ve kullanıma hazır:
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();
}
Önemli:
@JsonAnySetter
ek açıklama zorunludur, genel bir JSON ayrıştırma ve popülasyon sağlar.
İç içe dizilerle daha karmaşık durumlar için lütfen Baeldung referansına bakın: https://www.baeldung.com/jackson-mapping-dynamic-object