Pytanie Jackson i ogólny typ odniesienia


Chcę użyć biblioteki json json dla ogólnej metody w następujący sposób:

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

Problem polega na tym, że gdy wywołuję funkcję getMyObject (), która znajduje się wewnątrz obiektu żądania, jackson zwraca zagnieżdżony obiekt niestandardowy jako LinkedHashMap. Czy istnieje jakiś sposób, w którym określę, że obiekt T musi zostać zwrócony ?. Na przykład: jeśli wysłałem obiekt typu Klient, to Klient powinien zostać zwrócony z tej listy ?.

Dzięki.


76
2017-07-27 14:39


pochodzenie


Dodaj implementację getT () - Jim Garrison
To pytanie jest podobne do stackoverflow.com/questions/6062011/... ale zaproponowali określenie typu za pomocą TypeFactory. Jednak nie wiem typu w czasie kompilacji ... - techzen
TypeFactory ma metody, które nie wymagają klasy statycznej; createCollectionType i tak dalej. - StaxMan
Udostępnij pełny kod. Mam również ten sam problem. - AZ_


Odpowiedzi:


Jest to dobrze znany problem z wymazywaniem typu Java: T jest po prostu zmienną typu i należy wskazać aktualną klasę, zwykle jako argument Klasy. Bez takich informacji najlepiej można użyć granic; a zwykły T jest w przybliżeniu taki sam jak "T extends Object". A Jackson następnie zwiąże obiekty JSON jako Mapy.

W takim przypadku metoda testera musi mieć dostęp do klasy i można ją skonstruować

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

i wtedy

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

139
2017-07-27 22:51



Działa: Wykonałem następujące czynności: JavaType topMost = mapper.getTypeFactory (). ConstructParametricType (MyWrapper.class, ActualClassRuntime.class); a następnie odczytała wartość i w końcu zadziałała :) - techzen
Tak, to działa - dziękuję za wskazanie metody tworzenia generycznego typu innego niż typ mapy / kolekcji! - StaxMan
Dokładnie to, czego potrzebowałem, dzięki! - gresdiplitude
@husayt tak, technicznie java-classmate lib jest lepsza. Ale integracja z Jacksonem jest nieco trudna, ponieważ własna abstrakcja Jacksona jest integralną częścią API. Na dłuższą metę dobrze byłoby znaleźć właściwy sposób na wykorzystanie Jackson kod classmate, osadzone lub za pośrednictwem dep. - StaxMan
Czuję, że Jackson nie powinien ukrywać czegoś, co przypomina luki w generykach, ale tak czy owak, robi to bardzo dobrze. - Adrian Baker


Działa "JavaType"! Próbowałem unmarshall (deserialize) List w json String do obiektów ArrayList Java i walczył, aby znaleźć rozwiązanie od wielu dni.
Poniżej znajduje się kod, który w końcu dał mi rozwiązanie. 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 ;
    }  
}

6
2018-03-05 17:07



Jak zainicjować TargetClass? - AZ_
Przez konstruktora lub ustawiciela gettera !!! - rushidesai1
Proszę pokazać mi mały przykład. Przechodzę do celu klasy <?>, A następnie uzyskuję wartość target.getClassName (). - AZ_
Dodaj konstruktor w następujący sposób: JsonMarshallerUnmarshaller <T> {private Class <T> targetClass; JsonMarshallerUnmarshaller (Klasa <T> c) {targetClass = c; }} Dokonaj teraz odpowiednich zmian w funkcji 'unmarshal', aby użyć tej klasy, zamiast robić getClass wszędzie. - rushidesai1
Kilka uwag: kod można znacznie uprościć, zauważając, że wszystkie wyjątki są podtypami IOException (potrzebujesz tylko jednego haczyka) i że domyślny introspektor jest już dostępny JacksonAnnotationIntrospector- więc nie trzeba nic robić ObjectMapper, po prostu skonstruuj i działa. - StaxMan