Search code examples
javaspring-bootspring-batchexport-to-csv

Save object with List as csv file FlatFileItemWriter


I have an object like (abstract description)

public class Book {
private String name;
private List<Author> authors;
}
public class Author {
private String name;
}

and for example

 new Book()
 .setName("Book name1")
 .setAuthors(new ArrayList(Arrays.asList(
      new Author().setName("Author 1"), 
      new Author().setName("Author 2"))));

Example code:

@Bean
public FlatFileItemWriter<Book> writer()
{
    FlatFileItemWriter<Book> writer = new FlatFileItemWriter<>();
    writer.setResource(outputResource);
    writer.setAppendAllowed(true);
    writer.setLineAggregator(new DelimitedLineAggregator<Book>() {
        {
            setDelimiter(";");
            setFieldExtractor(new BeanWrapperFieldExtractor<Book>() {
                {
                    setNames(new String[] { "name", "authors" });
                }
            });
        }
    });
    return writer;
}

this way I get result:

Book name1;[Author(authorName=Author 1), Author(authorName=Author 2)]

But I want to get result csv file as:

Book name1;Author 1
Book name1;Author 2

Help me to understand, how does it work. Thanks in advance.


Solution

  • Help me to understand, how does it work

    The BeanWrapperFieldExtractor is a field extractor that call getters on each field of your input object. Here is an excerpt from its Javadoc:

    Given an array of property names, it will reflectively call getters on the item
    and return an array of all the values.
    

    In your case, calling the getter of the field authors results in the toString() value of a List object:

    [Author(authorName=Author 1), Author(authorName=Author 2)]
    

    However, what you are trying to do is actually a flatmap operation, since you want each input book to be written as multiple lines, one line for each author. There are many ways to do that, one of them is described in Flatten processing result in spring batch.