【问题标题】:Get better parsing error with Jackson使用 Jackson 获得更好的解析错误
【发布时间】:2018-03-06 14:46:33
【问题描述】:

我正在解析一个相当大的文件,其中包含很多行和列。现在,有时我也会获得新数据,但有时也会出现错误。 double 突然变成 String 或任何其他类型更改的事情。当运行它这种解析错误时,Jackson 正在报告列、值和行,然后基本上停止解析过程。

我认为是com.fasterxml.jackson.core.JsonParseException

我想要达到的,就是

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

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

我找不到任何文档。如果有的话,我会很感激一个指针。

编辑:我认为是InvalidFormatException

【问题讨论】:

  • JSON 没有列的概念,因此不清楚您的意思是“错误/失败”。如果引号或括号是错误的,你不能跳过它
  • JSON 没有,但 Jackson 可以解析选项卡文件。我需要这些信息。
  • 当我说“错误/失败”时,我的意思是在我的 Java 模型中我有一个:public int zipCode 现在有一个错误行,我正在解析其中 zipCode 是字符串。
  • 我认为 Jackson CSV 解析器不会返回 JsonParseException
  • @cricket_007 这个问题似乎是关于错误message,而不是关于修复错误。

标签: java jackson


【解决方案1】:

假设您有一个语法有效 JSON 文档,您可以创建一个反序列化程序来忽略由于类型不匹配或类型转换导致的解析错误。该实现不需要处理反序列化本身,它可以从 Jackson API 委托给现有的反序列化器。这种方法首先在 answer 中进行了描述。

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

请参阅下面的自定义反序列化器可能是什么样的:

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

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

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

解析错误将被记录为:

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 

【讨论】:

  • 我认为这不是 OP 正在寻找的答案。问题不在于导致异常的原因,而在于即使出现异常如何继续
  • 这看起来更好。 @tschaka1904,您能检查一下更新后的答案是否满足您的要求吗?
  • 看起来不错!我认为现在有问题仍然在我身边!对于Sourceorg.glassfish.jersey.message.internal.ReaderInterceptorExec‌​utor$UnCloseableInpu‌​Stream,我似乎无法将其转换为字符串。这很烦人,但其余的都可以!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-17
相关资源
最近更新 更多