杰克逊 - 反序列化一个基本枚举类型

18

是否可以对具有从1开始的索引的枚举进行反序列化?

enum Status {
  Active,
  Inactive
}

{status:1}的意思是Status.Active,但Jackson却把它变成了Status.Inactive :(


1
这个问题与序列化无关。 - Óscar López
就像奥斯卡所说,枚举(以及计算机科学一般)是从0开始的。如果你从另一层接收到一个数字,请减去1。 - rynmrtn
3个回答

49
public enum Status {
ACTIVE(1),
INACTIVE(2);
private final int value;
Status(int v) {
    value = v;
}
@org.codehaus.jackson.annotate.JsonValue
public int value() {
    return value;
}  
@org.codehaus.jackson.annotate.JsonCreator
public static Status fromValue(int typeCode) {
    for (Status c: Status.values()) {
        if (c.value==typeCode) {
            return c;
        }
    }
    throw new IllegalArgumentException("Invalid Status type code: " + typeCode);        

}}

3
这实际上是一个比我更简单、更通俗易懂的解决方案。感谢分享。 - Nathan
这也是处理枚举在序列化时大小写未知的常见问题的好方法。 - Nick Campion
但如果枚举是第三方的呢? - gstackoverflow
1
@gstackoverflow 你可以使用Jackson mixins。 - Matt Ball

10

您可以为枚举创建自定义类型解串器:

public enum Status {
    ACTIVE,
    INACTIVE;
    public static Status fromTypeCode(final int typeCode) {
        switch(typeCode) {
        case 1: return ACTIVE;
        case 2: return INACTIVE;
        }
        throw new IllegalArgumentException("Invalid Status type code: " + typeCode);
    }
}

public class StatusDeserializer extends JsonDeserializer<Status> {
    @Override
    public Status deserialize(final JsonParser parser, final DeserializationContext context) throws IOException {
        return Status.fromTypeCode(parser.getValueAsInt());
    }
}

然后,您可以告诉Jackson在属性中使用您的自定义反序列化器:

public class WarpDrive {
    private Status status; 
    @JsonDeserialize(using = StatusDeserializer.class)
    public void setStatus(final Status status) {
        this.status = status;
    }
    public Status getStatus() {
        return this.status;
    }
}

你还可以配置Jackson对象映射器,以在目标类型的所有出现中使用自定义反序列化程序。请参见http://wiki.fasterxml.com/JacksonHowToCustomDeserializers


2

枚举类型有数字序号,从零开始,每个枚举值都按照声明的顺序分配序号。例如,在您的代码中,Active 的序号为 0,而 Inactive 的序号为 1。您可以通过以下方式在枚举值和其序号之间进行转换:

// ordinal=0, since Active was declared first in the enum
int ordinal = Status.Active.ordinal();

// enumVal=Active, since 0 is the ordinal corresponding to Active
Status enumVal = Status.values()[0];

很明显,序数1对应于Inactive(这不是Jackson的问题),如上所述,在枚举中的序数是从零开始的。也许你应该修复你的代码以反映这一点,并确保{status:0}表示Status.Active


1
很明显,在Java世界中,0表示Status.Active!但这不是我的API,我只是在实现一个客户端。API表明1表示Active,2表示Inactive。所以我的问题是,我是否可以让Jackson知道这一点。也许通过添加一个虚拟值来将序数向前移动一位就可以了。 - Dirk
2
不建议使用枚举序数,更不要在序列化中使用它们,因为枚举定义的更改可能会更改序数。 - florian
在我看来,这个答案并没有回答问题。 - Max S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接