How to Serialize Object to CSV File

How to serialize object to CSV file?

First, serialization is writing the object to a file 'as it is'. AFAIK, you cannot choose file formats and all. The serialized object (in a file) has its own 'file format'

If you want to write the contents of an object (or a list of objects) to a CSV file, you can do it yourself, it should not be complex.

Looks like Java CSV Library can do this, but I have not tried this myself.

EDIT: See following sample. This is by no way foolproof, but you can build on this.

    //European countries use ";" as 
//CSV separator because "," is their digit separator
private static final String CSV_SEPARATOR = ",";
private static void writeToCSV(ArrayList<Product> productList)
{
try
{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("products.csv"), "UTF-8"));
for (Product product : productList)
{
StringBuffer oneLine = new StringBuffer();
oneLine.append(product.getId() <=0 ? "" : product.getId());
oneLine.append(CSV_SEPARATOR);
oneLine.append(product.getName().trim().length() == 0? "" : product.getName());
oneLine.append(CSV_SEPARATOR);
oneLine.append(product.getCostPrice() < 0 ? "" : product.getCostPrice());
oneLine.append(CSV_SEPARATOR);
oneLine.append(product.isVatApplicable() ? "Yes" : "No");
bw.write(oneLine.toString());
bw.newLine();
}
bw.flush();
bw.close();
}
catch (UnsupportedEncodingException e) {}
catch (FileNotFoundException e){}
catch (IOException e){}
}

This is product (getters and setters hidden for readability):

class Product
{
private long id;
private String name;
private double costPrice;
private boolean vatApplicable;
}

And this is how I tested:

public static void main(String[] args)
{
ArrayList<Product> productList = new ArrayList<Product>();
productList.add(new Product(1, "Pen", 2.00, false));
productList.add(new Product(2, "TV", 300, true));
productList.add(new Product(3, "iPhone", 500, true));
writeToCSV(productList);
}

Hope this helps.

Cheers.

Serialize and Deserialize CSV file as Stream

You are getting this error because the serializer does not know how to instantiate your FileParameter class. It prefers to use a default constructor if possible. It can use a parameterized constructor in some cases, if you give it a hint as to which one by marking it with a [JsonConstructor] attribute and all the constructor parameters match up to properties in the JSON object. However, that won't work in your case because all of your constructors expect a Stream and you require special handling for that.

To solve this you need a way for the serializer to instantiate your class without the stream and then use the converter to create the stream. You said you tried adding a default constructor, but then the stream was null. The reason it did not work is because all of your setters are private. With the default constructor, the serializer was able to instantiate the FileParameter, but then it could not populate it.

There are a couple of ways to make it work.

Solution 1 - modify the FileParameter class

  1. Add a default constructor to the FileParameter class as you did before. It can be private if you also mark it with [JsonConstructor].
  2. Add [JsonProperty] attributes to all of the private-set properties that need to be populated from the JSON. This will allow the serializer to write to the properties even though they are private.

So your class would look like this:

public partial class FileParameter
{
public FileParameter(System.IO.Stream data)
: this(data, null)
{
}

public FileParameter(System.IO.Stream data, string fileName)
: this(data, fileName, null)
{
}

public FileParameter(System.IO.Stream data, string fileName, string contentType)
{
Data = data;
FileName = fileName;
ContentType = contentType;
}

[JsonConstructor]
private FileParameter()
{
}

[JsonProperty]
public System.IO.Stream Data { get; private set; }

[JsonProperty]
public string FileName { get; private set; }

[JsonProperty]
public string ContentType { get; private set; }
}

Here is a working demo: https://dotnetfiddle.net/371ggK

Solution 2 - use a ContractResolver

If you cannot easily modify the FileParameter class because it is generated or you don't own the code, you can use a custom ContractResolver to do the same thing programmatically. Below is the code you would need for that.

public class CustomContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
JsonObjectContract contract = base.CreateObjectContract(objectType);
if (objectType == typeof(FileParameter))
{
// inject a "constructor" to use when creating FileParameter instances
contract.DefaultCreator = () => new FileParameter(null);

// make the private properties writable
string[] propNames = new string[]
{
nameof(FileParameter.Data),
nameof(FileParameter.FileName),
nameof(FileParameter.ContentType),
};
foreach (JsonProperty prop in contract.Properties.Where(p => propNames.Contains(p.UnderlyingName)))
{
prop.Writable = true;
}
}
return contract;
}
}

To use the resolver, add it to the JsonSerializerSettings along with the StreamStringConverter:

var obj = JsonConvert.DeserializeObject<BulkLeadRequest>(serializedObject,
new JsonSerializerSettings
{
ContractResolver = new CustomContractResolver(),
Converters = new List<JsonConverter> { new StreamStringConverter() }
});

Working demo: https://dotnetfiddle.net/VHf359


By the way, in the WriteJson method of your StreamStringConverter, I noticed you are casting the value to a FileStream even though the CanConvert method says it can handle any Stream. You can fix it by changing this line:

FileStream valueStream = (FileStream)value;

to this:

Stream valueStream = (Stream)value;

Write java objects to CSV file

If you want to write into a CSV file then you don't need to implement Serializable interface. With Serialization you can not write csv file. Serialization process write object state into .sar file. You may consider to use some CSV library or you may write it. You may check this tutorial.

Generating CSV file from object in java

You might have got the answer if googled it.
It already has answer here : Object to CSV

Using super csv : Using super csv to write in csv from object

How do I serialize & deserialize CSV properly?

From the error, I would like to believe that it has something to do with your schema for a Car, which has the columns of {"color"} taken from @JsonPropertyOrder on Car and not a "name" value.

You probably want to add "parts" in there, but you would get the same error that "name" is not part of that schema.

After a few changes to your code, I was able to serialize and deserialize a Car object.

Part

Here, after some other changes it needed a constructor with a single String value, so add that

@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;
}

Car

Here, you will need to implement a method that will convert the List<Part> into a CSV-readable format manually.

Such a method would look like this

@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();
}

Also, don't forget to fix the schema at the top of the class

@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

You can change your serialize method to take the type of the class as a generic type parameter instead of an explicit Class like so.

public static final synchronized <T> 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);
}

main - writer

Now, if you serialize a Car, you should see

color,parts
red,gearbox;door;bumper

main - reader

And reading that CSV string and looping over the 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


Related Topics



Leave a reply



Submit