如何配置Jackson CSV反序列化:忽略下划线开头属性,其余未知属性报错?
问题
我有一个Java对象,正使用jackson-dataformat-csv从CSV格式反序列化,相关代码如下:
public record MyType(String myString, Integer myInt) {}
private List<MyType> readFile(Path file) throws IOException { CsvMapper mapper = CsvMapper.csvBuilder().build(); CsvSchema schema = CsvSchema.emptySchema().withHeader(); ObjectReader objectReader = mapper.readerFor(MyType.class).with(schema); try (MappingIterator<MyType> iterator = objectReader.readValues(file.toFile())) { return iterator.readAll(); } }
标准CSV示例:
myString,myInt A,1 B,2 C,3
需求是:反序列化时,若发现非下划线开头的未知属性则报错,避免因拼写错误导致应赋值的属性被设为null;同时允许CSV中包含以下划线开头的可选额外列(如_description、_notes),示例CSV如下:
myString,myInt,_description,_notes A,1,Apple, B,2,Ball,Only used in legacy data C,3,Cat,Not used yet
要求不修改Java类注解(CSV反序列化是该对象的小众用法),实现上述配置。
解决方案
可以通过先过滤CSV表头、再配合Jackson反序列化特性来实现需求,具体步骤如下:
- 开启Jackson的
FAIL_ON_UNKNOWN_PROPERTIES特性,确保非预期的未知属性会触发报错 - 提前读取CSV的表头,过滤掉所有以下划线开头的列
- 使用过滤后的表头构建
CsvSchema,让Jackson只处理这些合法列,自动忽略下划线开头的列
完整实现代码
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.MappingIterator; import com.fasterxml.jackson.dataformat.csv.CsvMapper; import com.fasterxml.jackson.dataformat.csv.CsvSchema; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CsvReader { public record MyType(String myString, Integer myInt) {} private List<MyType> readFile(Path file) throws IOException { // 配置Mapper:开启未知属性报错 CsvMapper mapper = CsvMapper.csvBuilder() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true) .build(); // 读取表头并过滤下划线开头的列 List<String> filteredHeaders; try (BufferedReader reader = Files.newBufferedReader(file)) { String headerLine = reader.readLine(); if (headerLine == null) { return Collections.emptyList(); } filteredHeaders = Arrays.stream(headerLine.split(",")) .filter(columnName -> !columnName.startsWith("_")) .toList(); } // 用过滤后的表头构建Schema CsvSchema.Builder schemaBuilder = CsvSchema.builder(); filteredHeaders.forEach(schemaBuilder::addColumn); CsvSchema schema = schemaBuilder.build(); // 创建ObjectReader并读取数据 ObjectReader objectReader = mapper.readerFor(MyType.class).with(schema); try (MappingIterator<MyType> iterator = objectReader.readValues(file.toFile())) { return iterator.readAll(); } } }
效果说明
- 当下划线开头的列存在时:会被过滤掉,Jackson不会尝试反序列化这些列,不影响正常属性的赋值
- 当出现非下划线开头的未知列(比如拼写错误的
myStrng):Jackson会抛出UnrecognizedPropertyException,及时发现拼写错误问题 - 不需要修改
MyType实体类的任何注解,完全通过代码配置实现需求
内容的提问来源于stack exchange,提问作者M. Justin
相关产品推荐
相关产品推荐

