Удалить десериализацию enum в json из другой строки [duplicate]

In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']

Остерегайтесь

In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1]) 

, где вы можете ожидать / хотите, чтобы он был равен set([1, 3]). Если вы хотите, чтобы в качестве ответа вы set([1, 3]), вам нужно использовать set([1, 2]).symmetric_difference(set([2, 3])).

164
задан Mason Wan 22 October 2013 в 06:20
поделиться

9 ответов

Решение сериализатора / десериализатора, указанное xbakesx, является превосходным, если вы хотите полностью разделить класс enor enum из его представления JSON.

Альтернативно, если вы предпочитаете автономное решение, реализация основанные на @JsonCreator и @JsonValue, были бы более удобными.

Таким образом, используя пример Стэнли, это полное автономное решение (Java 6, Jackson 1.9):

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
    }
}
195
ответ дан maja 22 August 2018 в 09:29
поделиться
  • 1
    Добавление только @JsonValue сработало для меня. Благодарю. – Alessandro 30 October 2014 в 18:19
  • 2
    @Agusti, пожалуйста, взгляните на мой вопрос, что мне там не хватает stackoverflow.com/questions/30525986/enum-is-not-binding – Prabjot Singh 29 May 2015 в 09:30
  • 3
    может быть очевидным для некоторых, но обратите внимание, что @ JsonValue используется для сериализации и @ JsonCreator для десериализации. Если вы не делаете, вам понадобится только один или другой. – acvcu 9 October 2015 в 20:19
  • 4
    @Agusti, пожалуйста, скажите мне, как я буду использовать (вызывать) это перечисление в моем json – Deepika Rajani 7 April 2016 в 06:39
  • 5
    Мне действительно не нравится это решение для простого факта, что вы вводите два источника истины. Разработчику всегда нужно помнить, чтобы добавить имя в два места. Я предпочитаю решение, которое делает правильную вещь, не украшая внутренности перечисления с помощью карты. – mttdbrd 10 October 2016 в 18:41
  • 6

В контексте перечисления, используя @JsonValue сейчас (начиная с версии 2.0), работает для сериализации и десериализации.

Согласно аннотации джоксона javadoc для @JsonValue :

ПРИМЕЧАНИЕ. При использовании для перечислений Java одна дополнительная функция - это то, что значение, возвращаемое аннотированным методом, также считается значением десериализации, а не только JSON Строка для сериализации как. Это возможно, так как множество значений Enum является постоянным, и можно определить отображение, но не может быть сделано вообще для типов POJO; как таковой, это не используется для десериализации POJO.

Итак, с enumated Event, аннотированным так же, как описано выше (для сериализации и десериализации) с jackson 2.0 +.

0
ответ дан Brice Roncace 22 August 2018 в 09:29
поделиться

Вот еще один пример, который использует строковые значения вместо карты.

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;
    }
}
3
ответ дан Gremash 22 August 2018 в 09:29
поделиться

Я нашел очень приятное и сжатое решение, особенно полезное, когда вы не можете модифицировать классы enum, как это было в моем случае. Затем вы должны предоставить настраиваемый ObjectMapper с включенной определенной функцией. Эти функции доступны с Jackson 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-Features https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features

25
ответ дан lagivan 22 August 2018 в 09:29
поделиться
  • 1
    не знаете, почему вам нужно расширить класс. вы можете включить эту функцию в экземпляре ObjectMapper. – mttdbrd 10 October 2016 в 18:54
  • 2
    +1, потому что он указал мне на [READ | WRITE] _ENUMS_USING_TO_STRING, который я могу использовать в Spring application.yml – HelLViS69 15 February 2018 в 12:29
  • 3
    Ссылки на wiki.fasterxml.com больше не работают – a_horse_with_no_name 27 February 2018 в 09:08
  • 4
    @a_horse_with_no_name обновлено до github wiki – lagivan 28 February 2018 в 09:36

Вы можете настроить десериализацию для любого атрибута.

Объявить класс десериализации, используя аннотацию JsonDeserialize (import com.fasterxml.jackson.databind.annotation.JsonDeserialize) для атрибута, который будет обработан. Если это Enum:

@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
ответ дан raffian 22 August 2018 в 09:29
поделиться
  • 1
    Вы должны объяснить , почему это работает. – Nathaniel Ford 8 October 2015 в 21:57
  • 2
    Натаниэль Форд, стало лучше? – Fernando Gomes 27 January 2016 в 20:14
  • 3
    Да, это гораздо лучший ответ; он предоставляет некоторый контекст. Я бы пошел еще дальше, и обсуждать, почему добавление десериализации таким образом относится к конкретному препятствию OP. – Nathaniel Ford 27 January 2016 в 20:57

Существуют различные подходы, которые вы можете предпринять для выполнения десериализации объекта JSON для перечисления. Мой любимый стиль - создать внутренний класс:

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;
    }
  }
}
3
ответ дан Sam Berry 22 August 2018 в 09:29
поделиться

Вы должны создать статический заводский метод, который принимает один аргумент и аннотирует его с помощью @JsonCreator (доступно с Jackson 1.2)

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

Подробнее о аннотации JsonCreator здесь .

74
ответ дан Stanley 22 August 2018 в 09:29
поделиться
  • 1
    Это самое чистое и кратчайшее решение, остальное - всего лишь тонны шаблонов, которые можно (и должно!) Избегать любой ценой! – Clint Eastwood 1 July 2014 в 22:07
  • 2
    @JSONValue для сериализации и @JSONCreator для десериализации. – Chiranjib 27 March 2017 в 12:51
  • 3

Обратите внимание, что с это commit в июне 2015 года (Jackson 2.6.2 и выше) теперь вы можете просто написать:

public enum Event {
    @JsonProperty("forgot password")
    FORGOT_PASSWORD;
}
137
ответ дан tif 22 August 2018 в 09:29
поделиться
  • 1
    время для обновления. – Wei Zhu 21 March 2016 в 07:40
  • 2
    хорошее решение. Жаль, что я застрял с 2.6.0 в Dropwizard :-( – Clint Eastwood 18 May 2016 в 16:44
  • 3
    он работает как для сериализации, так и для десериализации – Mher Sarkissian 20 December 2016 в 19:45
  • 4
    К сожалению, это не возвращает свойство при преобразовании вашего перечисления в строку. – Nicholas 31 May 2017 в 16:02
  • 5
    Эта функция была устаревшей с 2.8. – pqian 10 October 2017 в 07:27

Фактический ответ:

Дессериализатор по умолчанию для перечислений использует .name() для десериализации, поэтому он не использует @JsonValue. Так, как отметил @OldCurmudgeon, вам нужно пройти в {"event": "FORGOT_PASSWORD"}, чтобы соответствовать значению .name().

Другой вариант (если вы хотите, чтобы значения записи и чтения json были одинаковыми) ...

Дополнительная информация:

Существует еще один способ управления процессом сериализации и десериализации с помощью Jackson. Вы можете указать эти аннотации для использования своего собственного сериализатора и десериализатора:

@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;
}
36
ответ дан xbakesx 22 August 2018 в 09:29
поделиться
  • 1
    Использование пользовательского (де) сериализатора убивает простоту (которая использует Джексон стоит, кстати), поэтому это необходимо в действительно тяжелых ситуациях. Используйте @JsonCreator, как описано ниже, и отметьте этот комментарий – Dmitry Gryazin 13 October 2014 в 14:37
  • 2
    Этот soluiton лучше всего подходит для некоторой сумасшедшей проблемы, введенной в вопросе OP. Реальная проблема здесь в том, что OP хочет вернуть структурированные данные в форме rendered . То есть, они возвращают данные, которые уже содержат удобную для пользователя строку. Но для того, чтобы превратить визуализированную форму обратно в идентификатор, нам нужен код, который может изменить преобразование. Хакерный принятый ответ хочет использовать карту для обработки преобразования, но требует большего обслуживания. С помощью этого решения вы можете добавлять новые перечисляемые типы, а затем ваши разработчики могут работать со своими заданиями. – mttdbrd 11 April 2017 в 05:00
Другие вопросы по тегам:

Похожие вопросы: