টাইপএডাপ্টার ব্যবহার করে কোনও বস্তুর মধ্যে একটি ভেরিয়েবলের (অনেকের) জন্য গসন কাস্টম সেরালাইজার


96

আমি কাস্টম টাইপএডাপ্টার ব্যবহারের প্রচুর সাধারণ উদাহরণ দেখেছি। সবচেয়ে সহায়ক হয়েছে Class TypeAdapter<T>। কিন্তু এটি এখনও আমার প্রশ্নের উত্তর দেয়নি।

আমি অবজেক্টের একটি একক ক্ষেত্রের সিরিয়ালাইজেশন কাস্টমাইজ করতে চাই এবং ডিফল্ট জিসন প্রক্রিয়াটি বাকীগুলিকে যত্ন নিতে দিন।

আলোচনার উদ্দেশ্যে, আমরা এই শ্রেণীর সংজ্ঞাটি যে বস্তুর ক্রমিকায়িত করতে চাই তার শ্রেণি হিসাবে ব্যবহার করতে পারি। আমি গসনকে প্রথম দুই শ্রেণির সদস্যদের পাশাপাশি বেস ক্লাসের সমস্ত উন্মুক্ত সদস্যকে সিরিয়াল করতে দিতে চাই, এবং আমি নীচে দেখানো তৃতীয় এবং চূড়ান্ত শ্রেণীর সদস্যের জন্য কাস্টম সিরিয়ালকরণ করতে চাই।

public class MyClass extends SomeClass {

@Expose private HashMap<String, MyObject1> lists;
@Expose private HashMap<String, MyObject2> sources;
private LinkedHashMap<String, SomeClass> customSerializeThis;
    [snip]
}

উত্তর:


131

এটি একটি দুর্দান্ত প্রশ্ন কারণ এটি এমন কোনও কিছুকে পৃথক করে যা সহজ হওয়া উচিত তবে বাস্তবে প্রচুর কোডের প্রয়োজন হয়।

শুরু করার জন্য, একটি বিমূর্তি লিখুন TypeAdapterFactoryযা আপনাকে বহির্গামী ডেটা সংশোধন করতে সহায়তা করে। এই উদাহরণটি জিএসন ২.২ এ একটি নতুন এপিআই getDelegateAdapter()ব্যবহার করে যা আপনাকে গডস ডিফল্টরূপে ব্যবহার করবে এমন অ্যাডাপ্টারটি সন্ধান করতে দেয়। যদি আপনি কেবল স্ট্যান্ডার্ড আচরণটি সামলানো চান তবে প্রতিনিধি অ্যাডাপ্টারগুলি অত্যন্ত কার্যকর hand এবং সম্পূর্ণ কাস্টম ধরণের অ্যাডাপ্টারগুলির বিপরীতে, আপনি ক্ষেত্রগুলি যুক্ত এবং সরানোর সাথে সাথে তারা স্বয়ংক্রিয়ভাবে আপ টু ডেট থাকবে।

public abstract class CustomizedTypeAdapterFactory<C>
    implements TypeAdapterFactory {
  private final Class<C> customizedClass;

  public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
    this.customizedClass = customizedClass;
  }

  @SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
  public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    return type.getRawType() == customizedClass
        ? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
        : null;
  }

  private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
    final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
    final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
    return new TypeAdapter<C>() {
      @Override public void write(JsonWriter out, C value) throws IOException {
        JsonElement tree = delegate.toJsonTree(value);
        beforeWrite(value, tree);
        elementAdapter.write(out, tree);
      }
      @Override public C read(JsonReader in) throws IOException {
        JsonElement tree = elementAdapter.read(in);
        afterRead(tree);
        return delegate.fromJsonTree(tree);
      }
    };
  }

  /**
   * Override this to muck with {@code toSerialize} before it is written to
   * the outgoing JSON stream.
   */
  protected void beforeWrite(C source, JsonElement toSerialize) {
  }

  /**
   * Override this to muck with {@code deserialized} before it parsed into
   * the application type.
   */
  protected void afterRead(JsonElement deserialized) {
  }
}

উপরের শ্রেণিটি একটি জেএসওএন ট্রি পেতে (ডিফল্টভাবে উপস্থাপিত JsonElement) পেতে ডিফল্ট সিরিয়ালাইজেশন ব্যবহার করে এবং তারপরে beforeWrite()সাব গাছটিকে সেই গাছটিকে কাস্টমাইজ করার অনুমতি দেওয়ার জন্য হুক পদ্ধতিটি কল করে । একইভাবে deserialization জন্য afterRead()

পরবর্তী আমরা নির্দিষ্ট MyClassউদাহরণের জন্য এটি সাবক্লাস করি । চিত্রিত করার জন্য আমি মানচিত্রটিতে সিরিয়ালযুক্ত হয়ে গেলে 'আকার' নামে একটি সিন্থেটিক সম্পত্তি যুক্ত করব। এবং প্রতিসাম্যতার জন্য আমি এটি সরিয়ে ফেলব যখন এটি ডিজাইরিয়াল করা হবে। অনুশীলনে এটি কোনও স্বনির্ধারণ হতে পারে।

private class MyClassTypeAdapterFactory extends CustomizedTypeAdapterFactory<MyClass> {
  private MyClassTypeAdapterFactory() {
    super(MyClass.class);
  }

  @Override protected void beforeWrite(MyClass source, JsonElement toSerialize) {
    JsonObject custom = toSerialize.getAsJsonObject().get("custom").getAsJsonObject();
    custom.add("size", new JsonPrimitive(custom.entrySet().size()));
  }

  @Override protected void afterRead(JsonElement deserialized) {
    JsonObject custom = deserialized.getAsJsonObject().get("custom").getAsJsonObject();
    custom.remove("size");
  }
}

পরিশেষে এটিকে একত্রে পছন্দসই Gsonউদাহরণ তৈরি করে নতুন টাইপ অ্যাডাপ্টার ব্যবহার করে:

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new MyClassTypeAdapterFactory())
    .create();

গসনের নতুন টাইপএডাপ্টার এবং টাইপএডাপ্টারফ্যাক্টরি টাইপগুলি অত্যন্ত শক্তিশালী তবে এগুলি বিমূর্ত এবং কার্যকরভাবে ব্যবহারের জন্য অনুশীলনও গ্রহণ করে। আশা করি আপনি এই উদাহরণটি দরকারী খুঁজে পেয়েছেন!


@ জেস আপনাকে ধন্যবাদ! আপনার সাহায্য ছাড়া আমি এটি কখনই খুঁজে পেতাম না!
মাউন্টেনএক্স

আমি new MyClassTypeAdapterFactory()প্রাইভেট কর্টারের সাথে ইনস্ট্যান্ট করতে পারিনি ...
মাউন্টেনএক্স

আহ, সে সম্পর্কে দুঃখিত। আমি এই সবগুলি একটি ফাইলে করেছিলাম।
জেসি উইলসন

7
সেই মেকানসিম (পূর্বের লেখার আগে এবং পরে পড়া) জিএসন কোরের অংশ হওয়া উচিত। ধন্যবাদ!
মেলানিয়া

4
পারস্পরিক রেফারেন্সিংয়ের কারণে অসীম লুপগুলি এড়াতে আমি টাইপএডাপ্টার ব্যবহার করছি .. এটি একটি দুর্দান্ত প্রক্রিয়া যা আপনি @ জেসিকে ধন্যবাদ জানালেন যদিও আমি আপনাকে জিজ্ঞাসা করতে চাই যে এই প্রক্রিয়াটির সাথে একই প্রভাব অর্জন করার কোনও ধারণা আছে তবে আমার মনে কিছু আছে তবে আমি আপনার মতামত শুনতে চাই .. ধন্যবাদ!
মোহাম্মদ আর এল-খুদারি

16

এটির জন্য আরও একটি পদ্ধতি রয়েছে। জেসি উইলসন যেমন বলেছেন, এটি সহজ হওয়ার কথা। এবং কি অনুমান, এটা হল সহজ!

আপনি যদি প্রয়োগ করেন JsonSerializerএবং JsonDeserializerআপনার ধরণের জন্য, আপনি যে অংশগুলি চান তা পরিচালনা করতে পারেন এবং খুব অল্প কোড সহ অন্য কোনও জিনিসের জন্য জিসনকে ডেলিগেট করতে পারেন । সুবিধার্থে আমি নীচে অন্য প্রশ্নের উপর @ পার্সਪশন এর উত্তরটি উদ্ধৃত করছি , আরও বিশদের জন্য সেই উত্তরটি দেখুন:

সেক্ষেত্রে সিরিয়ালাইজারদের সিরিয়ালাইজেশন প্রসঙ্গে অ্যাক্সেস রয়েছে এমন সাধারণ কারণে একটির JsonSerializerবিপরীতে হিসাবে এটি ব্যবহার করা ভাল TypeAdapter

public class PairSerializer implements JsonSerializer<Pair> {
    @Override
    public JsonElement serialize(final Pair value, final Type type,
            final JsonSerializationContext context) {
        final JsonObject jsonObj = new JsonObject();
        jsonObj.add("first", context.serialize(value.getFirst()));
        jsonObj.add("second", context.serialize(value.getSecond()));
        return jsonObj;
    }
}

এর জটিল সুবিধা (জটিল কাজের দিকগুলি এড়ানো ছাড়া) আপনি এখনও অন্য প্রকারের অ্যাডাপ্টার এবং কাস্টম সিরিয়ালাইজারগুলির সুবিধা নিতে পারেন যা মূল প্রসঙ্গে নিবন্ধিত হতে পারে। নোট করুন যে সিরিয়ালাইজার এবং অ্যাডাপ্টারের নিবন্ধন ঠিক একই কোড ব্যবহার করে।

তবে, আমি স্বীকার করব যে আপনি যদি আপনার জাভা অবজেক্টে ঘন ঘন ক্ষেত্রগুলি সংশোধন করতে যাচ্ছেন তবে জেসির দৃষ্টিভঙ্গি আরও ভাল দেখাচ্ছে। এটি ব্যবহারের সহজলভ্যতা বনাম নমনীয়তার একটি বাণিজ্য your


4
এই সমস্ত অন্যান্য ক্ষেত্রের প্রতিনিধিত্ব করতে ব্যর্থ valuegson করতে
ওয়েসলি

10

আমার সহকর্মীও @JsonAdapterটীকা ব্যবহারের কথা উল্লেখ করেছিল

https://google.github.io/gson/apidocs/com/google/gson/annotations/JsonAdapter.html

পৃষ্ঠাটি এখানে সরানো হয়েছে: https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/annotations/JsonAdapter.html

উদাহরণ:

 private static final class Gadget {
   @JsonAdapter(UserJsonAdapter2.class)
   final User user;
   Gadget(User user) {
       this.user = user;
   }
 }

4
এটি আমার ব্যবহারের ক্ষেত্রে খুব ভাল কাজ করে। অনেক ধন্যবাদ.
নিওক্ল্যাশ

4
এখানে একটি ওয়েবআর্কাইভ লিঙ্ক রয়েছে কারণ মূলটি এখন মৃত: web.archive.org/web/20180119143212/https://google.github.io/…
ভাসমান সানফিশ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.