我使用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

我错过了什么?


当前回答

您应该创建一个静态工厂方法,该方法接受单个参数,并使用@JsonCreator进行注释(从Jackson 1.2开始可用)

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

点击这里阅读更多关于JsonCreator注释的内容。

其他回答

这篇文章是旧的,但如果它可以帮助别人,使用JsonFormat.Shape.STRING

@JsonFormat(shape = JsonFormat.Shape.STRING)
public enum SomeEnum{
    @JsonProperty("SOME_PROPERTY")
    someProperty,
    ...
}

代码结果如下所示

{"someenum":"SOME_PROPERTY"}

如果您希望将枚举类与其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
    }
}

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

根据@JsonValue的jackson-annotations javadoc:

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

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

您应该创建一个静态工厂方法,该方法接受单个参数,并使用@JsonCreator进行注释(从Jackson 1.2开始可用)

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

点击这里阅读更多关于JsonCreator注释的内容。

下面是另一个使用字符串值而不是映射的例子。

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;
    }
}