与杰克逊一起获得更好的解析错误

tsc*_*904 1 java jackson

我正在解析一个相当大的文件,有很多行和列.现在,有时候我也会得到新的数据,有时也会出错.double突然发生的事情String或任何其他类型的变化.当运行这种解析错误时,Jackson会报告列,值和行,然后基本上停止解析过程.

我认为这是一个com.fasterxml.jackson.core.JsonParseException.

我想要实现的是,那就是

  1. 报告整行,例如第27列有问题,但要轻松跟踪它,我需要列第1列,因为它带有数据集的标识符.

  2. 能够跳过失败的列并继续解析过程而忽略/仅报告错误列.

我找不到任何相关的文档.如果有的话,我会很感激指针.

编辑:我认为这是一个InvalidFormatException

cas*_*lin 6

假设您有一个语法上有效的 JSON文档,您可以创建一个反序列化器来忽略由于类型不匹配或类型转换而导致的解析错误.实现不需要处理deserilization本身,它可以委托Jackson API的现有解串器.这个方法首先在这个答案中描述.

对于错误报告,您可以捕获a JsonProcessingException,检查特定子类型,然后从异常API获取一些详细信息.根据您的需要,API JsonParserDeserializationContextAPI可以为您提供日志的其他详细信息.

请参阅下面的自定义反序列化程序:

public class NonBlockingDeserializer<T> extends JsonDeserializer<T> {

    private static final Logger LOGGER = Logger.getLogger(NonBlockingDeserializer.class.getName());

    private StdDeserializer<T> delegate;

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

    @Override
    public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {

        try {

            // Delegate the deserialization
            return delegate.deserialize(jp, ctxt);

        } catch (JsonProcessingException e) {

            // Log the exception
            logException(e);

            // Return default null value
            return delegate.getNullValue(ctxt);
        }
    }

    private void logException(JsonProcessingException e) {

        StringBuilder builder = new StringBuilder(e.getOriginalMessage() + System.lineSeparator());

        builder.append(String.format("Source: %s \n", e.getLocation().getSourceRef()));
        builder.append(String.format("Line: %s \n", e.getLocation().getLineNr()));
        builder.append(String.format("Column: %s \n", e.getLocation().getColumnNr()));

        if (e instanceof InvalidFormatException) {

            InvalidFormatException e1 = (InvalidFormatException) e;
            builder.append(String.format("Value: %s \n", e1.getValue()));
            builder.append(String.format("Value type: %s \n", e1.getValue().getClass().getTypeName()));
            builder.append(String.format("Target type: %s \n", e1.getTargetType().getTypeName()));

        } else if (e instanceof UnrecognizedPropertyException) {

            UnrecognizedPropertyException e1 = (UnrecognizedPropertyException) e;
            builder.append(String.format("Property name: %s \n", e1.getPropertyName()));
            builder.append(String.format("Known properties: %s \n", e1.getKnownPropertyIds()));

        }

        LOGGER.warning(builder.toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

然后按如下所示使用它,为要忽略错误的类型添加反序列化器:

// Create module for custom deserializers
SimpleModule module = new SimpleModule("customDeserializers", Version.unknownVersion());

// Add deserializers for primitive types
module.addDeserializer(Double.TYPE,   new NonBlockingDeserializer<Double>(
                                      new NumberDeserializers.DoubleDeserializer(Double.TYPE, 0.d)));
module.addDeserializer(Integer.TYPE,  new NonBlockingDeserializer<Integer>(
                                      new NumberDeserializers.IntegerDeserializer(Integer.TYPE, 0)));

// Add deserializers for wrapper classes
module.addDeserializer(Double.class,  new NonBlockingDeserializer<Double>(
                                      new NumberDeserializers.DoubleDeserializer(Double.class, null)));
module.addDeserializer(Integer.class, new NonBlockingDeserializer<Integer>(
                                      new NumberDeserializers.IntegerDeserializer(Integer.class, null)));

// Create ObjectMapper and register module
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);

// Perform the deserialization as usual
Foo foo = mapper.readValue(json, Foo.class);
Run Code Online (Sandbox Code Playgroud)

解析错误将记录如下:

Mar 11, 2018 10:45:33 AM org.example.playground.NonBlockingDeserializer logException
WARNING: Cannot deserialize value of type `java.lang.Integer` from String "18a": not a valid Integer value
Source: {"name": "Joe", "age": "18a"} 
Line: 1 
Column: 24 
Value: 18a 
Value type: java.lang.String 
Target type: java.lang.Integer 
Run Code Online (Sandbox Code Playgroud)