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

我错过了什么?


当前回答

实际的回答:

枚举的默认反序列化器使用.name()来反序列化,所以它没有使用@JsonValue。因此,正如@OldCurmudgeon指出的那样,您需要传入{"event": " forget_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;
    }

}

最后一点,特别是对于使用getYourValue()方法序列化的枚举JsonEnum,你的序列化器和反序列化器可能看起来像这样:

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

其他回答

实际的回答:

枚举的默认反序列化器使用.name()来反序列化,所以它没有使用@JsonValue。因此,正如@OldCurmudgeon指出的那样,您需要传入{"event": " forget_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;
    }

}

最后一点,特别是对于使用getYourValue()方法序列化的枚举JsonEnum,你的序列化器和反序列化器可能看起来像这样:

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

以我为例,这就是解决方案:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum PeriodEnum {

    DAILY(1),
    WEEKLY(2),
    ;

    private final int id;

    PeriodEnum(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return this.name();
    }

    @JsonCreator
    public static PeriodEnum fromJson(@JsonProperty("name") String name) {
        return valueOf(name);
    }
}

序列化和反序列化以下json:

{
  "id": 2,
  "name": "WEEKLY"
}

我希望这能有所帮助!

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

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

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

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

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

试试这个。

public enum Event {

    FORGOT_PASSWORD("forgot password");

    private final String value;

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

    private Event() {
        this.value = this.name();
    }

    @JsonValue
    final String value() {
        return this.value;
    }
}