java - 复合类的 Jackson CSV 建模器

标签 java csv jackson

将 Person 和 Address 类视为:

class Person {

    String name;
    int age;
    Address first;
    Address second;
}

class Address {

    String country;
    String city;

}

我想将 csv 文件解析为 Person 对象。示例 csv 文件为:

NAME,AGE,COUNTERY_1,CITY_1,COUNTRY_2,CITY_2
john,50,USA,Arizona,UK,London
bob,27,France,paris,USA,Felorida

我写了一个模型方法:

CsvSchema bootstrapSchema = CsvSchema.emptySchema().withHeader();
CsvMapper mapper = new CsvMapper();
MappingIterator<Person> readValues = mapper
            .readerWithTypedSchemaFor(Person.class)
            .with(bootstrapSchema)
            .readValues(file);
return readValues.readAll();

如何向映射器添加地址类映射?

最佳答案

你不能真正对 jackson 做到这一点,但是 univocity-parsers可以使用其 @Nested 注释:

首先定义您的 Address 类,如下所示:

public static class Address {
    @Parsed
    String country;
    @Parsed
    String city;

    @Override
    public String toString() {
        return "Address{country='" + country + '\'' + ", city='" + city + '\'' + '}';
    }
}

现在,如果您查看输入,我们需要以某种方式将 header “country_1”和“city_1”与您的 Address 类中的字段关联起来。这是使用自定义 HeaderTransformer 类将索引附加到 header 名称来完成的。让我们这样定义它:

public static class SuffixAppender extends HeaderTransformer {

    private String suffix;

    public SuffixAppender(String... args) {
        suffix = args[0];
    }

    @Override
    public String transformName(Field field, String name) {
        return name + "_" + suffix;
    }
}

现在您可以使用嵌套的 Address 属性定义您的 Person 类:

public static class Person {
    @Parsed
    String name;

    @Parsed
    int age;

    @Nested(headerTransformer = SuffixAppender.class, args = "1")
    Address first;

    @Nested(headerTransformer = SuffixAppender.class, args = "2")
    Address second;

    @Override
    public String toString() {
        return "Person{name='" + name + '\'' + ", age=" + age + ", first=" + first + ", second=" + second + '}';
    }
}

上面的内容指示解析器获取 Address 中的字段名称,并使用 SuffixAppender 将给定的后缀附加到它。结果将与您输入的标题进行匹配。

最后你就可以解析了。使用解析器的方法有很多种,但最简单的是:

String input = "" +
        "NAME,AGE,COUNTRY_1,CITY_1,COUNTRY_2,CITY_2\n" +
        "john,50,USA,Arizona,UK,London\n" +
        "bob,27,France,paris,USA,Florida";

CsvParserSettings settings = new CsvParserSettings(); //configure the parser
settings.detectFormatAutomatically(); //detects line separators and delimiters

//parse the input with the settings above, into a list of Person objects    
List<Person> personList = new CsvRoutines(settings).parseAll(Person.class, new StringReader(input));

让我们看看结果:

Person person1 = personList.get(0);
Person person2 = personList.get(1);
System.out.println(person1);
System.out.println(person2);

输出:

Person{name='john', age=50, first=Address{country='USA', city='Arizona'}, second=Address{country='UK', city='London'}}
Person{name='bob', age=27, first=Address{country='France', city='paris'}, second=Address{country='USA', city='Florida'}}

希望有帮助。

免责声明:我是这个库的作者。它是开源且免费的(Apache 2.0 许可证)

关于java - 复合类的 Jackson CSV 建模器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47966374/

相关文章:

azure - ADF 复制数据事件在 CSV 中创建多行

java - 使用 CrudRepository 进行延迟加载

java - Jackson - 使用 self 引用序列化实体

java - 添加第二个节点后 Cassandra 中的持续超时

file - 在 Golang 中记录和查找 CSV 文件位置

java - 在单元测试中启动新的 JVM

excel - 有没有办法从 CSV 中获取行而不加载整个文件?

java - 如何使用 Java 和 Jackson 库反序列化 Json 字符串以获得多态结果?

java - 在类中声明方法的首选方式

java - 单击按钮停止 Java 中正在进行的进程(线程)