2016-04-29 31 views
0

我一直在尝试将对象序列化为CSV String,但对象包含List@JsonUnwrappedList对象不起作用。如何正确序列化和反序列化CSV?

预期样品输出

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<Part> parts; 

    public String getColor() { 
     return color; 
    } 

    public void setColor(String color) { 
     this.color = color; 
    } 

    public List<Part> getParts() { 
     return parts; 
    } 

    public void setParts(List<Part> 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); 
} 

} 

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

对不起任何毫无意义的注释,如果你用代码回答,请随时删除它们。

+0

您使用CSV,而不是JSON的原因吗?据我所知,你在一辆车上有很多零件,而且我不认为CSV是最好的格式来表示 –

+0

我使用的是XML和JSON,但我需要能够代表它3种格式。另外两个已经正常工作了。 – Hooli

+0

@SotiriosDelimanolis:完成。基本上和数据库'JOIN'一样的概念。 – Hooli

回答

4

从错误,我愿意相信它有事情做与你的架构一个Car,其中有来自@JsonPropertyOrderCar而不是"name"值取的{"color"}列。

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

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

部分

这里,其他的一些变动之后,它需要有一个字符串值构造,所以添加

@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<Part>手动转换为CSV可读格式的方法。

这样的方法是这样的

@JsonGetter("parts") 
public String getPartString() { 
    String separator = ";"; 
    StringBuilder sb = new StringBuilder(); 

    Iterator<Part> 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<Part> parts; 

    public Car() { 
     this.parts = new ArrayList<>(); 
    } 

连载

你可以更改您的serialize方法以将类的类型作为泛型类型参数而不是显式的Class如此。

​​

主 - 作家

现在,如果你序列化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 
+0

延迟响应道歉。谢谢你澄清一切。对于任何正在查找可用的CSV序列化/反序列化解决方案的用户,我已提前发布完整的解决方案。 – Hooli

+0

欢迎。看起来你并没有看到我对serialize方法的评论 –

0

全部工作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<Part> parts; 

     public String getColor() { 
      return color; 
     } 

     public void setColor(String color) { 
      this.color = color; 
     } 

     public List<Part> getParts() { 
      return parts; 
     } 

     public void setParts(List<Part> parts) { 
      this.parts = parts; 
     } 

     public Car() { 
      this.parts = new ArrayList<>(); 
     } 

     @JsonGetter("parts") 
     public String getPartString() { 
      String separator = ";"; 
      StringBuilder sb = new StringBuilder(); 

      Iterator<Part> 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<Car> 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<Object> 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<Object> mappingIterator = csvMapper.readerFor(type).with(csvSchema).readValues(csv); 
     List<Object> objects = new ArrayList<>(); 
     while (mappingIterator.hasNext()) { 
      objects.add(mappingIterator.next()); 
     } 
     return objects; 
    } 

}