Add support for quotes in DelimitedLineAggregator

Resolves #1139
This commit is contained in:
Glenn Renfro
2021-05-13 09:32:25 -04:00
committed by Mahmoud Ben Hassine
parent 4444e465a6
commit cc233e6b35
4 changed files with 75 additions and 6 deletions

View File

@@ -34,6 +34,7 @@ import org.springframework.batch.item.file.transform.LineAggregator;
import org.springframework.batch.item.file.transform.RecordFieldExtractor;
import org.springframework.core.io.WritableResource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A builder implementation for the {@link FlatFileItemWriter}
@@ -424,6 +425,8 @@ public class FlatFileItemWriterBuilder<T> {
private String delimiter = ",";
private String quoteCharacter = "";
private FieldExtractor<T> fieldExtractor;
private Class<T> sourceType;
@@ -457,6 +460,17 @@ public class FlatFileItemWriterBuilder<T> {
return this;
}
/**
* Define the quote character for each delimited field. Default is empty string.
* @param quoteCharacter String used as a quote for the aggregate.
* @return The instance of the builder for chaining.
* @see DelimitedLineAggregator#setQuoteCharacter(String)
*/
public DelimitedBuilder<T> quoteCharacter(String quoteCharacter) {
this.quoteCharacter = quoteCharacter;
return this;
}
/**
* Names of each of the fields within the fields that are returned in the order
* they occur within the delimited file. These names will be used to create a
@@ -489,6 +503,9 @@ public class FlatFileItemWriterBuilder<T> {
if (this.delimiter != null) {
delimitedLineAggregator.setDelimiter(this.delimiter);
}
if (StringUtils.hasLength(this.quoteCharacter)) {
delimitedLineAggregator.setQuoteCharacter(this.quoteCharacter);
}
if (this.fieldExtractor == null) {
if (this.sourceType != null && this.sourceType.isRecord()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,19 +15,24 @@
*/
package org.springframework.batch.item.file.transform;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* A {@link LineAggregator} implementation that converts an object into a delimited list
* of strings. The default delimiter is a comma.
* of strings. The default delimiter is a comma. An optional quote value can be set to add
* surrounding quotes for each element of the list. Default is empty string, which means
* not quotes.
*
* @author Dave Syer
*
* @author Glenn Renfro
*/
public class DelimitedLineAggregator<T> extends ExtractorLineAggregator<T> {
private String delimiter = ",";
private String quoteCharacter = "";
/**
* Public setter for the delimiter.
* @param delimiter the delimiter to set
@@ -36,9 +41,20 @@ public class DelimitedLineAggregator<T> extends ExtractorLineAggregator<T> {
this.delimiter = delimiter;
}
/**
* Setter for the quote character.
* @since 5.1
* @param quoteCharacter the quote character to set
*/
public void setQuoteCharacter(String quoteCharacter) {
this.quoteCharacter = quoteCharacter;
}
@Override
public String doAggregate(Object[] fields) {
return StringUtils.arrayToDelimitedString(fields, this.delimiter);
return Arrays.stream(fields)
.map(field -> this.quoteCharacter + field + this.quoteCharacter)
.collect(Collectors.joining(this.delimiter));
}
}

View File

@@ -153,6 +153,34 @@ class FlatFileItemWriterBuilderTests {
assertEquals("HEADER$123$456$FOOTER", readLine("UTF-16LE", output));
}
@Test
public void testDelimitedOutputWithEmptyDelimiterAndQuote() throws Exception {
FileSystemResource output = new FileSystemResource(File.createTempFile("foo", "txt"));
FlatFileItemWriter<Foo> writer = new FlatFileItemWriterBuilder<Foo>().name("foo")
.resource(output)
.lineSeparator("$")
.delimited()
.delimiter("")
.quoteCharacter("%")
.names("first", "second", "third")
.encoding("UTF-16LE")
.headerCallback(writer1 -> writer1.append("HEADER"))
.footerCallback(writer12 -> writer12.append("FOOTER"))
.build();
ExecutionContext executionContext = new ExecutionContext();
writer.open(executionContext);
writer.write(new Chunk<>(new Foo(1, 2, "3"), new Foo(4, 5, "6")));
writer.close();
assertEquals("HEADER$%1%%2%%3%$%4%%5%%6%$FOOTER", readLine("UTF-16LE", output));
}
@Test
void testDelimitedOutputWithDefaultFieldExtractor() throws Exception {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2022 the original author or authors.
* Copyright 2006-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test;
/**
* @author Dave Syer
* @author Glenn Renfro
*
*/
class DelimitedLineAggregatorTests {
@@ -40,6 +41,13 @@ class DelimitedLineAggregatorTests {
assertEquals("foo;bar", aggregator.aggregate(new String[] { "foo", "bar" }));
}
@Test
public void testSetDelimiterAndQuote() {
aggregator.setDelimiter(";");
aggregator.setQuoteCharacter("\"");
assertEquals("\"foo\";\"bar\"", aggregator.aggregate(new String[] { "foo", "bar" }));
}
@Test
void testAggregate() {
assertEquals("foo,bar", aggregator.aggregate(new String[] { "foo", "bar" }));