杰克逊反序列化错误处理

2022-09-02 01:16:56

我的问题相当简单:我有以下简单类:

public class Foo {
   private int id = -1;
   public void setId(int _id){ this.id = _id; }
   public int getId(){ return this.id; }
}

我正在尝试处理以下JSON:

{
  "id": "blah"
}

显然,这里有一个问题(“blah”不能解析为int)

以前,Jackson 抛出类似 org.codehaus.jackson.map.JsonMappingException: 无法从 String 值 'blah' 构造 java.lang.Integer 的实例:不是有效的 Integer 值

我同意这一点,但我想在某个地方注册一些东西,允许忽略这种类型的映射错误。我尝试使用已注册的反序列化问题Handler(请参阅此处),但它似乎仅适用于未知属性,而不适用于反序列化问题。

你对这个问题有什么线索吗?


答案 1

我成功地解决了我的问题,这要归功于Jackson ML的Tatu

我必须对 Jackson 中处理的每个基元类型使用自定义非阻塞反序列化器。像这个工厂这样的东西:

public class JacksonNonBlockingObjectMapperFactory {

    /**
     * Deserializer that won't block if value parsing doesn't match with target type
     * @param <T> Handled type
     */
    private static class NonBlockingDeserializer<T> extends JsonDeserializer<T> {
        private StdDeserializer<T> delegate;

        public NonBlockingDeserializer(StdDeserializer<T> _delegate){
            this.delegate = _delegate;
        }

        @Override
        public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            try {
                return delegate.deserialize(jp, ctxt);
            }catch (JsonMappingException e){
                // If a JSON Mapping occurs, simply returning null instead of blocking things
                return null;
            }
        }
    }

    private List<StdDeserializer> jsonDeserializers = new ArrayList<StdDeserializer>();

    public ObjectMapper createObjectMapper(){
        ObjectMapper objectMapper = new ObjectMapper();

        SimpleModule customJacksonModule = new SimpleModule("customJacksonModule", new Version(1, 0, 0, null));
        for(StdDeserializer jsonDeserializer : jsonDeserializers){
            // Wrapping given deserializers with NonBlockingDeserializer
            customJacksonModule.addDeserializer(jsonDeserializer.getValueClass(), new NonBlockingDeserializer(jsonDeserializer));
        }

        objectMapper.registerModule(customJacksonModule);
        return objectMapper;
    }

    public JacksonNonBlockingObjectMapperFactory setJsonDeserializers(List<StdDeserializer> _jsonDeserializers){
        this.jsonDeserializers = _jsonDeserializers;
        return this;
    }
}

然后像这样称呼它(只通过那些你想要不阻塞的人作为反序列化器):

JacksonNonBlockingObjectMapperFactory factory = new JacksonNonBlockingObjectMapperFactory();
factory.setJsonDeserializers(Arrays.asList(new StdDeserializer[]{
    // StdDeserializer, here, comes from Jackson (org.codehaus.jackson.map.deser.StdDeserializer)
    new StdDeserializer.ShortDeserializer(Short.class, null),
    new StdDeserializer.IntegerDeserializer(Integer.class, null),
    new StdDeserializer.CharacterDeserializer(Character.class, null),
    new StdDeserializer.LongDeserializer(Long.class, null),
    new StdDeserializer.FloatDeserializer(Float.class, null),
    new StdDeserializer.DoubleDeserializer(Double.class, null),
    new StdDeserializer.NumberDeserializer(),
    new StdDeserializer.BigDecimalDeserializer(),
    new StdDeserializer.BigIntegerDeserializer(),
    new StdDeserializer.CalendarDeserializer()
}));
ObjectMapper om = factory.createObjectMapper();

答案 2

您可能希望通过添加处理此特定异常的方法让控制器处理问题

@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseBody
public String handleHttpMessageNotReadableException(HttpMessageNotReadableException ex)
{
    JsonMappingException jme = (JsonMappingException) ex.getCause();
    return jme.getPath().get(0).getFieldName() + " invalid";
}

当然,线

    JsonMappingException jme = (JsonMappingException) ex.getCause();

在某些情况下可能会抛出类转换异常,但我还没有遇到它们。