जैक्सन - सामान्य वर्ग का उपयोग करते हुए वर्णन करें


147

मेरे पास एक जॉन्स स्ट्रिंग है, जिसे मुझे निम्न वर्ग के लिए डी-एसरियलाइज़ करना चाहिए

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

मैं यह कैसे करुं? यह सामान्य तरीका है

mapper.readValue(jsonString, Data.class);

लेकिन मैं कैसे उल्लेख करता हूं कि टी किस लिए खड़ा है?



जवाबों:


239

आपको TypeReferenceप्रत्येक जेनेरिक प्रकार के लिए एक ऑब्जेक्ट बनाने की ज़रूरत है जो आप उपयोग करते हैं और डिसेरिएलाइज़ेशन के लिए उपयोग करते हैं। उदाहरण के लिए -

mapper.readValue(jsonString, new TypeReference<Data<String>>() {});

मुझे इसे TypeReference <Data <T >> () {} ... के रूप में उपयोग करना है, लेकिन मुझे निम्न त्रुटि मिल रही है - java.lang.class से निजी java.lang.class.Class () तक नहीं पहुँच सकते। पहुँच सेट करने में विफल। एक java.lang.Class कंस्ट्रक्टर को सुलभ नहीं बना सकता
gnjago

नहीं, नहीं Data<T>, यह एक प्रकार नहीं है। आपको वास्तविक वर्ग निर्दिष्ट करना होगा; अन्यथा यह वैसा ही है Data<Object>
स्टेक्समैन

18
क्या होगा अगर मुझे नहीं पता कि रनटाइम तक यह किस वर्ग का है? मुझे रनटाइम के दौरान एक पैरामीटर के रूप में कक्षा मिलेगी। इस जनता की तरह <T> void deSerialize (Class <T> clazz {ObjectMapper mapper = new ObjectMapper (); mapper.readValue (jsonString, new TypeReference / Json <T >> () {});}
gnjago

1
मैंने पूरा सवाल यहाँ सही तरीके से पूछा है। stackoverflow.com/questions/1165984444/…
gnjago

का पूरा पैकेज नाम क्या है TypeReference? क्या यह है com.fasterxml.jackson.core.type?
लेई यांग

88

आप ऐसा नहीं कर सकते हैं: आपको पूरी तरह से हल किए गए प्रकार को निर्दिष्ट करना होगा, जैसे Data<MyType>Tसिर्फ एक चर है, और जैसा कि अर्थहीन है।

लेकिन अगर आप का मतलब है कि Tज्ञात हो जाएगा, सिर्फ सांख्यिकीय रूप से नहीं, तो आपको TypeReferenceगतिशील रूप से समकक्ष बनाने की आवश्यकता है । संदर्भित अन्य प्रश्न पहले से ही इसका उल्लेख कर सकते हैं, लेकिन यह कुछ इस तरह दिखना चाहिए:

public Data<T> read(InputStream json, Class<T> contentClass) {
   JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, contentClass);
   return mapper.readValue(json, type);
}

2
क्या होगा अगर मुझे नहीं पता कि रनटाइम तक यह किस वर्ग का है? मुझे रनटाइम के दौरान एक पैरामीटर के रूप में कक्षा मिलेगी। इस जनता की तरह <T> void deSerialize (Class <T> clazz {ObjectMapper mapper = new ObjectMapper (); mapper.readValue (jsonString, new TypeReference / Json <T >> () {});}
gnjago

1
मैंने पूरा सवाल यहाँ पूछा है stackoverflow.com/questions/11659844/…
gnjago

2
फिर बस कक्षा को पास करें, इसकी कोई आवश्यकता नहीं है TypeReference: return mapper.readValue(json, clazz);वास्तव में यहाँ क्या समस्या है?
स्टेक्समैन

2
समस्या यह है कि "डेटा" एक सामान्य वर्ग है। मुझे यह निर्दिष्ट करने की आवश्यकता है कि रन टाइम पर T किस प्रकार का है। पैरामीटर क्लैज वह है जो T हमें रनटाइम पर देता है। तो, readValue कैसे कॉल करें? इसे नए TypeReference के साथ कॉल करना> Json <T >> काम नहीं करता है पूरा सवाल यहाँ है stackoverflow.com/questions/11659844/…
gnjago

2
ठीक। फिर आपको उपयोग करने की आवश्यकता है TypeFactory.. मैं अपना उत्तर संपादित करूंगा।
स्टेक्समैन

30

पहली बात यह है कि आप क्रमबद्ध हैं, तो आप deserialize कर सकते हैं।
इसलिए जब आप क्रमबद्ध करते हैं, तो आपको @JsonTypeInfoजैकसन को कक्षा की जानकारी को अपने डेटा में लिखने के लिए उपयोग करना चाहिए । आप जो कर सकते हैं वह इस प्रकार है:

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

फिर जब आप डिस्क्रिअलाइज़ करते हैं, तो आप पाएंगे कि जैकसन ने आपके डेटा को एक क्लास में डिसेर्बलाइज़ कर दिया है, जो आपके वैरिएबल हिट वास्तव में रनटाइम पर है।


काम नहीं कर रहा है, नीचे त्रुटि हो रही है। com.fasterxml.jackson.databind.exc.InvalidTypeIdException: मिसिंग प्रकार आईडी जब [सरल प्रकार, वर्ग java.lang.Object के उपप्रकार को हल करने की कोशिश कर रहा है: लापता प्रकार आईडी संपत्ति '@class' (POJO के लिए) संपत्ति 'डेटा')
gaurav9620

15

कक्षा डेटा के लिए <>

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

अब यह पदावनत हो गया है।
इवान गर्टिस

13

सिर्फ यूटील क्लास में एक स्टैटिक तरीका लिखें। मैं एक फाइल से Json पढ़ रहा हूं। आप String भी readValue को दे सकते हैं

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

उपयोग:

List<TaskBean> list =  Util.<List<TaskBean>>convertJsonToPOJO("E:/J2eeWorkspaces/az_workspace_svn/az-client-service/dir1/dir2/filename.json", TaskBean.class);

7

आप इसे किसी अन्य वर्ग में लपेट सकते हैं जो आपके सामान्य प्रकार के प्रकार को जानता है।

उदाहरण के लिए,

class Wrapper {
 private Data<Something> data;
}
mapper.readValue(jsonString, Wrapper.class);

यहाँ कुछ एक ठोस प्रकार है। आपको प्रति संशोधित प्रकार के आवरण की आवश्यकता है। अन्यथा जैक्सन को पता नहीं है कि किन वस्तुओं को बनाना है।


6

JSON स्ट्रिंग को deserialized होने की आवश्यकता होती है जिसमें पैरामीटर के बारे में जानकारी होनी चाहिए T
आपको हर वर्ग पर जैक्सन एनोटेशन डालना होगा जिसे पैरामीटर के रूप Tमें कक्षा में पारित किया जा सकता है Dataताकि प्रकार के पैरामीटर के बारे में जानकारी होT से पढ़ा जा सकता / जैक्सन ने JSON स्ट्रिंग के लिए लिखा।

आइए हम यह मान लें कि Tऐसा कोई भी वर्ग हो सकता है जो अमूर्त वर्ग का विस्तार करता है 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 {

}

एक बार कक्षा के प्रत्येक (या उनके सामान्य सुपरप्राइप) को पैरामीटर के रूप में पारित किया जा सकता T है, जैक्सन Tमें JSON में पैरामीटर के बारे में जानकारी शामिल होगी । Tसंकलन समय पर पैरामीटर को जाने बिना ऐसे JSON को फिर से मिटाया जा सकता है ।
यह जैक्सन प्रलेखन लिंक पॉलीमॉर्फिक डिसेरिएलाइज़ेशन के बारे में बात करता है, लेकिन इस प्रश्न के लिए भी उपयोगी है।


और अगर मैं सूची बनाना चाहता हूं तो मैं इसे कैसे प्रबंधित करूं? जैसे
मान

5

जैक्सन 2.5 से, हल करने के लिए एक सुंदर तरीका जो TypeFactory.constructParametricType (क्लास पैराट्राइज्ड, क्लास ... पैरामीटर क्लैक्सेस) विधि का उपयोग कर रहा है ,JavaType जो पैरामीटर वर्ग और इसके पैरामीटर प्रकारों को निर्दिष्ट करके एक जैक्सन को स्पष्ट रूप से परिभाषित करने की अनुमति देता है ।

आप के लिए deserialize करना चाहते हैं की आपूर्ति Data<String>यह मानते हुए , आप कर सकते हैं:

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

ध्यान दें कि यदि वर्ग कई पैरामीटर प्रकारों की घोषणा करता है, तो यह वास्तव में कठिन नहीं होगा:

class Data <T, U> {
    int found;
    Class<T> hits;
    List<U> list;
}

हम कर सकते थे :

JavaType type = mapper.getTypeFactory().constructParametricType(Data.class, String.class, Integer);
Data<String, Integer> data = mapper.readValue(json, type);

बहुत बढ़िया, धन्यवाद यह मेरे लिए काम किया। टाइपराइटर के साथ मुझे मैप से लेकर विशिष्ट ऑब्जेक्ट तक का क्लासरूम अपवाद मिला लेकिन यह वास्तव में काम करता है।
ताकसीज़ुमा

1
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;
    }
    ...
 }

0

यदि आप स्लैला का उपयोग कर रहे हैं और संकलन समय पर सामान्य प्रकार को जानते हैं, लेकिन अपने सभी एपीआई l खरीदारों में हर जगह TypeReference मैन्युअल रूप से पास नहीं करना चाहते हैं, तो आप निम्न कोड (जैकसन 2.9.5 के साथ) का उपयोग कर सकते हैं:

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

जिसका उपयोग इस तरह किया जा सकता है:

read[List[Map[Int, SomethingToSerialize]]](inputStream)

0

जैक्सन की जरूरत के साथ जावा-ऑब्जेक्ट के लिए एक सामान्य JSON-string का वर्णन करने के लिए:

  1. JSON वर्ग को परिभाषित करने के लिए।

  2. एक विशेषता मानचित्रण करें।

अंतिम कोड, परीक्षण किया गया और तैयार होने के लिए:

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

महत्वपूर्ण:
@JsonAnySetter एनोटेशन अनिवार्य है, यह एक सामान्य JSON- पार्सिंग और आबादी सुनिश्चित करता है।

नेस्टेड सरणियों के साथ और अधिक जटिल मामलों के लिए कृपया बेल्डंग संदर्भ देखें: https://www.baeldung.com/jackson-mapping-dynamic-object


0

उदाहरण बहुत अच्छा नहीं है, लेकिन सरल निर्णय (न केवल जैक्सन के लिए, स्प्रिंग रेस्टेमप्लेट, आदि के लिए भी):

Set<MyClass> res = new HashSet<>();
objectMapper.readValue(json, res.getClass());
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.