jackson-data-format-csv 读取csv文件——高级配置及原理解析

本文探讨如何使用Jackson的jackson-data-format-csv库解析CSV文件并转换为Java对象,重点介绍了schema的创建方式,包括基于POJO、手动构建和从文件头读取。同时,提到了列顺序的控制,以及解析结果可以是Map对象或Array的配置选项。另外,文章还指出了一种可能导致JSON输出无限循环的问题,并给出了相关应用实例链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

尝试使用jackson-data-format-csv解析csv文件,转换成Java对象,最终作为response body 以Json格式返回给用户,遇到几点问题:

第一:解析后字段顺序不对:

要解析csv文件,首先要定义以什么格式解析,即schema。

jackson csv library document 讲的很清楚,在这里定义schema有三种方式:

  • 基于一个Java类创建schema
    // Schema from POJO (usually has @JsonPropertyOrder annotation)
    CsvSchema schema = mapper.schemaFor(Pojo.class);

  • 在需要schema的时候通过手动添加每个列的方式build构建schema
    // Manually-built schema: one with type, others default to "STRING"
    CsvSchema schema = CsvSchema.builder()
            .addColumn("firstName")
            .addColumn("lastName")
            .addColumn("age", CsvSchema.ColumnType.NUMBER)
            .build();

  • 使用csv文件的第一行列名作为schema,(但这种方式就没办法定义每个字段的类型,只有个名字而已)
    // Read schema from the first line; start with bootstrap instance
    // to enable reading of schema from the first line
    // NOTE: reads schema and uses it for binding
    CsvSchema bootstrapSchema = CsvSchema.emptySchema().withHeader();
    ObjectMapper mapper = new CsvMapper();
    mapper.readerFor(Pojo.class).with(bootstrapSchema).readValue(json);
其中还特别强调了schema中列名顺序的问题。但值得一提的是:
如果使用第二种方式,可以手动修改addColumn的顺序从而决定解析结果与csv列序一致;
如果使用第三种方式,则不论怎样都能依据csv标题栏以正确顺序解析这个文件。
那么第一种情况下该怎样掌控正确的列解析顺序呢。
来看CsvMapper的构造方法:

public CsvMapper(CsvFactory f)
    {
        super(f);
        // As per #11: default to alphabetic ordering
        enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
        _untypedSchemas = new LRUMap<JavaType,CsvSchema>(8,32);
        _typedSchemas = new LRUMap<JavaType,CsvSchema>(8,32);
    }
而来看它究竟在实例化过程中enable了什么:
    /**
     * Feature that defines default property serialization order used
     * for POJO fields (note: does <b>not</b> apply to {@link java.util.Map}
     * serialization!):
     * if enabled, default ordering is alphabetic (similar to
     * how {@link com.fasterxml.jackson.annotation.JsonPropertyOrder#alphabetic()}
     * works); if disabled, order is unspecified (based on what JDK gives
     * us, which may be declaration order, but is not guaranteed).
     *<p>
     * Note that this is just the default behavior, and can be overridden by
     * explicit overrides in classes (for example with
     * {@link com.fasterxml.jackson.annotation.JsonPropertyOrder} annotation)
     *<p>
     * Feature is disabled by default.
     */
    SORT_PROPERTIES_ALPHABETICALLY(false),
因此,如果不强调解析顺序,默认情况下可能会根据创建schema的类内字段的alpha-beta顺序对应csv的列序;
这就解释了为什么我之前尝试解析的时候总是不能以自认为定义好的列序解析。
但这一情况不是不可更改的,可以在创建schema的类上注解

@JsonPropertyOrder({"id","name","description"})

通过这种方式可以定义解析时的列顺序。


有些帖子的例子上还有

CsvMapper mapper = new CsvMapper();
mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY);
的用法,根据document,其实给配置主要针对如何解析csv文件上的一行元素。

默认情况下会将csv的每一行解析成一个map对象,即一组key-value键值对序列;

但如果利用上面的配置enable了wrap_as_array,则csv的每一行都会被解析为一个array,就一行上的每个column元素都是array中的一个,也即不区分column之间的不同key值。

其实jackson csv还提供了很多配置属性;更多信息还是要查看源码或官方文档。

    第二:作为JSON输出时无限循环。

    这个问题主要出现于在定义schema的类中同时提供了读取csv文件返回该类为元素的list的解析结果的方法;

    解析的结果就变成了例如:

    {
        "StandardCodeList" : [
            "id":"xxxx",
            "name":"yyyy",
            "description":"this is an example",
            "StandardCodeList":[
                ....,
                "StandardCodeList":[
                    ....
                ]
            ]
        ]
    }
    这样的死循环。将getList的方法从schema定义类中剥离出来就解决这个问题了。

    更多应用实例详见:

    https://www.programcreek.com/java-api-examples/index.php?api=com.fasterxml.jackson.dataformat.csv.CsvMapper

    http://blog.youkuaiyun.com/doctor_who2004/article/details/50760622

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值