2012-01-09 3 views
17

Можно ли десериализовать перечисления, которые имеют один индекс?Jackson - десериализовать одну базовую enums

enum Status { 
    Active, 
    Inactive 
} 

{Статус: 1} означает Status.Active, но Джексон делает его Status.Inactive :(

+1

вопрос не имеет ничего общего с сериализации –

+0

Как Оскар говорит, перечисление (и информатики в целом) является 0 на основе. Вычитайте 1 из числа, если это то, что вы получаете от другого слоя. – rynmrtn

ответ

10

Вы можете создать пользовательский тип deserialiser для перечисления:

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

Вы можете сказать Джексон использовать пользовательские deserialiser для свойства:

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

Вы также можете настроить объект Джексона mapper, чтобы использовать свой десериализатор для всех вхождений целевого типа. См. http://wiki.fasterxml.com/JacksonHowToCustomDeserializers.

3

Перечни имеют числовые порядковые, начиная с нуля, и получить присваивается каждому значению в перечислении . в том порядке, в котором они были объявлены, например, в коде 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 (это не проблема Джексона), как объяснялось выше, ординалы в перечислении основаны на нуле. Возможно, вы должны исправить свой код, чтобы это отразить, и убедитесь, что {status:0} означает Status.Active.

+1

Его ясно, что 0 означает Status.Active в мире java! Но это не мой api, я только реализую клиента. И api говорит, что 1 означает Active и 2 Inactive. Так что мой вопрос был, если я могу рассказать об этом Джексону. Возможно, просто добавив фиктивное значение для смещения ординала на единицу. – Dirk

+2

Не рекомендуется использовать порядковые номера Enum, а тем более использовать их в сериализации, поскольку изменения в определении Enum могут изменять порядковые номера. – florian

44
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);   

}} 
+2

Это на самом деле более простое, более идиоматическое решение, чем мое. Спасибо, что поделился. – Nathan

+0

Это также отличный способ справиться с общей проблемой перечисления сериализуемых данных с неизвестной капитализацией. –

+0

но если перечисление является третьим лицом? – gstackoverflow