web-gelistirme-sc.com

Jackson - Genel sınıfı kullanarak seri hale getirme

Aşağıdaki sınıfa seri hale getirmem gereken bir json stringim var

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

Bunu nasıl yaparım? Bu normal yoldur.

mapper.readValue(jsonString, Data.class);

Ama T'nin neyi temsil ettiğini nasıl anlarım?

90
gnjago

Kullandığınız her genel tür için bir TypeReference nesnesi oluşturmanız ve onu seri kaldırma için kullanmanız gerekir. Örneğin,

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

Bunu yapamazsınız: Data<MyType> gibi tamamen çözülmüş bir tür belirtmelisiniz. T sadece bir değişkendir ve anlamsızdır.

Ancak T öğesinin tanınacağını kastediyorsanız, statik olarak değil, TypeReference 'nin denkini dinamik olarak oluşturmanız gerekir. Başvurulan 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.class);
   return mapper.readValue(json, type);
}
50
StaxMan

Yaptığınız ilk şey serileştirmek, sonra seri hale getirmek olabilir.
bu yüzden serileştirme yaparken, jackson'un sınıf bilgilerini json verilerinize yazmasına izin vermek için @JsonTypeInfo kullanmalısınız. Yapabileceğin şey şunun gibi:

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

Ardından seriyi kaldırdığınızda, jackson'ın verilerinizi gerçekte çalışma zamanında olan bir sınıfa seri hale getirdiğini göreceksiniz.

22
CharlieQ

Sadece Util sınıfında statik bir yöntem yazın. Bir Json'u bir dosyadan okuyorum. Ayrıca 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);
9
AZ_

Veri sınıfı için <> 

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

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 türüdür. Her bir tür için bir sarıcıya ihtiyacınız vardır. Aksi halde Jackson hangi nesneleri yaratacağını bilmiyor.

6
monkjack

Serileştirilmesi gereken JSON dizesinin, T parametresi hakkında tür bilgisi içermesi gerekir.
T parametresi olarak geçirilebilecek her sınıfa Jackson ek açıklamalarını, Data sınıfına koymanız gerekir, böylece T parametre türü hakkında bilgi yazın./JSON stringine Jackson tarafından yazılmıştır.

T öğesinin soyut sınıfı Result genişleten herhangi bir sınıf olabileceğini varsayalım.

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 parametresi olarak geçirilebilecek her sınıfın (veya ortak alt tipinin) her biri açıklamalı olduğunda, Jackson, JSON'da T parametresi hakkında bilgi içerecektir. Böyle bir JSON daha sonra derleme zamanında T parametresini bilmeden seri hale getirilebilir.
Bu Jackson dokümantasyon bağlantısı Polimorfik Serileştirme hakkında konuşuyor ancak bu soruya da atıfta bulunmak için faydalı.

4
Sanjeev Sachdev

Jackson 2.5'ten, parametreli olarak bir Jackson JavaType parametresi tanımlayarak sabit bir şekilde tanımlamayı sağlayan TypeFactory.constructParametricType (Sınıf parametreli, Sınıf ... parametresiClass) yöntemini kullanarak çözmenin zarif bir yolu sınıf ve parametreleştirilmiş türleri.

Data<String> için seriyi kaldırmak istediğinizi varsayalım:

// 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, çoklu parametreleştirilmiş tipler bildirirse, gerçekten zor olmaz:

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);
1
davidxxx

eğer scala kullanıyorsanız ve derleme zamanında jenerik tipini biliyorsanız, ancak TypeReference'ı tüm kullanıcılarınızda her yere 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)
0
nathan g