Jackson ve genel tür başvurusu


107

Aşağıdaki gibi genel bir yöntem için jackson json kitaplığını kullanmak istiyorum:

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);
     }
}

Şimdi sorun şu ki, jackson istek nesnesinin içindeki getMyObject () 'i çağırdığımda yuvalanmış özel nesneyi LinkedHashMap olarak döndürüyor. T nesnesinin iade edilmesi gerektiğini belirtmenin herhangi bir yolu var mı? Örneğin: Müşteri türünde bir nesne gönderirsem, Müşteri bu Listeden iade edilmeli ?.

Teşekkürler.


Lütfen getT () uygulamasını ekleyin
Jim Garrison

Bu soru stackoverflow.com/questions/6062011/… 'e benzer, ancak TypeFactory kullanarak tür belirtmeyi önerdiler. Ancak, derleme zamanında türü bilmiyorum ...
techzen

TypeFactory, statik sınıfa ihtiyaç duymayan yöntemlere sahiptir; createCollectionType vb.
StaxMan

Lütfen tam kodu paylaşın. Ben de aynı sorunla karşı karşıyayım.
AZ_

TypeReferenceSoyut değil mi?
Kyle Delaney

Yanıtlar:


195

Bu, Java türü silme ile ilgili iyi bilinen bir sorundur: T yalnızca bir tür değişkenidir ve gerçek sınıfı, genellikle Sınıf bağımsız değişkeni olarak belirtmeniz gerekir. Bu tür bilgiler olmadan yapılabilecek en iyi şey sınırları kullanmaktır; ve düz T kabaca 'T extends Object' ile aynıdır. Ve Jackson daha sonra JSON Nesnelerini Haritalar olarak bağlayacaktır.

Bu durumda, test kullanıcısı yönteminin Sınıfa erişmesi gerekir ve

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

ve sonra

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

16
Çalışır: Aşağıdakileri yaptım: JavaType topMost = mapper.getTypeFactory (). ConstructParametricType (MyWrapper.class, ActualClassRuntime.class); ve sonra readValue yaptım ve sonunda çalıştı :)
techzen

Evet, işe yarıyor - Harita / Koleksiyon türü dışında genel tür oluşturma yöntemine işaret ettiğiniz için teşekkürler!
StaxMan

1
@StaxMan bundan böyle bu tür şeyler için ClassMate'i kullanmak daha iyi olur mu?
husayt

2
@husayt evet, teknik olarak java-classmate lib üstündür. Ancak onu Jackson ile entegre etmek biraz zor çünkü Jackson'ın kendi tür soyutlaması API'nin entegre bir parçası. Uzun vadede, Jackson'ın sınıf arkadaşı kodunu gömülü veya dep aracılığıyla kullanmasını sağlamanın doğru yolunu bulmak harika olurdu.
StaxMan

1
Jackson'ın jenerikteki boşlukları örtmek zorunda kalmaması gerektiğini düşünüyorum, ama her iki şekilde de çok iyi yapıyor.
Adrian Baker

6

'JavaType' çalışıyor !! Json String'deki bir Listeyi ArrayList java Nesnelerine unmarshall (seri durumdan çıkarma) yapmaya çalışıyordum ve günlerden beri bir çözüm bulmakta zorlanıyordum.
Sonunda bana çözüm veren kod aşağıdadır. Kod:

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 nasıl başlatılır?
AZ_

Lütfen bana küçük bir örnek gösterin. Class <?> Hedefini geçiyorum ve sonra target.getClassName () alıyorum.
AZ_

1
Aşağıdaki gibi bir oluşturucu ekleyin: JsonMarshallerUnmarshaller <T> {private Class <T> targetClass; JsonMarshallerUnmarshaller (Sınıf <T> c) {targetClass = c; }} Her yerde getClass yapmak yerine bu sınıfı kullanmak için şimdi 'unmarshal' işlevinde uygun değişiklikleri yapın.
rushidesai1

Birkaç not: kod, tüm istisnaların alt türleri olduğu IOException(yalnızca bir yakalamaya ihtiyaç duyduğu) ve varsayılan ek açıklama iç gözlemcisinin zaten olduğu JacksonAnnotationIntrospector- yani herhangi bir şey yapmaya gerek yok ObjectMapper, sadece inşa edin ve işe yaradığına dikkat edilerek çok basitleştirilebilir .
StaxMan

Yani bu kodu derleyemiyorum bile. Bunun yerine yapıştırmak için canlı bir örnek var mı?
Wrench

0

Rushidesai1'in cevabını çalışan bir örnek içerecek şekilde değiştirdim .

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
    }
}

Çıktı

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"
}]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.