जैक्सन और सामान्य प्रकार का संदर्भ


107

मैं एक सामान्य विधि के लिए जैकसन जसन लाइब्रेरी का उपयोग करना चाहता हूं:

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

अब समस्या यह है कि जब मैं getMyObject () को कॉल करता हूं जो अनुरोध ऑब्जेक्ट के अंदर होता है तो नेस्टेड कस्टम ऑब्जेक्ट को LinkedHashMap के रूप में देता है। क्या कोई ऐसा तरीका है जिसमें मैं निर्दिष्ट करता हूं कि टी ऑब्जेक्ट को वापस करने की आवश्यकता है? उदाहरण के लिए: यदि मैंने ग्राहक का प्रकार भेजा है तो ग्राहक को उस सूची से लौटा दिया जाना चाहिए।

धन्यवाद।


कृपया getT ()
जिम गैरीसन

यह प्रश्न stackoverflow.com/questions/6062011/… के समान है, लेकिन उन्होंने TypeFactory का उपयोग करके प्रकार निर्दिष्ट करने का सुझाव दिया है। हालाँकि मुझे संकलन के समय प्रकार का पता नहीं है ...
techzen

टाइपफैक्टरी में ऐसी विधियाँ हैं जिन्हें स्थिर वर्ग की आवश्यकता नहीं है; createCollectionType और इसी तरह।
स्टेक्समैन

कृपया पूरा कोड साझा करें। मैं भी इसी समस्या का सामना कर रहा हूं।

TypeReferenceअमूर्त नहीं है?
काइल डेलानी

जवाबों:


194

यह जावा प्रकार के क्षरण के साथ एक अच्छी तरह से ज्ञात समस्या है: टी सिर्फ एक प्रकार का चर है, और आपको वास्तविक वर्ग को इंगित करना चाहिए, आमतौर पर कक्षा तर्क के रूप में। ऐसी जानकारी के बिना, सबसे अच्छा जो किया जा सकता है वह सीमा का उपयोग करना है; और सादा T लगभग 'T फैली हुई वस्तु' के समान है। और जैक्सन तब JSON ऑब्जेक्ट्स को मैप्स के रूप में बांध देगा।

इस मामले में, परीक्षक विधि को कक्षा तक पहुंच की आवश्यकता होती है, और आप निर्माण कर सकते हैं

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

और फिर

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

16
यह काम करता है: मैंने निम्न कार्य किया: JavaType topMost = mapper.getTypeFactory ()। buildParametricType (MyWrapper.class, RealClassRuntime.class); और फिर readValue किया और यह आखिरकार काम किया :)
techzen

हां, यह काम करता है - मानचित्र / संग्रह प्रकार के अलावा अन्य सामान्य प्रकार बनाने के लिए विधि को इंगित करने के लिए धन्यवाद!
स्टेक्समैन

1
@StaxMan क्या अब से इस तरह की चीजों के लिए ClassMate का उपयोग करना बेहतर होगा?
15

2
@husayt हाँ, तकनीकी रूप से जावा-सहपाठी परिवाद श्रेष्ठ है। लेकिन जैक्सन के साथ इसे एकीकृत करना थोड़ा मुश्किल है क्योंकि जैक्सन का स्वयं का अमूर्त एपीआई का एकीकृत हिस्सा है। लंबी अवधि के लिए जैक्सन के सहपाठी कोड का उपयोग करने के लिए उचित तरीका पता लगाना बहुत अच्छा होगा, या तो एम्बेडेड या डिप के माध्यम से।
स्टैक्मैन मैन 27'14

1
मुझे लगता है जैक्सन को ऐसा नहीं लगना चाहिए कि जेनेरिक में अंतराल क्या महसूस होता है, लेकिन किसी भी तरह से, यह बहुत अच्छी तरह से करता है।
एड्रियन बेकर

6

'JavaType' काम करता है !! मैं ArrayList जावा ऑब्जेक्ट्स में स्ट्रिंग स्ट्रिंग में एक सूची को अनसार्ट करने (डिस्क्रिअलाइज़ करने) की कोशिश कर रहा था और दिनों से एक समाधान खोजने के लिए संघर्ष कर रहा था।
नीचे वह कोड है जिसने आखिरकार मुझे समाधान दिया। कोड:

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 को इनिशियलाइज़ कैसे करें?

कृपया मुझे एक छोटा सा उदाहरण दिखाएं। मैं कक्षा पास कर रहा हूं <>? लक्ष्य और फिर लक्ष्य प्राप्त करना ।getClassName ()।
अ ० अ ० अ ० १०'१३ रात .:

1
एक कंस्ट्रक्टर को निम्नानुसार जोड़ें: JsonMarshallerUnmarshaller <T> {निजी वर्ग <T> targetClass; JsonMarshallerUnmarshaller (कक्षा <T> c) {targetClass = c; }} हर जगह getClass करने के बजाय इस वर्ग का उपयोग करने के लिए 'अनमर्सल' फ़ंक्शन के लिए अब उचित परिवर्तन करें।
राइडसाइड 1

नोटों के जोड़े: कोड को यह देखते हुए बहुत सरल किया जा सकता है कि सभी अपवाद IOException(केवल एक कैच की आवश्यकता) के उपप्रकार हैं , और यह कि डिफ़ॉल्ट एनोटेशन इंट्रॉस्पेक्टर पहले से ही है JacksonAnnotationIntrospector- इसलिए कुछ भी करने की आवश्यकता नहीं है ObjectMapper, बस इसका निर्माण करें और यह काम करता है।
स्टेक्समैन

तो यह कोड मुझे संकलन करने के लिए भी नहीं मिलता है। इसके बजाय पेस्ट करने के लिए कोई जीवंत उदाहरण मिला?
रिंच

0

मैंने एक कामकाजी उदाहरण को शामिल करने के लिए राइडसाइडाई 1 के उत्तर को संशोधित किया ।

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

उत्पादन

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"
}]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.