我使用JAVA 1.6和Jackson 1.9.9,我有一个enum

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

我错过了什么?


当前回答

在枚举上下文中,现在(从2.0开始)使用@JsonValue可用于序列化和反序列化。

根据@JsonValue的jackson-annotations javadoc:

注意:当用于Java枚举时,一个额外的特性是带注释的方法返回的值也被认为是要反序列化的值,而不仅仅是要序列化的JSON字符串。这是可能的,因为Enum值的集合是常量,可以定义映射,但不能在一般POJO类型;因此,这并不用于POJO反序列化。

因此,在jackson 2.0+中,像上面那样对Event枚举进行注释(对于序列化和反序列化都适用)。

其他回答

可以采用多种方法将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;
    }
  }
}

如果您希望将枚举类与其JSON表示完全解耦,@xbakesx指出的序列化器/反序列化器解决方案是一个很好的解决方案。

或者,如果您更喜欢自包含的解决方案,那么基于@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
    }
}
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum LoginOptionType {

 PHONE(1, "Phone"), MAIL(2, "mail"), PERSONAL_EMAIL(3, "Personal email");

private static List<LoginOptionType> all;

static {
    all = new ArrayList<LoginOptionType>() {
        {
            add(LoginOptionType.PHONE);
            add(LoginOptionType.MAIL);
            add(LoginOptionType.PERSONAL_EMAIL);
        }
    };
}

private final Integer viewValue;

private final String name;

LoginOptionType(Integer viewValue, String name) {
    this.viewValue = viewValue;
    this.name = name;
}

public Integer getViewValue() {
    return viewValue;
}

public String getName() {
    return name;
}

public static List<LoginOptionType> getAll() {
    return all;
}
}

响应

[
{
    "viewValue": 1,
    "name": "Phone"
},
{
    "viewValue": 2,
    "name": "mail"
},
{
    "viewValue": 3,
    "name": "Personal email"
}
]

我喜欢公认的答案。但是,我想稍微改进一下(考虑到现在有高于版本6的Java可用)。

例子:

    public enum Operation {
        EQUAL("eq"),
        NOT_EQUAL("ne"),
        LESS_THAN("lt"),
        GREATER_THAN("gt");

        private final String value;

        Operation(String value) {
            this.value = value;
        }

        @JsonValue
        public String getValue() {
            return value;
        }

        @JsonCreator
        public static Operation forValue(String value) {
            return Arrays.stream(Operation.values())
                .filter(op -> op.getValue().equals(value))
                .findFirst()
                .orElseThrow(); // depending on requirements: can be .orElse(null);
        }
    }

在枚举上下文中,现在(从2.0开始)使用@JsonValue可用于序列化和反序列化。

根据@JsonValue的jackson-annotations javadoc:

注意:当用于Java枚举时,一个额外的特性是带注释的方法返回的值也被认为是要反序列化的值,而不仅仅是要序列化的JSON字符串。这是可能的,因为Enum值的集合是常量,可以定义映射,但不能在一般POJO类型;因此,这并不用于POJO反序列化。

因此,在jackson 2.0+中,像上面那样对Event枚举进行注释(对于序列化和反序列化都适用)。