CSV Writing: split HashSetValuedHashMap to multiple columns
Brought to you by:
aruckerjones,
sconway
Is there anyway when writing a CSV file with OpenCSV to do the reverse of CsvBindAndJoinByName and split the multivaluemap back to separate columns, as a use case I have an input file that has headers like
field1, field2, metadata.x, metadata.y, metadata.z
Which I parse into field1, field2 and metadata using
@CsvBindAndJoinByName(column = "metadata.*", elementType = String.class)
protected HashSetValuedHashMap<string, string=""> metadata;</string,>
I have a requirement to be able to separately write a matching file, I don't care what order the metadata appears in - just that the appropriate values appear in the right place!
Sure. Just write it.
http://opencsv.sourceforge.net/#writing_from_a_list_of_beans
Examples can be found here:
https://sourceforge.net/p/opencsv/source/ci/master/tree/src/test/java/com/opencsv/bean/JoinTest.java#l871
testWritePrimitive() on line 871 is a nice place to start.
That helps a lot although I still have a slight issue that I'm not sure whether there is an equally easy way to solve - in my case I don't want the columns to come out in alphabetical order, so currently I've done it by position to allow me to order them correctly, but I also need a header record. (since that lets me define the name of the arbitrary number of metadata fields) so I had written a CustomMappingStrategy that did it by position but used the Name annotation to define a column name too, but it doesn't handle the multivaluemaps - since I equally have to use @CsvBindAndJoinByPosition, but it's position is a String which doesn't cast well as an Integer
From what I understand doing it by Name gets me a header, but doing it by position doesn't.
My multi-value maps are Key,Value (which fits the Name model), and not Index, Value (since I don't know/care what the position is and I need both the "name" and the "value" (the metadata columns are always at the end of the row so as not to break any of the earlier field positions.
Given that I've got a fixed number of initial columns (needing to be a specific order) and an arbitrary number of additional columns (which aren't order dependent and I don't know the union of all the keys that might be present in the list of beans that I have I couldn't see how I could use a Comparator to define the order / names?
This is what I was using the for the CustomMapping if it helps...
public class NameAndPositionMappingStrategy<t> extends ColumnPositionMappingStrategy<t> {
@SuppressWarnings("rawtypes")
@Override
public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
final int numColumns = getFieldMap().values().size();
super.generateHeader(bean);</t></t>
}
Read up on the Comparators Apache Commons Collections offers, most especially ComparatorChain and FixedOrderComparator. It really should be possible to use a Comparator to define any possible order. Commons Collections is already in your classpath because of opencsv.
As to the position strategy and a header: CSV either has a header, and then order does not matter, or it does not have a header, and then order is everything. The two do not and will never mix.
closed for lack of movement.