I am trying to export a bean via opencsv and came across a little problem with a specialty in the export structure.
I have a few columns like this
@CsvBindAndSplitByPosition(position = 16, splitOn = "\\|", converter = MultiAttributeValueConverter.class, elementType = MultiAttributeValue.class, writeDelimiter = "|")
private List<MultiAttributeValue> attributes;
Works as expected and delivers the following result
...,"attribute1=value|attribute2=value2|attribute3=value3",...
I require a slightly different output
...,"|attribute1=value|attribute2=value2|attribute3=value3|",...
I require a leading and tailing | for these fields. Currently I have no idea how I would add these with any default functionality or where to add it.
Happy about any input or tips
Edit as request in comment Info about the MultivValueAttribute Currently not access to the code so more of a loose description, altough it shouldn't effect my case since i would have the same problem with a simple string
class MultivValueAttribute {
String name;
String value;
...
}
Converter:
return name+value;
Although not pretty I did find a solution using a custom binding converter:
public class CustomBindingConverter<T, I> extends AbstractBeanField<T, I>
{
private CustomFormatBeanFieldSplit<T, I> myConvert = null;
@Override
public void setField(Field field)
{
// TODO Auto-generated method stub
super.setField(field);
if (field.isAnnotationPresent(CsvBindAndSplitByPosition.class))
{
CsvBindAndSplitByPosition annotation = field.getAnnotation(CsvBindAndSplitByPosition.class);
String fieldLocale = annotation.locale();
String fieldWriteLocale = annotation.writeLocaleEqualsReadLocale() ? fieldLocale : annotation.writeLocale();
Class<?> elementType = annotation.elementType();
CsvConverter converter = determineConverter(field, elementType, fieldLocale, fieldWriteLocale,
annotation.converter());
myConvert = new CustomFormatBeanFieldSplit<>(getType(), field, annotation.required(), errorLocale,
converter, annotation.splitOn(), annotation.writeDelimiter(), annotation.collectionType(),
annotation.elementType(), annotation.capture(), annotation.format());
}
}
@Override
protected Object convert(String value) throws CsvDataTypeMismatchException, CsvConstraintViolationException
{
return myConvert.convert(value);
}
@Override
protected String convertToWrite(Object value) throws CsvDataTypeMismatchException, CsvRequiredFieldEmptyException
{
// TODO Auto-generated method stub
return myConvert.convertToWrite(value);
}
protected CsvConverter determineConverter(Field field, Class<?> elementType, String locale, String writeLocale,
Class<? extends AbstractCsvConverter> customConverter) throws CsvBadConverterException
{
CsvConverter converter;
// A custom converter always takes precedence if specified.
if (customConverter != null && !customConverter.equals(AbstractCsvConverter.class))
{
try
{
converter = customConverter.newInstance();
}
catch(IllegalAccessException | InstantiationException oldEx)
{
CsvBadConverterException newEx = new CsvBadConverterException(customConverter,
String.format(ResourceBundle.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
.getString("custom.converter.invalid"),
customConverter.getCanonicalName()));
newEx.initCause(oldEx);
throw newEx;
}
converter.setType(elementType);
converter.setLocale(locale);
converter.setWriteLocale(writeLocale);
converter.setErrorLocale(errorLocale);
}
// Perhaps a date instead
else if (field.isAnnotationPresent(CsvDate.class))
{
CsvDate annotation = field.getAnnotation(CsvDate.class);
String readFormat = annotation.value();
String writeFormat = annotation.writeFormatEqualsReadFormat() ? readFormat : annotation.writeFormat();
String readChrono = annotation.chronology();
String writeChrono = annotation.writeChronologyEqualsReadChronology() ? readChrono
: annotation.writeChronology();
converter = new ConverterDate(elementType, locale, writeLocale, errorLocale, readFormat, writeFormat,
readChrono, writeChrono);
}
// Or a number
else if (field.isAnnotationPresent(CsvNumber.class))
{
CsvNumber annotation = field.getAnnotation(CsvNumber.class);
String readFormat = annotation.value();
String writeFormat = annotation.writeFormatEqualsReadFormat() ? readFormat : annotation.writeFormat();
converter = new ConverterNumber(elementType, locale, writeLocale, errorLocale, readFormat, writeFormat);
}
// or a Currency
else if (elementType.equals(java.util.Currency.class))
{
converter = new ConverterCurrency(errorLocale);
}
// Or an enumeration
else if (elementType.isEnum())
{
converter = new ConverterEnum(elementType, locale, writeLocale, errorLocale);
}
// Otherwise a primitive
else
{
converter = new ConverterPrimitiveTypes(elementType, locale, writeLocale, errorLocale);
}
return converter;
}
}
And a modification of the BeanFieldSplitConverter:
public class CustomFormatBeanFieldSplit<T, I> extends BeanFieldSplit<T, I>
{
String writeFormat;
String writeDelimiter;
public CustomFormatBeanFieldSplit(Class<?> type, Field field, boolean required, Locale errorLocale,
CsvConverter converter, String splitOn, String writeDelimiter,
Class<? extends Collection> collectionType, Class<?> elementType, String capture, String format)
{
super(type, field, required, errorLocale, converter, splitOn, writeDelimiter, collectionType, elementType, capture,
format);
this.writeFormat = format;
this.writeDelimiter = writeDelimiter;
}
@Override
protected String convertToWrite(Object value)
throws CsvDataTypeMismatchException {
String retval = StringUtils.EMPTY;
if(value != null) {
@SuppressWarnings("unchecked") Collection<Object> collection = (Collection<Object>) value;
String[] convertedValue = new String[collection.size()];
int i = 0;
for(Object o : collection) {
convertedValue[i] = converter.convertToWrite(o);
if(StringUtils.isNotEmpty(this.writeFormat)
&& StringUtils.isNotEmpty(convertedValue[i])) {
convertedValue[i] = String.format(this.writeFormat, convertedValue[i]);
}
i++;
}
String coreValue = StringUtils.join(convertedValue, writeDelimiter);
if(StringUtils.isEmpty(coreValue)) {
return coreValue;
}
retval = writeDelimiter + coreValue + writeDelimiter;
}
return retval;
}
@Override
protected Object convert(String value) throws CsvDataTypeMismatchException, CsvConstraintViolationException
{
// TODO Auto-generated method stub
return super.convert(value);
}
}