jackson-dataformat-csv 不会忽略未知属性

jackson-dataformat-csv does not ignore unknown properties

正在尝试使用 jackson-dataformat-csv 解析 .csv 文件。文件包含许多与我的程序无关的列。

尝试对我的数据 class 使用 @JsonIgnoreProperties(ignoreUnknown = true), 和 csvMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES),但都不起作用,应用程序抛出异常:

com.fasterxml.jackson.databind.RuntimeJsonMappingException: Too many entries: expected at most 2 (value #2 (17 chars) "policy_issue_date")
 at [Source: (com.fasterxml.jackson.dataformat.csv.impl.UTF8Reader); line: 1, column: 37]

    at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:194)
    at pl.polins.readers.oc.OcPolicyCsvReader.readNext(OcPolicyCsvReader.kt:25)
    at pl.polins.readers.oc.OcPolicyCsvReaderTest.should read PolicyCsv from .csv file(OcPolicyCsvReaderTest.groovy:19)
Caused by: com.fasterxml.jackson.dataformat.csv.CsvMappingException: Too many entries: expected at most 2 (value #2 (17 chars) "policy_issue_date")
 at [Source: (com.fasterxml.jackson.dataformat.csv.impl.UTF8Reader); line: 1, column: 37]
    at com.fasterxml.jackson.dataformat.csv.CsvMappingException.from(CsvMappingException.java:23)
    at com.fasterxml.jackson.dataformat.csv.CsvParser._reportCsvMappingError(CsvParser.java:1210)
    at com.fasterxml.jackson.dataformat.csv.CsvParser._handleExtraColumn(CsvParser.java:965)
    at com.fasterxml.jackson.dataformat.csv.CsvParser._handleNextEntry(CsvParser.java:826)
    at com.fasterxml.jackson.dataformat.csv.CsvParser.nextToken(CsvParser.java:580)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:418)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1266)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:325)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.MappingIterator.nextValue(MappingIterator.java:277)
    at com.fasterxml.jackson.databind.MappingIterator.next(MappingIterator.java:192)
    ... 2 more

是否有任何解决方案可以忽略 csv 中不需要的列?

找到解决方案:

csvMapper.enable(CsvParser.Feature.IGNORE_TRAILING_UNMAPPABLE)

这对我有用:

csvMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

简介

为了便于理解,这里有一个简单的 (Java) 示例:

  1. 从 InputStream 读取 CSV 文件 (jackson-dataformat-csv 依赖)

  2. 将其内容映射到对象列表(jackson-core 依赖项)

CSV 文件内容

data.csv 一个包含以下数据的 CSV 文件:

a;b;c
1;2;0.5
3;4;

Java Class 缺少属性的数据

classMyModel表示一个数据class具有以下属性:

private Long a;
private Integer b;

请注意缺少属性 c,因此解析器将不得不忽略它。

读取CSV内容并映射到对象列表

所以CsvMapper可以配合Jackson对象映射器从CSV文件读取记录到对象列表,整个方法很方便:

<U> List<U> mapRecordsToObjects(InputStream inputStream, Class<U> encodingType) {
    CsvMapper csvMapper = new CsvMapper();
    CsvSchema bootstrapSchema = CsvSchema.emptySchema() //
                                         .withHeader() //
                                         .withColumnSeparator(";");
    ObjectReader reader = csvMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) //
                                   .readerFor(encodingType) //
                                   .with(bootstrapSchema);
    MappingIterator<U> iterator;
    try {
        iterator = reader.readValues(inputStream);
    } catch (IOException e) {
        throw new IllegalStateException(String.format("could not access file [%s]", this.source), e);
    }
    List<U> results = new ArrayList<>();
    iterator.forEachRemaining(results::add);
    return results;
}

最后,让我们调用这个方法:

List<MyModel> result = mapRecordsToObjects(fileInputStream, MyModel.class);

为了读取文件,您只需要初始化 InputStream。

反序列化功能

documentation中,classDeserializationFeature有如下描述:

Enumeration that defines simple on/off features that affect the way Java objects are deserialized from JSON

在此枚举中 class,有许多功能具有默认状态(有时默认启用,有时禁用)。功能 FAIL_ON_UNKOWN_PROPERTIES 默认为 禁用 可以启用,如示例所示。在其描述中,可以看到:

Feature that determines whether encountering of unknown properties (ones that do not map to a property, and there is no "any setter" or handler that can handle it) should result in a failure (by throwing a {@link JsonMappingException}) or not.