জেএসএন-এর সাথে পার্স করার সময় এনামগুলি ব্যবহার করা


119

এটি আমি এখানে আগে জিজ্ঞাসা করা একটি আগের প্রশ্নের সাথে সম্পর্কিত

জসন জিএসন ব্যবহার করে পার্সিং করছে

আমি একই জেএসএনকে বিশ্লেষণ করার চেষ্টা করছি তবে এখন আমি আমার ক্লাসগুলি কিছুটা পরিবর্তন করেছি।

{
    "lower": 20,
    "upper": 40,
    "delimiter": " ",
    "scope": ["${title}"]
}

আমার ক্লাসটি এখন এমন দেখাচ্ছে:

public class TruncateElement {

   private int lower;
   private int upper;
   private String delimiter;
   private List<AttributeScope> scope;

   // getters and setters
}


public enum AttributeScope {

    TITLE("${title}"),
    DESCRIPTION("${description}"),

    private String scope;

    AttributeScope(String scope) {
        this.scope = scope;
    }

    public String getScope() {
        return this.scope;
    }
}

এই কোডটি একটি ব্যতিক্রম ছুঁড়েছে,

com.google.gson.JsonParseException: The JsonDeserializer EnumTypeAdapter failed to deserialized json object "${title}" given the type class com.amazon.seo.attribute.template.parse.data.AttributeScope
at 

ব্যতিক্রমটি বোধগম্য, কারণ আমার আগের প্রশ্নের সমাধান অনুসারে, জিএসওএন প্রত্যাশা করছে যে এনাম বস্তুগুলি আসলে তৈরি হবে

${title}("${title}"),
${description}("${description}");

তবে যেহেতু এটি সিনট্যাক্টিকভাবে অসম্ভব, তাই প্রস্তাবিত সমাধানগুলি কী কী?

উত্তর:


57

গসনের জন্য ডকুমেন্টেশন থেকে :

জিসন এনামদের জন্য ডিফল্ট সিরিয়ালাইজেশন এবং ডিসরিয়ালাইজেশন সরবরাহ করে ... আপনি যদি ডিফল্ট উপস্থাপনা পরিবর্তন করতে পছন্দ করেন তবে আপনি GsonBuilder.registerTypeAdapter (টাইপ, অবজেক্ট) এর মাধ্যমে টাইপ অ্যাডাপ্টার নিবন্ধভুক্ত করে এটি করতে পারেন।

নিম্নলিখিত যেমন একটি পদ্ধতির হয়।

import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

public class GsonFoo
{
  public static void main(String[] args) throws Exception
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(AttributeScope.class, new AttributeScopeDeserializer());
    Gson gson = gsonBuilder.create();

    TruncateElement element = gson.fromJson(new FileReader("input.json"), TruncateElement.class);

    System.out.println(element.lower);
    System.out.println(element.upper);
    System.out.println(element.delimiter);
    System.out.println(element.scope.get(0));
  }
}

class AttributeScopeDeserializer implements JsonDeserializer<AttributeScope>
{
  @Override
  public AttributeScope deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    AttributeScope[] scopes = AttributeScope.values();
    for (AttributeScope scope : scopes)
    {
      if (scope.scope.equals(json.getAsString()))
        return scope;
    }
    return null;
  }
}

class TruncateElement
{
  int lower;
  int upper;
  String delimiter;
  List<AttributeScope> scope;
}

enum AttributeScope
{
  TITLE("${title}"), DESCRIPTION("${description}");

  String scope;

  AttributeScope(String scope)
  {
    this.scope = scope;
  }
}

309

আমি কিছুটা NAZIK / user2724653 উত্তর (আমার ক্ষেত্রে) প্রসারিত করতে চাই। এখানে একটি জাভা কোড রয়েছে:

public class Item {
    @SerializedName("status")
    private Status currentState = null;

    // other fields, getters, setters, constructor and other code...

    public enum Status {
        @SerializedName("0")
        BUY,
        @SerializedName("1")
        DOWNLOAD,
        @SerializedName("2")
        DOWNLOADING,
        @SerializedName("3")
        OPEN
     }
}

জসন ফাইলে আপনার কেবল একটি ক্ষেত্র রয়েছে "status": "N",, যেখানে এন = 0,1,2,3 - স্থিতির মানগুলির উপর নির্ভর করে। তাই সব, GSONনেস্টেড enumবর্গের মানগুলির সাথে সূক্ষ্মভাবে কাজ করে । আমার ক্ষেত্রে আমি অ্যারে Itemsথেকে একটি তালিকা পার্স করেছি json:

List<Item> items = new Gson().<List<Item>>fromJson(json,
                                          new TypeToken<List<Item>>(){}.getType());

28
এই উত্তরটি পুরোপুরি সবকিছু সমাধান করে, টাইপ অ্যাডাপ্টারের প্রয়োজন নেই!
লেনা ব্রু

4
যখন আমি এটি করি, রেট্রোফিট / জিসনের সাথে, এনাম মানগুলির সিরিয়ালাইজড নেমে অতিরিক্ত উদ্ধৃতি চিহ্ন যুক্ত হয়। সার্ভারটি প্রকৃতপক্ষে "1"কেবলমাত্র পরিবর্তে 1... উদাহরণস্বরূপ প্রাপ্ত হয় ...
ম্যাথু হউসার

17
কি হবে, স্ট্যাটাস 5 সহ জসন উপস্থিত হবে? ডিফল্ট মান নির্ধারণ করার কোনও উপায় আছে কি?
দিমিত্রিওরোডিন

8
@ দিমিত্রিওরোডিন যদি জেএসএন থেকে প্রাপ্ত মান কোনওটির সাথে মেলে না SerializedNameতবে এনাম ডিফল্ট হবে null। অজানা রাষ্ট্রের ডিফল্ট আচরণটি একটি মোড়কের ক্লাসে পরিচালনা করা যেতে পারে। তবে আপনার যদি তবে "অজানা" এর জন্য অন্য কোনও উপস্থাপনা nullপ্রয়োজন হয় তবে আপনাকে একটি কাস্টম ডিসরিয়ালাইজার লিখতে হবে বা অ্যাডাপ্টার টাইপ করতে হবে।
পিটার এফ


9

জিএসওএন সংস্করণ ২.২.২ সহ এনাম মার্শাল করা হবে এবং সহজেই নিবিড় করে দেওয়া হবে।

import com.google.gson.annotations.SerializedName;

enum AttributeScope
{
  @SerializedName("${title}")
  TITLE("${title}"),

  @SerializedName("${description}")
  DESCRIPTION("${description}");

  private String scope;

  AttributeScope(String scope)
  {
    this.scope = scope;
  }

  public String getScope() {
    return scope;
  }
}

8

নীচের স্নিপেটটি জেনসন ২.৩ থেকে উপলব্ধ টীকাটি Gson.registerTypeAdapter(...)ব্যবহার করে সুস্পষ্টর প্রয়োজনীয়তা সরিয়ে @JsonAdapter(class)ফেলল (মন্তব্য pm_labs দেখুন )।

@JsonAdapter(Level.Serializer.class)
public enum Level {
    WTF(0),
    ERROR(1),
    WARNING(2),
    INFO(3),
    DEBUG(4),
    VERBOSE(5);

    int levelCode;

    Level(int levelCode) {
        this.levelCode = levelCode;
    }

    static Level getLevelByCode(int levelCode) {
        for (Level level : values())
            if (level.levelCode == levelCode) return level;
        return INFO;
    }

    static class Serializer implements JsonSerializer<Level>, JsonDeserializer<Level> {
        @Override
        public JsonElement serialize(Level src, Type typeOfSrc, JsonSerializationContext context) {
            return context.serialize(src.levelCode);
        }

        @Override
        public Level deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
            try {
                return getLevelByCode(json.getAsNumber().intValue());
            } catch (JsonParseException e) {
                return INFO;
            }
        }
    }
}

1
দয়া করে মনে রাখবেন যে এই টীকাগুলি কেবলমাত্র 2.3 সংস্করণটি উপলব্ধ: google.github.io/gson/apidocs/index.html?com/google/gson/…
pm_labs

3
আপনার অগ্রগামী কনফিগারেশনে আপনার সিরিয়ালাইজার / ডিসরিয়ালাইজার-ক্লাস যুক্ত করার বিষয়ে সতর্ক থাকুন, সেগুলি মুছে ফেলা হতে পারে (এটি আমার জন্য ঘটেছিল)
টরুমন্ডথুন্ডফার্লিস্ট

2

আপনি যদি সত্যিই এনামের মূল মানটি ব্যবহার করতে চান তবে আপনি গসনের ডিফল্ট কারখানাকে ওভাররাইড করতে একটি টাইপ অ্যাডাপ্টার কারখানাটি নিবন্ধভুক্ত করতে পারেন।

public class EnumTypeAdapter <T extends Enum<T>> extends TypeAdapter<T> {
    private final Map<Integer, T> nameToConstant = new HashMap<>();
    private final Map<T, Integer> constantToName = new HashMap<>();

    public EnumTypeAdapter(Class<T> classOfT) {
        for (T constant : classOfT.getEnumConstants()) {
            Integer name = constant.ordinal();
            nameToConstant.put(name, constant);
            constantToName.put(constant, name);
        }
    }
    @Override public T read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }
        return nameToConstant.get(in.nextInt());
    }

    @Override public void write(JsonWriter out, T value) throws IOException {
        out.value(value == null ? null : constantToName.get(value));
    }

    public static final TypeAdapterFactory ENUM_FACTORY = new TypeAdapterFactory() {
        @SuppressWarnings({"rawtypes", "unchecked"})
        @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
            Class<? super T> rawType = typeToken.getRawType();
            if (!Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) {
                return null;
            }
            if (!rawType.isEnum()) {
                rawType = rawType.getSuperclass(); // handle anonymous subclasses
            }
            return (TypeAdapter<T>) new EnumTypeAdapter(rawType);
        }
    };
}

তারপরে শুধু কারখানাটি নিবন্ধ করুন।

Gson gson = new GsonBuilder()
               .registerTypeAdapterFactory(EnumTypeAdapter.ENUM_FACTORY)
               .create();

0

এই পদ্ধতি ব্যবহার করুন

GsonBuilder.enableComplexMapKeySerialization();

3
যদিও এই কোডটি প্রশ্নের উত্তর দিতে পারে, কীভাবে এবং / বা কেন এটি সমস্যার সমাধান করে তা সম্পর্কিত অতিরিক্ত প্রসঙ্গ সরবরাহ করলে উত্তরের দীর্ঘমেয়াদী মান উন্নত হবে।
নিক 3500

জিএসএস ২.৮.৫ অনুসারে, আপনি কী হিসাবে ব্যবহার করতে চান এমন
এনামগুলিতে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.