Skip to content

Commit cc233e6

Browse files
cppwfsfmbenhassine
authored andcommitted
Add support for quotes in DelimitedLineAggregator
Resolves #1139
1 parent 4444e46 commit cc233e6

File tree

4 files changed

+75
-6
lines changed

4 files changed

+75
-6
lines changed

spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/builder/FlatFileItemWriterBuilder.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.batch.item.file.transform.RecordFieldExtractor;
3535
import org.springframework.core.io.WritableResource;
3636
import org.springframework.util.Assert;
37+
import org.springframework.util.StringUtils;
3738

3839
/**
3940
* A builder implementation for the {@link FlatFileItemWriter}
@@ -424,6 +425,8 @@ public static class DelimitedBuilder<T> {
424425

425426
private String delimiter = ",";
426427

428+
private String quoteCharacter = "";
429+
427430
private FieldExtractor<T> fieldExtractor;
428431

429432
private Class<T> sourceType;
@@ -457,6 +460,17 @@ public DelimitedBuilder<T> sourceType(Class<T> sourceType) {
457460
return this;
458461
}
459462

463+
/**
464+
* Define the quote character for each delimited field. Default is empty string.
465+
* @param quoteCharacter String used as a quote for the aggregate.
466+
* @return The instance of the builder for chaining.
467+
* @see DelimitedLineAggregator#setQuoteCharacter(String)
468+
*/
469+
public DelimitedBuilder<T> quoteCharacter(String quoteCharacter) {
470+
this.quoteCharacter = quoteCharacter;
471+
return this;
472+
}
473+
460474
/**
461475
* Names of each of the fields within the fields that are returned in the order
462476
* they occur within the delimited file. These names will be used to create a
@@ -489,6 +503,9 @@ public DelimitedLineAggregator<T> build() {
489503
if (this.delimiter != null) {
490504
delimitedLineAggregator.setDelimiter(this.delimiter);
491505
}
506+
if (StringUtils.hasLength(this.quoteCharacter)) {
507+
delimitedLineAggregator.setQuoteCharacter(this.quoteCharacter);
508+
}
492509

493510
if (this.fieldExtractor == null) {
494511
if (this.sourceType != null && this.sourceType.isRecord()) {

spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/DelimitedLineAggregator.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2007 the original author or authors.
2+
* Copyright 2006-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,19 +15,24 @@
1515
*/
1616
package org.springframework.batch.item.file.transform;
1717

18-
import org.springframework.util.StringUtils;
18+
import java.util.Arrays;
19+
import java.util.stream.Collectors;
1920

2021
/**
2122
* A {@link LineAggregator} implementation that converts an object into a delimited list
22-
* of strings. The default delimiter is a comma.
23+
* of strings. The default delimiter is a comma. An optional quote value can be set to add
24+
* surrounding quotes for each element of the list. Default is empty string, which means
25+
* not quotes.
2326
*
2427
* @author Dave Syer
25-
*
28+
* @author Glenn Renfro
2629
*/
2730
public class DelimitedLineAggregator<T> extends ExtractorLineAggregator<T> {
2831

2932
private String delimiter = ",";
3033

34+
private String quoteCharacter = "";
35+
3136
/**
3237
* Public setter for the delimiter.
3338
* @param delimiter the delimiter to set
@@ -36,9 +41,20 @@ public void setDelimiter(String delimiter) {
3641
this.delimiter = delimiter;
3742
}
3843

44+
/**
45+
* Setter for the quote character.
46+
* @since 5.1
47+
* @param quoteCharacter the quote character to set
48+
*/
49+
public void setQuoteCharacter(String quoteCharacter) {
50+
this.quoteCharacter = quoteCharacter;
51+
}
52+
3953
@Override
4054
public String doAggregate(Object[] fields) {
41-
return StringUtils.arrayToDelimitedString(fields, this.delimiter);
55+
return Arrays.stream(fields)
56+
.map(field -> this.quoteCharacter + field + this.quoteCharacter)
57+
.collect(Collectors.joining(this.delimiter));
4258
}
4359

4460
}

spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/builder/FlatFileItemWriterBuilderTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,34 @@ void testDelimitedOutputWithEmptyDelimiter() throws Exception {
153153
assertEquals("HEADER$123$456$FOOTER", readLine("UTF-16LE", output));
154154
}
155155

156+
@Test
157+
public void testDelimitedOutputWithEmptyDelimiterAndQuote() throws Exception {
158+
159+
FileSystemResource output = new FileSystemResource(File.createTempFile("foo", "txt"));
160+
161+
FlatFileItemWriter<Foo> writer = new FlatFileItemWriterBuilder<Foo>().name("foo")
162+
.resource(output)
163+
.lineSeparator("$")
164+
.delimited()
165+
.delimiter("")
166+
.quoteCharacter("%")
167+
.names("first", "second", "third")
168+
.encoding("UTF-16LE")
169+
.headerCallback(writer1 -> writer1.append("HEADER"))
170+
.footerCallback(writer12 -> writer12.append("FOOTER"))
171+
.build();
172+
173+
ExecutionContext executionContext = new ExecutionContext();
174+
175+
writer.open(executionContext);
176+
177+
writer.write(new Chunk<>(new Foo(1, 2, "3"), new Foo(4, 5, "6")));
178+
179+
writer.close();
180+
181+
assertEquals("HEADER$%1%%2%%3%$%4%%5%%6%$FOOTER", readLine("UTF-16LE", output));
182+
}
183+
156184
@Test
157185
void testDelimitedOutputWithDefaultFieldExtractor() throws Exception {
158186

spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/transform/DelimitedLineAggregatorTests.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2022 the original author or authors.
2+
* Copyright 2006-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222

2323
/**
2424
* @author Dave Syer
25+
* @author Glenn Renfro
2526
*
2627
*/
2728
class DelimitedLineAggregatorTests {
@@ -40,6 +41,13 @@ void testSetDelimiter() {
4041
assertEquals("foo;bar", aggregator.aggregate(new String[] { "foo", "bar" }));
4142
}
4243

44+
@Test
45+
public void testSetDelimiterAndQuote() {
46+
aggregator.setDelimiter(";");
47+
aggregator.setQuoteCharacter("\"");
48+
assertEquals("\"foo\";\"bar\"", aggregator.aggregate(new String[] { "foo", "bar" }));
49+
}
50+
4351
@Test
4452
void testAggregate() {
4553
assertEquals("foo,bar", aggregator.aggregate(new String[] { "foo", "bar" }));

0 commit comments

Comments
 (0)