2012-01-11 6 views
4

У меня есть класс, который нужно десериализовать из JSON с помощью Jackson. Структура классов выглядит так:Джексон: игнорирование свойств вместо того, чтобы бросать JsonMappingException

public class A { 
    public B b; 
} 

public class B { 
    public List<C> c; 
} 

public class C { 
    public String s; 
    public Long l1; 
    public Long l2; 
    public Long l3; 
} 

Deserializing объекты в основном работают нормально; кроме, он взаимодействует с кодом ошибки, который испускает неправильное значение, когда список пуст. То есть, вместо того, чтобы испускать:

{ "b" : { "c" : [] } } 

он излучается:

{ "b" : { "c" : {} } } 

Джексон бросает это исключение, когда сталкивается с этим:

org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token 
at [Source: [[email protected]; line: 1, column: 896] (through reference chain: A["b"]->B["c"]) 

Все это имеет смысл, конечно. Вход неверный.

Однако, пустой список в этом случае не относится ни к одному из кодов; если это было null Мне было все равно. Есть ли способ сказать Джексону игнорировать это свойство (и хранить null), если его десериализировать невозможно?

Я попытался с помощью пользовательского десериализатор:

public class CListDeserializer extends JsonDeserializer<List<C>> 
{ 
    public CListDeserializer() { } 

    @Override 
    public List<C> deserialize(JsonParser arg0, 
     DeserializationContext arg1) throws IOException, 
      JsonProcessingException 
    { 
     try 
     { 
      return arg0.readValueAs(new TypeReference<List<C>>(){}); 
     } 
     catch (JsonMappingException jme) 
     { 
     } 
     return null; 
    } 
} 

А если добавить аннотацию к полю:

@JsonDeserialize(using=CListDeserializer.class) 
public List<C> c; 

я получаю это исключение вместо:

org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class asgard.ChangeEntry] from JSON String; no single-String constructor/factory method (through reference chain: A["b"]) 

Обратите внимание, что это исключение только происходит, если я попытаюсь десериализовать t он внешний тип A - если я вытащил внутреннее сериализованное значение для B и десериализую это, он отлично работает.

+0

Еще одна точка данных: класс B также имеет поле перечислимую, который имеет такое же имя как ссылка на 'B' в' A': 'public EnumType b'. Когда Джексон делает десериализацию внутреннего типа «B», он, похоже, запутывается и пытается десериализовать его как «A» –

ответ

2

Я понял, почему обычай десериализатор не работает: метод readValueAs потребляет {, которая вызывает исключение, оставляя } в качестве следующих маркеров. Это закрывает внутренний объект, и тогда синтаксический анализатор будет считать, что значение enum, которое встречается в следующий раз, должно анализироваться как внутренний тип, а не как тип перечисления.

Постараюсь это завтра, но я думаю, что путь этот, в deserialize метода:

ObjectMapper om = ...; 

JsonNode node = arg0.readValueAs(JsonNode.class); 
try 
{ 
    return om.readValue(node, new TypeReference<List<C>>(){}); 
} 
catch (JsonMappingException jme) 
{ 
} 
return null; 
+0

Выглядит хорошо. Если 'arg0.readValueAs (JsonNode.class)' не работает, вы можете попробовать с 'arg0.readValueAsTree()', который также возвращает JsonNode. – waxwing

+0

Yup, отлично работает. –

Смежные вопросы