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

我错过了什么?


当前回答

这里,'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;
}

其他回答

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

我一直在寻找枚举序列化的解决方案,我终于做出了一个解决方案。

https://github.com/sirgilligan/EnumerationSerialization

https://digerati-illuminatus.blogspot.com/2022/10/java-enum-generic-serializer-and.html

它使用了一个新的注释和两个新类EnumerationSerializer和EnumerationDeserializer。您可以子类化EnumerationDeserializer,并创建一个设置枚举class的类(典型方法),或者您可以注释枚举,并且不必拥有EnumerationDeserializer的子类。

@JsonSerialize(using = EnumerationSerializer.class)
@JsonDeserialize(using = EnumerationDeserializer.class)
@EnumJson(serializeProjection = Projection.NAME, deserializationClass = RGB.class)
enum RGB {
    RED,
    GREEN,
    BLUE
}

注意ContextualDeserializer的实现如何从注释中提取类。

https://github.com/sirgilligan/EnumerationSerialization/blob/main/src/main/java/org/example/EnumerationDeserializer.java

这里有很多很好的代码,可以提供一些见解。

对于你的具体问题,你可以这样做:

@JsonSerialize(using = EnumerationSerializer.class)
@JsonDeserialize(using = EnumerationDeserializer.class)
@EnumJson(serializeProjection = Projection.NAME, deserializationClass = Event.class)
public enum Event {
    FORGOT_PASSWORD("forgot password");

    //This annotation is optional because the code looks for value or alias.
    @EnumJson(serializeProjection = Projection.VALUE)
    private final String value;

    private Event(final String description) {
        this.value = description;
    }

}

或者你可以这样做:

@JsonSerialize(using = EnumerationSerializer.class)
@JsonDeserialize(using = EnumerationDeserializer.class)
@EnumJson(serializeProjection = Projection.NAME, deserializationClass = Event.class)
public enum Event {
    FORGOT_PASSWORD("forgot password");

    private final String value;

    private Event(final String description) {
        this.value = description;
    }

}

这就是你要做的。

然后,如果您有一个“有”事件的类,您可以注释每个事件以您想要的方式序列化。

class EventHolder {
    @EnumJson(serializeProjection = Projection.NAME)
    Event someEvent;

    @EnumJson(serializeProjection = Projection.ORDINAL)
    Event someOtherEvent;

    @EnumJson(serializeProjection = Projection.VALUE)
    Event yetAnotherEvent;
}

您可以自定义任何属性的反序列化。

使用将要处理的属性的annotationJsonDeserialize (import com.fasterxml.jackson.databin .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;
    }
}

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

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