জ্যাকসন এনাম সিরিয়ালাইজিং এবং ডি-সিরিয়ারাইজার


225

আমি জাভা 1.6 এবং জ্যাকসন 1.9.9 ব্যবহার করছি আমি একটি এনাম পেয়েছি

public enum Event {
    FORGOT_PASSWORD("forgot password");

    private final String value;

    private Event(final String description) {
        this.value = description;
    }

    @JsonValue
    final String value() {
        return this.value;
    }
}

আমি একটি @ জসনভ্যালু যুক্ত করেছি, এটি কাজটি মনে করে যা এটি বস্তুকে সিরিয়ালাইজ করে:

{"event":"forgot password"}

তবে আমি যখন ডিজিটালাইজেশন করার চেষ্টা করি তখন আমি একটি পাই

Caused by: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.globalrelay.gas.appsjson.authportal.Event from String value 'forgot password': value not one of declared Enum instance names

আমি এখানে কি মিস করছি?


4
আপনি চেষ্টা করেছেন {"Event":"FORGOT_PASSWORD"}? ইভেন্ট এবং FORGOT_PASSWORD উভয়টিতে ক্যাপগুলি নোট করুন।
ওল্ড কার্মিউডজিয়ন


কে এখানে এসেছিল তাও যদি আপনি বিভিন্ন নামকরণের কনভেনশন অনুসরণ করেন তবে এর পরিবর্তে getValueএটি কার্যকর GetValueহয় না
গ্যাটার

উত্তর:


286

Serializer / deserializer সমাধান নির্দিষ্ট দ্বারা @xbakesx একটি চমৎকার এক যদি আপনি আপনার decouple সম্পূর্ণরূপে করতে ইচ্ছুক হয় enum তার তাদেরকে JSON উপস্থাপনা থেকে বর্গ।

বিকল্পভাবে, আপনি যদি একটি স্ব-অন্তর্ভুক্ত সমাধান পছন্দ করেন তবে এর উপর ভিত্তি করে একটি টিকা @JsonCreatorএবং @JsonValueএনোটেশন আরও সুবিধাজনক হবে।

সুতরাং @ স্ট্যানলির উদাহরণের উপর নির্ভর করে নীচে একটি সম্পূর্ণ স্বয়ংসম্পূর্ণ সমাধান (জাভা,, জ্যাকসন ১.৯):

public enum DeviceScheduleFormat {

    Weekday,
    EvenOdd,
    Interval;

    private static Map<String, DeviceScheduleFormat> namesMap = new HashMap<String, DeviceScheduleFormat>(3);

    static {
        namesMap.put("weekday", Weekday);
        namesMap.put("even-odd", EvenOdd);
        namesMap.put("interval", Interval);
    }

    @JsonCreator
    public static DeviceScheduleFormat forValue(String value) {
        return namesMap.get(StringUtils.lowerCase(value));
    }

    @JsonValue
    public String toValue() {
        for (Entry<String, DeviceScheduleFormat> entry : namesMap.entrySet()) {
            if (entry.getValue() == this)
                return entry.getKey();
        }

        return null; // or fail
    }
}

@Agusti দয়া আমার প্রশ্ন কটাক্ষপাত করা, কি আমি সেখানে অনুপস্থিত করছি stackoverflow.com/questions/30525986/enum-is-not-binding
Prabjot সিং

25
কারও কাছে সম্ভবত সুস্পষ্ট, তবে মনে রাখবেন যে @ জসনভ্যালু সিরিয়ালাইজেশনের জন্য এবং @ জসনক্রিটরকে ডিসেরায়ালাইজের জন্য ব্যবহৃত হয়। যদি আপনি উভয়ই না করেন তবে আপনার কেবল একটি বা অন্যটির প্রয়োজন হবে।
acvcu

6
আপনি সত্যের দুটি উত্স প্রবর্তন করেন এমন সাধারণ সত্যের জন্য আমি এই সমাধানটি সত্যিই অপছন্দ করি। বিকাশকারীকে সর্বদা দুটি জায়গায় নাম যুক্ত করতে হবে। আমি অনেকটা এমন একটি সমাধান পছন্দ করি যা মানচিত্রের সাথে এনামের অভ্যন্তরগুলি সজ্জিত না করে কেবল সঠিক কাজ করে।
mtdbrd

2
@ttdbrd সত্যকে একীকরণের জন্য এটি কীভাবে? gist.github.com/Scuilion/036c53fd7fee2de89701a95822c0fb60
কেভিন ও

1
স্থির মানচিত্রের পরিবর্তে আপনি YourEnum.values ​​() ব্যবহার করতে পারেন যা আপনারEnum এর অ্যারে দেয় এবং এতে পুনরাবৃত্তি করতে পারে
কে।

209

লক্ষ্য করুন হিসাবে এই কমিট জুন 2015 (জ্যাকসন 2.6.2 এবং পরবর্তী) আপনি এখন কেবল লিখতে পারেন:

public enum Event {
    @JsonProperty("forgot password")
    FORGOT_PASSWORD;
}

1
সুন্দর সমাধান ড্রপউইজার্ডে আমি ২. 2..০ বান্ডিল করে আটকেছি এটি লজ্জাজনক :-(
ক্লিন্ট ইস্টউড

1
দুর্ভাগ্যক্রমে আপনার এনামকে স্ট্রিংয়ে রূপান্তর করার সময় এটি সম্পত্তিটি ফিরিয়ে দেয় না।
নিকোলাস

4
এই বৈশিষ্ট্যটি ২.৮ থেকে অবহেলা করা হয়েছে।
pqian

2
এই সমাধানটি এনামকে সিরিয়ালাইজ এবং ডিসরিয়ালাইজ করার জন্য কাজ করে। 2.8 তে পরীক্ষিত।
ডাউনহিলসকি


88

আপনার একটি স্থিতিশীল কারখানা পদ্ধতি তৈরি করা উচিত যা একক যুক্তি নেয় এবং এটির সাথে এ্যানোটেট করে @JsonCreator(জ্যাকসন ১.২ থেকে উপলব্ধ)

@JsonCreator
public static Event forValue(String value) { ... }

জসনক্রিটর টিকা সম্পর্কে আরও পড়ুন এখানে


10
এটিই সবচেয়ে পরিষ্কার এবং সংক্ষিপ্ত সমাধান, বাকিগুলি হ'ল টন বয়লারপ্লেট যা (এবং হওয়া উচিত!) সর্বদা এড়ানো যায়!
ক্লিন্ট ইস্টউড

4
@JSONValueসিরিয়ালাইজ এবং @JSONCreatordeserialize।
চিরঞ্জিব

@JsonCreator public static Event valueOf(int intValue) { ... }গনিতকারীকে deserialize intকরা Event
oদও 95

1
@ ক্লিন্টএস্টউড অন্যান্য সমাধানগুলি এড়ানো উচিত কিনা তা নির্ভর করে আপনি এনাম থেকে সিরিয়ালাইজেশন / ডেসারিয়ালাইজেশন উদ্বেগ আলাদা করতে চান কিনা তার উপর নির্ভর করে।
আসা

44

আসল উত্তর:

এনামগুলির জন্য ডিফল্ট ডিসরিয়ালাইজার ডিসরিয়ালাইজেশন ব্যবহার .name()করে, সুতরাং এটি ব্যবহার করে না @JsonValue। সুতরাং @ ওল্ড কার্কামডজিয়ন যেমন উল্লেখ করেছেন, মানটির {"event": "FORGOT_PASSWORD"}সাথে মিল রাখতে আপনাকে পাস করতে হবে .name()

অন্য একটি বিকল্প (আপনি ধরে নিচ্ছেন যে আপনি লিখতে চান এবং জেসন মানগুলি একই রকম হয়) ...

অধিক তথ্য:

জ্যাকসনের সাথে সিরিয়ালাইজেশন এবং ডিসিরিয়ালাইজেশন প্রক্রিয়া পরিচালনা করার (এখনও) অন্য উপায় রয়েছে। আপনি নিজের নিজস্ব কাস্টম সিরিয়ালাইজার এবং ডিসরিয়ালাইজার ব্যবহার করতে এই টিকাগুলি নির্দিষ্ট করতে পারেন:

@JsonSerialize(using = MySerializer.class)
@JsonDeserialize(using = MyDeserializer.class)
public final class MyClass {
    ...
}

তারপরে আপনাকে লিখতে হবে MySerializerএবং MyDeserializerযা দেখতে দেখতে এটি দেখতে:

MySerializer

public final class MySerializer extends JsonSerializer<MyClass>
{
    @Override
    public void serialize(final MyClass yourClassHere, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
    {
        // here you'd write data to the stream with gen.write...() methods
    }

}

MyDeserializer

public final class MyDeserializer extends org.codehaus.jackson.map.JsonDeserializer<MyClass>
{
    @Override
    public MyClass deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
    {
        // then you'd do something like parser.getInt() or whatever to pull data off the parser
        return null;
    }

}

সর্বশেষে কিছুটা, বিশেষত এমন কোনও এনামের জন্য JsonEnumযা পদ্ধতিটির সাথে সিরিয়ালাইজ হয় getYourValue(), আপনার সিরিয়ালাইজার এবং ডিসরিওলাইজার এর মতো দেখতে পাবেন:

public void serialize(final JsonEnum enumValue, final JsonGenerator gen, final SerializerProvider serializer) throws IOException, JsonProcessingException
{
    gen.writeString(enumValue.getYourValue());
}

public JsonEnum deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException
{
    final String jsonValue = parser.getText();
    for (final JsonEnum enumValue : JsonEnum.values())
    {
        if (enumValue.getYourValue().equals(jsonValue))
        {
            return enumValue;
        }
    }
    return null;
}

3
কাস্টম (ডি) সিরিয়ালাইজের ব্যবহার সরলতা (যা জ্যাকসন ব্যবহার করছে এটি বিটিডব্লিউর জন্য মূল্যবান) হ'ল, তাই এটি ভারী ভারী পরিস্থিতিতে প্রয়োজন। নীচে বর্ণিত হিসাবে @ জসনক্রিটার ব্যবহার করুন, এবং এই মন্তব্যটি দেখুন
দিমিত্রি গ্রিয়াজিন

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

34

আমি একটি খুব সুন্দর এবং সংক্ষিপ্ত সমাধান পেয়েছি, বিশেষত দরকারী যখন আপনি এনাম ক্লাসগুলি আমার ক্ষেত্রে যেমন পরিবর্তন করতে পারবেন না। তারপরে আপনার একটি নির্দিষ্ট বৈশিষ্ট্য সক্ষম থাকা কাস্টম অবজেক্টম্যাপার সরবরাহ করা উচিত। জ্যাকসন 1.6 থেকে এই বৈশিষ্ট্যগুলি উপলব্ধ। সুতরাং toString()আপনার এনামে কেবল আপনার পদ্ধতি লিখতে হবে ।

public class CustomObjectMapper extends ObjectMapper {
    @PostConstruct
    public void customConfiguration() {
        // Uses Enum.toString() for serialization of an Enum
        this.enable(WRITE_ENUMS_USING_TO_STRING);
        // Uses Enum.toString() for deserialization of an Enum
        this.enable(READ_ENUMS_USING_TO_STRING);
    }
}

আরও এনাম সম্পর্কিত বৈশিষ্ট্য উপলব্ধ রয়েছে, এখানে দেখুন:

https://github.com/FasterXML/jackson-databind/wiki/Serialization- ফিচারস https://github.com/FasterXML/jackson-databind/wiki/Deserialization- ফিচারস


10
আপনার ক্লাসটি বাড়ানোর প্রয়োজন কেন তা নিশ্চিত নন। আপনি অবজেক্টম্যাপারের উদাহরণে এই বৈশিষ্ট্যটি সক্ষম করতে পারেন।
এমটিডিডিবিআরড

+1 কারণ তিনি আমাকে [READ | WRITE] _ENUMS_USING_TO_STRING এর দিকে ইঙ্গিত করেছিলেন যা আমি স্প্রিং অ্যাপ্লিকেশনটিতে ব্যবহার করতে পারি
ym জিম

8

এটা চেষ্টা কর.

public enum Event {

    FORGOT_PASSWORD("forgot password");

    private final String value;

    private Event(final String description) {
        this.value = description;
    }

    private Event() {
        this.value = this.name();
    }

    @JsonValue
    final String value() {
        return this.value;
    }
}

6

আপনি কোনও বৈশিষ্ট্যের জন্য ডিসরিয়ালাইজেশন কাস্টমাইজ করতে পারেন।

import com.fasterxml.jackson.databind.annotation.JsonDeserializeযে বৈশিষ্ট্যটি প্রক্রিয়া করা হবে তার জন্য টীকা জেসন ডিজিজারাইজ ( ) ব্যবহার করে আপনার ডিসিরিয়ালাইজ শ্রেণি ঘোষণা করুন । যদি এটি এনুম হয়:

@JsonDeserialize(using = MyEnumDeserialize.class)
private MyEnum myEnum;

এইভাবে আপনার শ্রেণিটি অ্যাট্রিবিউটটি ডিসরিয়ালাইজ করতে ব্যবহৃত হবে। এটি একটি সম্পূর্ণ উদাহরণ:

public class MyEnumDeserialize extends JsonDeserializer<MyEnum> {

    @Override
    public MyEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        MyEnum type = null;
        try{
            if(node.get("attr") != null){
                type = MyEnum.get(Long.parseLong(node.get("attr").asText()));
                if (type != null) {
                    return type;
                }
            }
        }catch(Exception e){
            type = null;
        }
        return type;
    }
}

নাথানিয়েল ফোর্ড, ভাল হয়েছে?
ফার্নান্দো গোমেস

1
হ্যাঁ, এটি আরও ভাল উত্তর; এটি কিছু প্রসঙ্গ সরবরাহ করে। যদিও আমি আরও এগিয়ে যাব এবং আলোচনা করব যে কেন এই পদ্ধতিতে ডিসেরায়ালাইজেশন যুক্ত করা গেলে ওপি'র নির্দিষ্ট বাধা চিহ্নিত করে।
নাথানিয়েল ফোর্ড

5

একটি এনএম-তে কোনও জেএসওএন অবজেক্টের ডিসেরায়ালাইজেশন সম্পন্ন করতে বিভিন্ন পদ্ধতি রয়েছে। আমার প্রিয় স্টাইলটি একটি অভ্যন্তর শ্রেণি তৈরি করা:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.fasterxml.jackson.annotation.JsonFormat.Shape.OBJECT;

@JsonFormat(shape = OBJECT)
public enum FinancialAccountSubAccountType {
  MAIN("Main"),
  MAIN_DISCOUNT("Main Discount");

  private final static Map<String, FinancialAccountSubAccountType> ENUM_NAME_MAP;
  static {
    ENUM_NAME_MAP = Arrays.stream(FinancialAccountSubAccountType.values())
      .collect(Collectors.toMap(
        Enum::name,
        Function.identity()));
  }

  private final String displayName;

  FinancialAccountSubAccountType(String displayName) {
    this.displayName = displayName;
  }

  @JsonCreator
  public static FinancialAccountSubAccountType fromJson(Request request) {
    return ENUM_NAME_MAP.get(request.getCode());
  }

  @JsonProperty("name")
  public String getDisplayName() {
    return displayName;
  }

  private static class Request {
    @NotEmpty(message = "Financial account sub-account type code is required")
    private final String code;
    private final String displayName;

    @JsonCreator
    private Request(@JsonProperty("code") String code,
                    @JsonProperty("name") String displayName) {
      this.code = code;
      this.displayName = displayName;
    }

    public String getCode() {
      return code;
    }

    @JsonProperty("name")
    public String getDisplayName() {
      return displayName;
    }
  }
}

4

এখানে ম্যাপের পরিবর্তে স্ট্রিং মানগুলি ব্যবহার করে এমন অন্য একটি উদাহরণ।

public enum Operator {
    EQUAL(new String[]{"=","==","==="}),
    NOT_EQUAL(new String[]{"!=","<>"}),
    LESS_THAN(new String[]{"<"}),
    LESS_THAN_EQUAL(new String[]{"<="}),
    GREATER_THAN(new String[]{">"}),
    GREATER_THAN_EQUAL(new String[]{">="}),
    EXISTS(new String[]{"not null", "exists"}),
    NOT_EXISTS(new String[]{"is null", "not exists"}),
    MATCH(new String[]{"match"});

    private String[] value;

    Operator(String[] value) {
        this.value = value;
    }

    @JsonValue
    public String toStringOperator(){
        return value[0];
    }

    @JsonCreator
    public static Operator fromStringOperator(String stringOperator) {
        if(stringOperator != null) {
            for(Operator operator : Operator.values()) {
                for(String operatorString : operator.value) {
                    if (stringOperator.equalsIgnoreCase(operatorString)) {
                        return operator;
                    }
                }
            }
        }
        return null;
    }
}

4

এনামের প্রসঙ্গে, @JsonValueএখন ব্যবহার করা (২.০ থেকে) ক্রমিকায়নের জন্য কাজ করে এবং ডিসরিয়ালাইজেশনের ।

জ্যাকসন-এনোটেশন জাভাদোক@JsonValue অনুসারে :

দ্রষ্টব্য: জাভা এনামগুলির জন্য ব্যবহার করার সময়, একটি অতিরিক্ত বৈশিষ্ট্য হ'ল টীকাযুক্ত পদ্ধতিতে ফিরে আসা মানটিকে কেবল জেএসওন স্ট্রিং হিসাবে সিরিয়ালকরণের জন্য নয়, থেকে ডিসিরিয়ালাইজ করার মান হিসাবেও বিবেচনা করা হয়। এটি সম্ভব যেহেতু এনাম মানগুলির সেটটি ধ্রুবক এবং ম্যাপিং সংজ্ঞায়িত করা সম্ভব তবে POJO ধরণের ক্ষেত্রে সাধারণত করা যায় না; যেমন, এটি পজো ডিসরিয়ালাইজেশনের জন্য ব্যবহৃত হয় না।

সুতরাং Eventজ্যাকসন ২.০+ এর সাথে উপরের কাজগুলি (সিরিয়ালাইজেশন এবং ডিসরিয়ালাইজেশন উভয়ের জন্য) ঠিক যেমন এনোমেটযুক্ত রয়েছে um


3

@ জসনসরিয়ালাইজড @ জসনডিজারালাইজ ব্যবহার করার পাশাপাশি আপনি অবজেক্ট ম্যাপারে সিরিয়ালাইজেশন ফিচার এবং ডিসরিয়ালাইজেশন ফিচার (জ্যাকসন বাইন্ডিং) ব্যবহার করতে পারেন।

যেমন DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, যা সরবরাহকৃত এনাম শ্রেণিতে সংজ্ঞায়িত না হলে ডিফল্ট এনাম টাইপ দেয়।


0

আমি খুঁজে পাওয়া সবচেয়ে সহজ উপায় হ'ল এনজমের জন্য @ জসনফর্ম্যাট.শ্যাপ.ওবিজেইসিট টীকাগুলি।

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum MyEnum{
    ....
}

0

আমার ক্ষেত্রে, এটিই সমাধান করেছে:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum PeriodEnum {

    DAILY(1),
    WEEKLY(2),
    ;

    private final int id;

    PeriodEnum(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return this.name();
    }

    @JsonCreator
    public static PeriodEnum fromJson(@JsonProperty("name") String name) {
        return valueOf(name);
    }
}

নিম্নলিখিত জসনকে সিরিয়ালাইজ করে এবং ডিসরিয়ালাইজ করে:

{
  "id": 2,
  "name": "WEEKLY"
}

আমি আসা করি এটা সাহায্য করবে!

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