263

JAVA 1.6 と Jackson 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;
    }
}

@JsonValue を追加しました。これは、オブジェクトをシリアル化する仕事をしているようです。

{"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

17 に答える 17

323

@xbakesxによって指摘されたシリアライザー/デシリアライザーのソリューションは、JSON 表現から列挙型クラスを完全に切り離したい場合に優れたソリューションです。

@JsonCreatorまたは、自己完結型のソリューションを好む場合は、およびアノテーションに基づく実装の@JsonValue方が便利です。

したがって、@Stanley による例を活用すると以下は完全な自己完結型ソリューション (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
    }
}
于 2013-12-06T10:23:35.357 に答える
245

2015 年 6 月のこのコミット(Jackson 2.6.2 以降) の時点で、次のように簡単に記述できることに注意してください。

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

動作はここに文書化されています: https://fasterxml.github.io/jackson-annotations/javadoc/2.11/com/fasterxml/jackson/annotation/JsonProperty.html

Jackson 2.6 以降では、この注釈を使用して Enum のシリアル化を次のように変更することもできます。

 public enum MyEnum {
      @JsonProperty("theFirstValue") THE_FIRST_VALUE,
      @JsonProperty("another_value") ANOTHER_VALUE;
 }

JsonValue アノテーションを使用する代わりに。

于 2015-09-22T17:56:59.033 に答える
97

単一の引数を取り、それに注釈を付ける静的ファクトリメソッドを作成する必要があります@JsonCreator(Jackson 1.2以降で利用可能)

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

JsonCreator アノテーションの詳細については、こちらをご覧ください。

于 2013-07-02T08:21:32.310 に答える
47

実際の答え:

列挙型のデフォルトのデシリアライザーは.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最後に、特にmethodでシリアル化する列挙型に対してこれを行う場合、シリアライザー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;
}
于 2012-11-13T21:08:57.560 に答える
42

私の場合のように列挙型クラスを変更できない場合に特に便利です。次に、特定の機能を有効にしたカスタム 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);
    }
}

利用可能な enum 関連の機能は他にもあります。こちらを参照してください。

https://github.com/FasterXML/jackson-databind/wiki/Serialization-Features https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features

于 2014-07-02T17:37:04.200 に答える
7

任意の属性の逆シリアル化をカスタマイズできます。

import com.fasterxml.jackson.databind.annotation.JsonDeserialize処理される属性に対して、annotationJsonDeserialize () を使用して、デシリアライズ クラスを宣言します。これが列挙型の場合:

@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;
    }
}
于 2015-10-08T21:32:47.333 に答える
5

マップの代わりに文字列値を使用する別の例を次に示します。

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;
    }
}
于 2016-01-29T23:32:16.283 に答える
5

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;
    }
  }
}
于 2016-08-31T22:05:55.810 に答える