জ্যাকসন - জেনেরিক ক্লাস ব্যবহার করে ডিসেরায়ালাইজ করুন


147

আমার কাছে একটি জেসন স্ট্রিং রয়েছে, যা আমার নিম্নোক্ত ক্লাসে ডি-সিরিয়াল করা উচিত

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

আমি এটা কিভাবে করব? এটি স্বাভাবিক উপায়

mapper.readValue(jsonString, Data.class);

তবে টি কী বোঝায় তা আমি কীভাবে উল্লেখ করব?



উত্তর:


238

TypeReferenceআপনার ব্যবহৃত প্রতিটি জেনেরিক ধরণের জন্য আপনাকে একটি অবজেক্ট তৈরি করতে হবে এবং এটি ডিসরিয়ালাইজেশনের জন্য ব্যবহার করতে হবে। উদাহরণ স্বরূপ -

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

আমাকে এটিকে টাইপ-রেফারেন্স <ডেটা <T>> () {} হিসাবে ব্যবহার করতে হবে ... তবে আমি নিম্নলিখিত ত্রুটিটি পেয়ে যাচ্ছি - java.lang.class থেকে ব্যক্তিগত java.lang.class.Class () অ্যাক্সেস করতে পারছি না। অ্যাক্সেস সেট করতে ব্যর্থ।
জাভা.লাং.ক্লাস

না, না Data<T>, এটি কোনও প্রকার নয়। আপনাকে অবশ্যই প্রকৃত শ্রেণি নির্দিষ্ট করতে হবে; অন্যথায় এটি হিসাবে একই Data<Object>
স্টেক্সম্যান 24

18
আমি যদি না জানতে পারি রানটাইম পর্যন্ত এটি কোন শ্রেণীর? রানটাইমের সময় আমি প্যারামিটার হিসাবে ক্লাসটি পাব। এই পাবলিকের মতো <T> অকার্যকর ডি-সিরিয়ালাইজ করুন (ক্লাস <টি> ক্লজ {অবজেক্টম্যাপার ম্যাপার = নতুন অবজেক্টম্যাপার (); ম্যাপার.ড্রেডভ্যালু (জসনস্ট্রিং, নতুন টাইপরেফারেন্স <জসন <টি>> () {});}
জিঞ্জো

1
আমি পূর্ণ প্রশ্ন সঠিকভাবে এখানে বলা হয়েছে stackoverflow.com/questions/11659844/...
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> অকার্যকর ডি-সিরিয়ালাইজ করুন (ক্লাস <টি> ক্লজ {অবজেক্টম্যাপার ম্যাপার = নতুন অবজেক্টম্যাপার (); ম্যাপার.ড্রেডভ্যালু (জসনস্ট্রিং, নতুন টাইপরেফারেন্স <জসন <টি>> () {});}
জিঞ্জো

1
আমি পূর্ণ প্রশ্ন এখানে বলা হয়েছে stackoverflow.com/questions/11659844/...
gnjago

2
তারপরে কেবল ক্লাসটি পাস করুন, প্রয়োজন নেই TypeReference: return mapper.readValue(json, clazz);এখানে সমস্যাটি আসলে কী?
স্টেক্সম্যান

2
সমস্যাটি হ'ল "ডেটা" একটি জেনেরিক শ্রেণি। রানটাইমের সময় টি কী টাইপ করা উচিত তা উল্লেখ করতে হবে। প্যারামিটারের ক্লজটি রানটাইমে আমাদের টি কি। সুতরাং, রিডভ্যালু কল কিভাবে? এটিকে নতুন টাইপ রেফারেন্সের সাথে কল করে> Json <T>> কাজ করে না পুরো প্রশ্নটি এখানে stackoverflow.com/questions/11659844/…
gnjago

2
ঠিক আছে. তাহলে আপনার ব্যবহার করা দরকার TypeFactory.. আমি আমার উত্তরটি সম্পাদনা করব।
স্ট্যাক্সম্যান

30

আপনি যে কাজটি করেন তা প্রথমে সিরিয়ালাইজ করা হয়, তারপরে আপনি ডিজিটালাইজ করতে পারেন।
সুতরাং আপনি যখন সিরিয়ালাইজ করবেন তখন @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.InuthorTypeIdException: [সরল ধরণের, শ্রেণি java.lang.Object] এর সাব টাইপ সমাধান করার চেষ্টা করার সময় আইডি অনুপস্থিত: আইডি সম্পত্তি '@ ক্লাস' হারিয়ে যাচ্ছে (পজোর জন্য সম্পত্তি 'ডেটা')
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

কেবল ইউটিল ক্লাসে একটি স্ট্যাটিক পদ্ধতি লিখুন। আমি একটি ফাইল থেকে একটি জেসন পড়ছি। আপনি স্ট্রিংকে রিডভ্যালুতেও দিতে পারেন

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

জেএসওএন স্ট্রিং যা ডিসরিয়ালাইজড হওয়া দরকার সেগুলিতে প্যারামিটার সম্পর্কে টাইপ তথ্য থাকতে হবে T
আপনাকে জ্যাকসন টীকা প্রতিটি ক্লাসে রাখতে হবে যা প্যারামিটার হিসাবে Tক্লাসে পাস করা যেতে পারে Dataযাতে প্যারামিটারের ধরণ সম্পর্কে টাইপ তথ্যT জ্যাকসন দ্বারা জেএসএন স্ট্রিং থেকে / লিখিতভাবে পড়তে পারে।

আসুন ধরে নেওয়া যাক যে 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সংকলন সময় প্যারামিটার না জেনে deserialized করা যেতে পারে ।
এই জ্যাকসন ডকুমেন্টেশন লিঙ্ক পলিমর্ফিক ডিসেরিয়ালাইজেশন সম্পর্কে কথা বলে তবে এই প্রশ্নের জন্যও উল্লেখ করা দরকারী।


এবং আমি যদি একটি তালিকা রাখতে চাই তবে আমি কীভাবে এটি পরিচালনা করব? যেমন << আইজামআরসাল্ট>
লুকা

5

জ্যাকসন 2.5 থেকে, সমাধানের একটি মার্জিত উপায় যা টাইপফ্যাক্ট্রি.কমস্ট্রাক্ট প্যারামেট্রিক টাইপ (ক্লাস প্যারামেট্রাইজড, ক্লাস ... প্যারামিটার ক্লাস) পদ্ধতি ব্যবহার করে যা একটি জ্যাকসনকে স্ট্র্যাথলি সংজ্ঞায়িত করতে দেয়JavaType করে যা প্যারামিটারাইজড ক্লাস এবং তার প্যারামিটারাইজড নির্দিষ্ট করে ।

ধরুন আপনি ডিসরিয়ালাইজ করতে চান 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

আপনি যদি স্কেল ব্যবহার করছেন এবং সংকলনের সময় জেনেরিক প্রকারটি জানেন তবে আপনার সমস্ত এপিআই আয়ার্সের যেকোন জায়গায় ম্যানুয়ালি টাইপরেফারেন্সটি পাস করতে চান না, আপনি নিম্নলিখিত কোডটি ব্যবহার করতে পারেন (জ্যাকসন ২.৯.৫ সহ):

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- স্ট্রিংটি ডিজিজালাইজ করার জন্য আপনার প্রয়োজন:

  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 টীকাগুলি বাধ্যতামূলক, এটি জেনারিক জেএসএন পার্সিং এবং জনসংখ্যা নিশ্চিত করে।

নেস্টেড অ্যারেগুলির সাথে আরও জটিল মামলার জন্য দয়া করে বেলডুং রেফারেন্সটি দেখুন: https://www.baeldung.com/jackson-mapping-dynamic-object


0

খুব ভাল না, তবে সহজ সিদ্ধান্তের উদাহরণ (কেবল জ্যাকসনের জন্য নয়, এছাড়াও স্প্রিং রেস্টটেম্পলেট ইত্যাদি):

Set<MyClass> res = new HashSet<>();
objectMapper.readValue(json, res.getClass());
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.