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

我错过了什么?


当前回答

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

其他回答

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

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

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

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

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

代码结果如下所示

{"someenum":"SOME_PROPERTY"}
@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"
}
]

这里,'value'充当反序列化器,'namespace'充当序列化器。因此,你可以在保存时将值“Student Absent”传递给API,在DB中它将被保存为“STUDENT_ABSENT”。另一方面,在检索类中的数据时,API将返回“Student Absent”。

import com.fasterxml.jackson.annotation.JsonProperty;
public enum AttendanceEnums {
    STUDENT_PRESENT,
    @JsonProperty(value = "Student Absent", namespace = "Student Absent")
    STUDENT_ABSENT;
}