如何正确序列化和反序列化CSV?
我一直在尝试将对象序列化为CSV String
但该对象包含List
而@JsonUnwrapped
对List
对象不起作用。
预期样本输出 :
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