2015-06-11 5 views
3

У меня проблемы десериализации Перечисления, которые имеют несколько имен для значения. Вот пример: информация является классом Java, который имеет внутри перечисление с несколькими именами:Jackson deserialize Перечисления с несколькими именами

public class Info { 
    //... 
    private ContainerFormat format; 
} 

// ContainerFormat.java: 

public enum ContainerFormat { 
    // .... 
    MP4("mp4", "mpeg4"), 
    UNKNOWN("null"); 

    private String name; 
    private List<String> others; 

    ContainerFormat(String name) { 
     this.name = name; 
    } 

    /** The service does not always return the same String for output formats. 
    * This 'other' string fixes the deserialization issues caused by that. 
    */ 
    ContainerFormat(String name, String... others) { 
     this.name = name; 
     this.others = new ArrayList<String>(); 
     for (String other : others) { 
      this.others.add(other); 
     } 
    } 

    @JsonValue 
    @Override 
    public String toString() { 
     return name; 
    } 

    public List<String> otherNames() { 
     return others; 
    } 

    @JsonCreator 
    public static ContainerFormat fromValue(String other) throws JsonMappingException { 
     for (ContainerFormat format : ContainerFormat.values()) { 
      if (format.toString().equalsIgnoreCase(other)) { 
       return format; 
      } 
      if (format.otherNames() != null && format.otherNames().contains(other)) { 
       return format; 
      } 
     } 
     return UNKNOWN; 
    } 
} 

Проблема, когда я десериализации то, что содержит «mpeg4» вместо mp4 я получаю эту ошибку:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of com.foo.ContainerFormat from String value 'mpeg4': value not one of declared Enum instance names 
at [Source: N/A; line: -1, column: -1] (through reference chain: com.foo.Info["format"]) 
    at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:55) 
    at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:650) 
    at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:85) 
    at com.fasterxml.jackson.databind.deser.std.EnumDeserializer.deserialize(EnumDeserializer.java:20) 
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375) 
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121) 
    at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2769) 
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1478) 
    at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:1811) 

Любые указатели на то, как исправить это?

ТИА

ответ

3

я нашел хорошее решение, основанное на ответ Флорин:

правильной конфигурации с Джексоном 2.7.0-RC2 (и, вероятно, также до того)

private ObjectMapper createObjectMapper() { 
    final ObjectMapper mapper = new ObjectMapper(); 
    // enable toString method of enums to return the value to be mapped 
    mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); 
    mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); 
    return mapper; 
} 

В вашем перечислении вы просто должны переопределить метод ToString():

public enum EXAMPLE_TYPE { 
START("start"), 
MORE("more"); 

    // the value which is used for matching 
    // the json node value with this enum 
    private final String value; 

    SectionType(final String type) { 
     value = type; 
    } 

    @Override 
    public String toString() { 
     return value; 
    } 
} 

Вам не нужно никаких аннотаций или пользовательских deserializers.

0

Избавьтесь от String name и List<String> other и вместо иметь только одно поле - List<String> names и сериализовать единственный добытчик с @JsonValue

public enum ContainerFormat { 
// .... 
MP4("mp4", "mpeg4"), 
UNKNOWN("null"); 

private List<String> names; 

ContainerFormat(List<String> names) { 
    this.names = new ArrayList<String>(names); 
} 

@JsonValue 
public List<String> getNames() 
{ 
    return this.names; 
} 

@JsonCreator 
public static ContainerFormat getContainerFromValue(String value) throws JsonMappingException { 
    for (ContainerFormat format : ContainerFormat.values()) { 
     if(format.getValues().contains(value)) 
      return format; 
    } 
    return UNKNOWN; 
} 

В качестве альтернативы, если вы выбираете чтобы сохранить существующий код, вы можете попробовать аннотировать otherValues() с @JsonValue

+0

У меня есть значения, которые имеют только одно имя: 'M4A (" m4a ")' Это не будет работать с этим предлагаемым решением. –

+0

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

0

Ну, я нашел обходной путь: один из этих флагов делает правильно, и позволяет мне читать, что mpeg4 назад в:

mapper.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false); 
    mapper.configure(org.codehaus.jackson.map.SerializationConfig.Feature.WRITE_ENUMS_USING_TO_STRING, true); 
    mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.READ_ENUMS_USING_TO_STRING, true); 
    mapper.setPropertyNamingStrategy(org.codehaus.jackson.map.PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES); 
    mapper.setSerializationInclusion(org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_EMPTY); 
    mapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
Смежные вопросы