2017-02-10 4 views
0

У меня проблема с неправильными объектами в списках. Например, я имею в JSON модель:Пользовательский десериализатор для любого списка в Jackson

{ 
    "items": [ 
    { 
     "id": 1, 
     "name": "Item1" 
    }, 
    { 
     "id": 2, 
     "name": "Item2" 
    }, 
    { 
     "id": [], 
     "name": "Item3" 
    } 
    ] 
} 

и два POJO

data class BadList(val items: List<BadItem>) 

data class BadItem(val id: Int, val name: String) 

Конечно, когда анализатор натыкается на третий элемент я получаю исключение

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.Integer out of START_ARRAY token 
at [Source: {"items":[{"id":1,"name":"Item1"},{"id":2,"name":"Item2"},{"id":[],"name":"Item3"}]}; line: 1, column: 19] (through reference chain: my.package.BadList["items"]->java.util.ArrayList[2]->my.package.BadItem["id"]) 

Кто знает, как обойти это? Я хочу пропустить этот неправильный элемент.

+0

Что вы хотите сделать? – shmosel

+0

@shmosel Я хочу пропустить этот неправильный элемент – 0wl

ответ

0

Вы можете написать пользовательские deserializer и реализовать десериализации логика в нем, например:

class ItemIdDeserialiser extends JsonDeserializer<Integer> { 

    @Override 
    public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
     Object value = p.getCurrentValue(); 
     //Check if it's Integer 
     if(value instanceof Integer){ 
      return (Integer) value; 
     } 
     return null; //Or return first element if it's a non empty list 
    } 
} 

Как только это будет сделано, вы можете аннотировать поле с @JsonDeserialise поручить Джексон использовать свой класс, например:

class Item { 

    @JsonDeserialize(using = ItemIdDeserialiser.class) 
    private Integer id; 
} 

Update

Если вы просто хотите, чтобы игнорировать поле в сериализации/десериализации, вы можете аннотировать его с помощью @JsonIgnore, например.

class Item { 

     @JsonIgnore 
     private Integer id; 
    } 

Или еще лучше, удалить id из POJO и добавить @JsonIgnoreProperties на классе, например .:

@JsonIgnoreProperties(ignoreUnknown = true) 
class Item { 

} 

Он будет автоматически игнорировать свойства, которые присутствуют в json, но не нашел в своем классе.

+0

Прошу прощения, но ваше решение слишком локальное. Я хочу получить возможность пропуска таких элементов, потому что другие поля также могут быть неверными. – 0wl

+0

Ну, в этом вопросе нигде не упоминается «пропуская» часть. В любом случае, если вы просто хотите пропустить элемент, то почему бы вам не использовать '@ JsonIgnore' –

+0

Можете ли вы показать пример? – 0wl

0

Вы можете использовать "HidableSerializer" для этого и проверки данных во время сериализации

1. Создайте интерфейс IHidable

Интерфейс имеет IsHidden метод, который называется в процессе сериализации

package ch.hasselba.jackson.test; 

public interface IHidable { 
    public boolean isHidden(); 
} 

2. Измените свой BadItem класс

Добавьте интерфейс и изменить сеттер ид. Когда свойство id десериализуется, оно проверяется, если оно целое. Если нет, элемент отмечен как плохой.

package ch.hasselba.jackson.test; 

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 

@JsonIgnoreProperties({"hidden"}) 
public class BadItem implements IHidable{ 
    private Integer id; 
    public String name; 
    private boolean isBadItem; 
    public Integer getId(){ 
     return id; 
    } 
    public void setId(Object value){ 
     if(value instanceof Integer){ 
      this.id = (Integer) value; 
     }else{ 
      this.isBadItem = true; 
     } 
    } 
    public boolean isHidden() { 
     return isBadItem; 
    } 
} 

3. Создать HidableSerializer

package ch.hasselba.jackson.test; 

import java.io.IOException; 

import com.fasterxml.jackson.core.JsonGenerator; 
import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.JsonSerializer; 
import com.fasterxml.jackson.databind.SerializerProvider; 
import com.fasterxml.jackson.databind.ser.std.StdSerializer; 


@SuppressWarnings("serial") 
public class HidableSerializer<T> extends StdSerializer<T> { 

    private JsonSerializer<T> defaultSerializer; 

    protected HidableSerializer(Class<T> t) { 
     super(t); 
    } 

    public JsonSerializer<T> getDefaultSerializer() { 
     return defaultSerializer; 
    } 

    public void setDefaultSerializer(JsonSerializer<T> defaultSerializer) { 
     this.defaultSerializer = defaultSerializer; 
    } 

    @Override 
    public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) 
      throws IOException, JsonProcessingException { 

     if(value instanceof IHidable){ 
      IHidable hidableValue = (IHidable) value; 
      if(hidableValue.isHidden()) 
       return; 
     } 

     defaultSerializer.serialize(value, jgen, provider); 
    } 

} 

4.Зарегистрируйте HidableSerializer и это его

package ch.hasselba.jackson.test; 

import com.fasterxml.jackson.annotation.JsonInclude.Include; 
import com.fasterxml.jackson.databind.BeanDescription; 
import com.fasterxml.jackson.databind.JsonSerializer; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.SerializationConfig; 
import com.fasterxml.jackson.databind.module.SimpleModule; 
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; 

public class Demo { 

    @SuppressWarnings("serial") 
    public static void main(String[] args) { 

     // register the HidableSerializer 
     ObjectMapper mapper = new ObjectMapper(); 
     mapper.setSerializationInclusion(Include.NON_EMPTY); 
     mapper.registerModule(new SimpleModule() { 
      @Override 
      public void setupModule(SetupContext context) { 
       super.setupModule(context); 
       context.addBeanSerializerModifier(new BeanSerializerModifier() { 
        @Override 
        public JsonSerializer<?> modifySerializer(
         SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) { 
         if (BadItem.class.isAssignableFrom(desc.getBeanClass())) { 
          HidableSerializer ser = new HidableSerializer(BadItem.class); 
          ser.setDefaultSerializer(serializer); 
          return ser; 
         } 
         return serializer; 
        } 
       }); 
      } 
     }); 

     String content = "{ \"items\": [ {  \"id\": 1,  \"name\": \"Item1\" }, {  \"id\": 2,  \"name\": \"Item2\" }, {  \"id\":[],  \"name\": \"Item3\" } ]}"; 

     // build the Object 
     BadList test = null; 
     try { 
      test = mapper.readValue(content, BadList.class); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     // and now convert it back to a String 
     String data = null; 
     try { 
      data = mapper.writeValueAsString(test); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     // print the result 
     System.out.println(data); 
    } 

} 

При изменении идентификатора «[]» в значение Integer отображается Item, в противном случае она пуста.

Результат:

{"items":[{"id":1,"name":"Item1"},{"id":2,"name":"Item2"}]}