如何正确序列化和反序列化CSV?

我一直在尝试将对象序列化为CSV String但该对象包含List@JsonUnwrappedList对象不起作用。

预期样本输出

 color,part.name\n red,gearbox\n red,door\n red,bumper 

实际产量

 com.fasterxml.jackson.core.JsonGenerationException: Unrecognized column 'name': 

这是我的代码 :(大部分是2 POJO)

 import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonRootName; import com.fasterxml.jackson.dataformat.csv.CsvMapper; import com.fasterxml.jackson.dataformat.csv.CsvSchema; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import java.io.IOException; import static java.util.Arrays.asList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; public class NestedWrapping { @JsonRootName("Car") @JsonInclude(JsonInclude.Include.NON_DEFAULT) @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) @JsonPropertyOrder({"color"}) public static class Car { @JsonProperty("color") private String color; @JsonFormat(shape = JsonFormat.Shape.STRING) @JacksonXmlElementWrapper(useWrapping = false) private List parts; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public List getParts() { return parts; } public void setParts(List parts) { this.parts = parts; } } @JsonInclude(JsonInclude.Include.NON_DEFAULT) @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) @JsonPropertyOrder({ "name" }) public static class Part { @JsonProperty("name") private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public static void main(String args[]) { try { Car car = new Car(); car.setColor("red"); Part part1 = new Part(); part1.setName("geabox"); Part part2 = new Part(); part2.setName("door"); Part part3 = new Part(); part3.setName("bumper"); car.setParts(asList(part1, part2, part3)); System.out.println("serialized: " + serialize(car, Car.class, true)); } catch (IOException ex) { Logger.getLogger(NestedWrapping.class.getName()).log(Level.SEVERE, null, ex); } } public static final synchronized String serialize(final Object object, final Class type, final Boolean withHeaders) throws IOException { CsvMapper csvMapper = new CsvMapper(); CsvSchema csvSchema; if (withHeaders) { csvSchema = csvMapper.schemaFor(type).withHeader(); } else { csvSchema = csvMapper.schemaFor(type).withoutHeader(); } return csvMapper.writer(csvSchema).writeValueAsString(object); } } 

我没有尝试似乎工作,我已阅读stackoverflow和github关于该主题的每篇文章 ,但我找不到一个有效的解决方案。

对于我无缘无故地留下的任何无意义的注释感到抱歉,如果您使用代码回答,请随时删除它们。

从错误中,我想相信它与您的Car架构有关,它的Car {"color"}列取自@JsonPropertyOrder上的@JsonPropertyOrder而不是"name"值。

您可能希望在其中添加"parts" ,但是您会得到"name"不属于该架构的相同错误。

在对代码进行一些更改后,我能够序列化和反序列化Car对象。

部分

在这里,经过一些其他更改后,它需要一个具有单个String值的构造函数,所以添加它

 @JsonPropertyOrder({"name"}) public static class Part { @JsonProperty("name") private String name; public Part() { this(""); } public Part(String partJSON) { // TODO: Unserialize the parameter... it is a serialized Part string... this.name = partJSON; } 

汽车

在这里,您需要实现一种方法,将List手动转换为CSV可读格式。

这样的方法看起来像这样

 @JsonGetter("parts") public String getPartString() { String separator = ";"; StringBuilder sb = new StringBuilder(); Iterator iter = this.parts.iterator(); while (iter.hasNext()) { Part p = iter.next(); sb.append(p.getName()); if (iter.hasNext()) sb.append(separator); } return sb.toString(); } 

另外,不要忘记将模式修复到类的顶部

 @JsonPropertyOrder({"color", "parts"}) public static class Car { @JsonProperty("color") private String color; @JsonProperty("parts") private List parts; public Car() { this.parts = new ArrayList<>(); } 

连载

您可以更改serialize方法,将类的类型作为generics类型参数,而不是像这样的显式Class

 public static final synchronized  String serialize(final T object, final Boolean withHeaders) throws IOException { CsvMapper csvMapper = new CsvMapper(); CsvSchema csvSchema = csvMapper.schemaFor(object.getClass()); if (withHeaders) { csvSchema = csvSchema.withHeader(); } else { csvSchema = csvSchema.withoutHeader(); } return csvMapper.writer(csvSchema).writeValueAsString(object); } 

主要作家

现在,如果您序列化Car ,您应该看到

 color,parts red,gearbox;door;bumper 

主要读者

读取CSV字符串并循环遍历Car.getParts()

 Car car = mapper.readerFor(Car.class).with(csvSchema).readValue(csv); for (Part p : car.getParts()) { System.out.println(p.getName()); } 
 gearbox door bumper 

完整的CSV 序列化 序列 解决方案:

 import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.databind.MappingIterator; import com.fasterxml.jackson.dataformat.csv.CsvMapper; import com.fasterxml.jackson.dataformat.csv.CsvSchema; import java.io.IOException; import java.util.ArrayList; import static java.util.Arrays.asList; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; public class NestedWrapping { @JsonPropertyOrder({"color", "parts"}) public static class Car { @JsonProperty("color") private String color; @JsonProperty("parts") private List parts; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public List getParts() { return parts; } public void setParts(List parts) { this.parts = parts; } public Car() { this.parts = new ArrayList<>(); } @JsonGetter("parts") public String getPartString() { String separator = ";"; StringBuilder sb = new StringBuilder(); Iterator iter = this.parts.iterator(); while (iter.hasNext()) { Part p = iter.next(); sb.append(p.getName()); if (iter.hasNext()) { sb.append(separator); } } return sb.toString(); } @Override public String toString() { return "Car{" + "color=" + color + ", parts=" + parts + '}'; } } @JsonPropertyOrder({ "name" }) public static class Part { @JsonProperty("name") private String name; public Part() { } public Part(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Part{" + "name=" + name + '}'; } } public static void main(String args[]) { try { Car car = new Car(); car.setColor("red"); Part part1 = new Part(); part1.setName("geabox"); Part part2 = new Part(); part2.setName("door"); Part part3 = new Part(); part3.setName("bumper"); car.setParts(asList(part1, part2, part3)); String serialized = serialize(car, Car.class, true); System.out.println("serialized: " + serialized); List deserializedCars = (List) deserialize(serialized, Car.class, true); for (Car deserializedCar : deserializedCars) { System.out.println("deserialized: " + deserializedCar.toString()); } } catch (IOException ex) { Logger.getLogger(NestedWrapping.class.getName()).log(Level.SEVERE, null, ex); } } public static final synchronized String serialize(final Object object, final Class type, final Boolean withHeaders) throws IOException { CsvMapper csvMapper = new CsvMapper(); CsvSchema csvSchema; if (withHeaders) { csvSchema = csvMapper.schemaFor(type).withHeader(); } else { csvSchema = csvMapper.schemaFor(type).withoutHeader(); } return csvMapper.writer(csvSchema).writeValueAsString(object); } public static final synchronized List deserialize(final String csv, final Class type, final Boolean hasHeaders) throws IOException { CsvMapper csvMapper = new CsvMapper(); CsvSchema csvSchema; if (hasHeaders) { csvSchema = csvMapper.schemaFor(type).withHeader(); } else { csvSchema = csvMapper.schemaFor(type).withoutHeader(); } MappingIterator mappingIterator = csvMapper.readerFor(type).with(csvSchema).readValues(csv); List objects = new ArrayList<>(); while (mappingIterator.hasNext()) { objects.add(mappingIterator.next()); } return objects; } }