【问题标题】:Custom deserializer for any list in Jackson杰克逊中任何列表的自定义反序列化器
【发布时间】:2017-02-10 22:01:01
【问题描述】:

我对列表中的错误对象有疑问。例如我有一个 JSON 模型:

{
  "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"])

谁知道如何解决这个问题?我想跳过那个错误的项目。

【问题讨论】:

  • 你想让它做什么?
  • @shmosel 我想跳过那个错误的项目

标签: java json jackson kotlin


【解决方案1】:

您可以编写一个自定义的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 注释该字段以指示 jackson 使用您的类,例如:

class Item {

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

更新

如果您只想忽略序列化/反序列化中的字段,则可以使用@JsonIgnore 对其进行注释,例如

class Item {

        @JsonIgnore
        private Integer id;
    }

或者更好的是,从 pojo 中删除 id 并在类中添加 @JsonIgnoreProperties,例如:

@JsonIgnoreProperties(ignoreUnknown = true)
class Item {

}

它会自动忽略 json 中存在但在类中找不到的属性。

【讨论】:

  • 很抱歉,您的决定过于本地化。我想获得跳过这些元素的能力,因为其他字段也可能不正确。
  • 好吧,问题没有提到skipping 部分。无论如何,如果您只想跳过该元素,那么为什么不使用@JsonIgnore
  • 它不适合我。如果它的任何字段是错误的,我想忽略整个元素。
  • @0wl 如果任何字段为null,您可以简单地从BadList 中删除BadItem
  • @SergeyVoitovich 不幸的是,我的问题与“null”无关。请仔细阅读我的问题。
【解决方案2】:

您可以为此使用 "HidableSerializer" 并在序列化期间检查数据

1.创建一个IHidable界面

接口有一个isHidden方法,在序列化过程中被调用

package ch.hasselba.jackson.test;

public interface IHidable {
    public boolean isHidden();
}

2。更改您的 BadItem

添加接口并更改id的setter。当属性 id 被反序列化时,会测试它是否为 Integer。如果不是,则该项目被标记为坏。

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

}

将id“[]”改为Integer值时,显示Item,否则为空。

结果:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-11
    • 2014-01-31
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 2017-04-21
    相关资源
    最近更新 更多