StatefulBeanToCsv with Column headers
ColumnPositionMappingStrategy#generateHeader returns empty array
/**
* This method returns an empty array.
* The column position mapping strategy assumes that there is no header, and
* thus it also does not write one, accordingly.
* @return An empty array
*/
@Override
public String[] generateHeader() {
return new String[0];
}
If you remove MappingStrategy from BeanToCsv builder
// replace
StatefulBeanToCsv<Product> beanWriter = builder.withMappingStrategy(mappingStrategy).build();
// with
StatefulBeanToCsv<Product> beanWriter = builder.build();
It will write Product's class members as CSV header
If your Product class members names are
"productCode", "MFD", "EXD"
This should be the right solution
Else, add @CsvBindByName annotation
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import java.io.FileWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
public class CsvTest {
public static void main(String[] args) throws Exception {
Writer writer = new FileWriter(fileName);
StatefulBeanToCsvBuilder<Product> builder = new StatefulBeanToCsvBuilder<>(writer);
StatefulBeanToCsv<Product> beanWriter = builder.build();
List<Product> products = new ArrayList<>();
products.add(new Product("1", "11", "111"));
products.add(new Product("2", "22", "222"));
products.add(new Product("3", "33", "333"));
beanWriter.write(products);
writer.close();
}
public static class Product {
@CsvBindByName(column = "productCode")
String id;
@CsvBindByName(column = "MFD")
String member2;
@CsvBindByName(column = "EXD")
String member3;
Product(String id, String member2, String member3) {
this.id = id;
this.member2 = member2;
this.member3 = member3;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMember2() {
return member2;
}
public void setMember2(String member2) {
this.member2 = member2;
}
public String getMember3() {
return member3;
}
public void setMember3(String member3) {
this.member3 = member3;
}
}
}
Output:
"EXD","MFD","PRODUCTCODE"
"111","11","1"
"222","22","2"
"333","33","3"
Pay attention; class, getters & setters needs to be public due to the use of Reflection by OpenCSV library
Why opencsv capitalizing csv headers while writing to file
It happens, because the code in HeaderColumnNameMappingStrategy uses toUpperCase()
for storing and retrieving the field names.
You could use the HeaderColumnNameTranslateMappingStrategy instead and create the mapping by reflection.
public class AnnotationStrategy extends HeaderColumnNameTranslateMappingStrategy
{
public AnnotationStrategy(Class<?> clazz)
{
Map<String,String> map=new HashMap<>();
//To prevent the column sorting
List<String> originalFieldOrder=new ArrayList<>();
for(Field field:clazz.getDeclaredFields())
{
CsvBindByName annotation = field.getAnnotation(CsvBindByName.class);
if(annotation!=null)
{
map.put(annotation.column(),annotation.column());
originalFieldOrder.add(annotation.column());
}
}
setType(clazz);
setColumnMapping(map);
//Order the columns as they were created
setColumnOrderOnWrite((a,b) -> Integer.compare(originalFieldOrder.indexOf(a), originalFieldOrder.indexOf(b)));
}
@Override
public String[] generateHeader(Object bean) throws CsvRequiredFieldEmptyException
{
String[] result=super.generateHeader(bean);
for(int i=0;i<result.length;i++)
{
result[i]=getColumnName(i);
}
return result;
}
}
And, assuming that there is only one class of items (and always at least one item), the creation of beanWriter
has to be expanded:
StatefulBeanToCsv beanWriter = builder.withSeparator(';')
.withMappingStrategy(new AnnotationStrategy(projectInfos.iterator().next().getClass()))
.build();
Appending to CSV file without headers
Good one. Appending was something we did not think much of when we did writing in opencsv because it is potentially risky (something goes wrong you could corrupt what was a good file) so write was favored instead.
That said open up a bug or feature request in sourceforge and if there is enough interest we will try and get it in the 4.3 release (4.2 is booked solid).
THAT said if you want to get around this create your own MappingStrategy class that extends the HeaderColumnNameMappingStrategy and all you need there is a override on the generateHeader method to return an empty String array. You can look at the code in ColumnPositionMappingStrategy to see what I am talking about. This will prevent the header from being written. In this case you will need to use this only in the else part.
Hope that helps.
:)
When writing a file produced by opencsv in java how do I create a file with no heading?
Put the annotation
@CsvBindByPosition(position = 0)
On the bean being serialised.
OpenCsv writes wrong column names with BeanToCsv + HeaderColumnNameTranslateMappingStrategy
Looking at the source code of BeanToCsv
, the processHeader(...)
method does nothing with the supplied headers. Your only option is to create a custom strategy ( to avoid CSVReader
) and a custom BeanToCsv
as below
public class CustomBean {
...
public static void main(String[] args) {
...
HeaderColumnNameTranslateMappingStrategy strategy = new CustomStrategy<CustomBean>();
strategy.setType(CustomBean.class);
strategy.setColumnMapping(mapping);
...
BeanToCsv bean = new CustomBeanToCsv<CustomBean>();
...
}
static class CustomStrategy<T> extends HeaderColumnNameTranslateMappingStrategy {
@Override
public void setColumnMapping(Map columnMapping) {
super.setColumnMapping(columnMapping);
header = new String[columnMapping.size()];
int i = 0;
for (Map.Entry entry : columnMapping.entrySet()) {
header[i] = entry.getKey().toUpperCase();
i++;
}
}
public String[] getHeader() {
return header;
}
}
static class CustomBeanToCsv<T> extends BeanToCsv {
@Override
protected String[] processHeader(MappingStrategy mapper) throws IntrospectionException {
if (mapper instanceof CustomStrategy) {
return ((CustomStrategy) mapper).getHeader();
} else {
return super.processHeader(mapper);
}
}
}
}
OpenCSV all of the data storing in single line version (5.1) and data loss
When you try to write more than one object the last one is overwritten because the FileWriter you are passing to StatefulBeanToCsv
is not in append mode. You should specify the append mode in the FileWriter constructor.
Writer writer = new FileWriter(filePath, true);
StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer).build();
beanToCsv.write(object);
writer.close();
Edit: This should solve multiple columns headers and column header not breaking line. It works for me.
public <T> void beanToCsvExport(final List<T> object, final String filePath) {
if (object == null) {
System.out.println("Initialization of object failed");
} else {
try {
cleanFile(filePath);
FileWriter writer = new FileWriter(filePath, true);
StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer).build();
beanToCsv.write(object);
writer.close();
} catch (IOException | CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
System.out.println(e.getMessage());
}
}
}
The function that resets the file:
public void cleanFile(String path) throws IOException {
FileWriter writer = new FileWriter(path); //Open as non-append to delete all data.
writer.write("");
writer.close();
}
To test the functions:
public void employeesToCsv() {
List<Employee> list = Arrays.asList(new Employee("101", "sunny"), new Employee("102", "Andrew"));
beanToCsvExport(list, "file.csv");
}
The achieved output:
"eId","eName"
"101","sunny"
"102","Andrew"
Related Topics
Spring Jpa/Hibernate Transaction Force Insert Instead of Update
How to Find Out If String Has Already Been Url Encoded
Disable Spring Security Config Class for @Webmvctest in Spring Boot
I Get a Status 200 When Connecting to the Websocket, But It Is an Error
How to Pass Variables Between Cucumber-Jvm Steps
Using Comparable to Compare Generic Variables
Detecting a File Downloaded in Selenium Java
How to Solve Gradle Error Cannot Find Symbol
Spring Kafka - How to Reset Offset to Latest With a Group Id
Gradle Java9 Could Not Target Platform: 'Java Se 9' Using Tool Chain: 'Jdk 8 (1.8)'
Default Value in Lombok. How to Init Default With Both Constructor and Builder
Kafka Consumer in Java Not Consuming Messages
Jdk Tools.Jar as Maven Dependency
Method to Find the Smallest Number from an Integer
@Valid Annotation Is Not Working as Expected
How to Avoid 302 Response on Https Spring Security Unit Test
Java8 Way to Handle If..Else Check in Collections
How to Set the Radio Button Based on the Value Fetched from the Database