2016-04-29 33 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; 
    } 

}