Skip to content

Commit d65203e

Browse files
parikshitduttafmbenhassine
authored andcommitted
Add support for 'standalone' attribute in StaxEventItemWriter
Issue #758
1 parent b309ddc commit d65203e

File tree

5 files changed

+188
-11
lines changed

5 files changed

+188
-11
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ allprojects {
9494
servletApiVersion = '4.0.1'
9595
sqlfireclientVersion = '1.0.3'
9696
sqliteVersion = '3.32.3.2'
97-
woodstoxVersion = '6.2.0'
97+
woodstoxVersion = '6.2.1'
9898
xmlunitVersion = '2.7.0'
9999
xstreamVersion = '1.4.12'
100100
jrubyVersion = '1.7.27'

spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2017 the original author or authors.
2+
* Copyright 2006-2020 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.
@@ -72,7 +72,7 @@
7272
* @author Peter Zozom
7373
* @author Robert Kasanicky
7474
* @author Michael Minella
75-
*
75+
* @author Parikshit Dutta
7676
*/
7777
public class StaxEventItemWriter<T> extends AbstractItemStreamItemWriter<T> implements
7878
ResourceAwareItemWriterItemStream<T>, InitializingBean {
@@ -85,6 +85,9 @@ public class StaxEventItemWriter<T> extends AbstractItemStreamItemWriter<T> impl
8585
// default encoding
8686
public static final String DEFAULT_XML_VERSION = "1.0";
8787

88+
// default standalone document declaration, value not set
89+
public static final Boolean DEFAULT_STANDALONE_DOCUMENT = null;
90+
8891
// default root tag name
8992
public static final String DEFAULT_ROOT_TAG_NAME = "root";
9093

@@ -109,6 +112,9 @@ public class StaxEventItemWriter<T> extends AbstractItemStreamItemWriter<T> impl
109112
// XML version
110113
private String version = DEFAULT_XML_VERSION;
111114

115+
// standalone header attribute
116+
private Boolean standalone = DEFAULT_STANDALONE_DOCUMENT;
117+
112118
// name of the root tag
113119
private String rootTagName = DEFAULT_ROOT_TAG_NAME;
114120

@@ -270,6 +276,29 @@ public void setVersion(String version) {
270276
this.version = version;
271277
}
272278

279+
/**
280+
* Get used standalone document declaration.
281+
*
282+
* @return the standalone document declaration used
283+
*
284+
* @since 4.3
285+
*/
286+
public Boolean getStandalone() {
287+
return standalone;
288+
}
289+
290+
/**
291+
* Set standalone document declaration to be used for output XML. If not set,
292+
* standalone document declaration will be omitted.
293+
*
294+
* @param standalone the XML standalone document declaration to be used
295+
*
296+
* @since 4.3
297+
*/
298+
public void setStandalone(Boolean standalone) {
299+
this.standalone = standalone;
300+
}
301+
273302
/**
274303
* Get the tag name of the root element.
275304
*
@@ -606,7 +635,12 @@ protected void startDocument(XMLEventWriter writer) throws XMLStreamException {
606635
XMLEventFactory factory = createXmlEventFactory();
607636

608637
// write start document
609-
writer.add(factory.createStartDocument(getEncoding(), getVersion()));
638+
if (getStandalone()==null) {
639+
writer.add(factory.createStartDocument(getEncoding(), getVersion()));
640+
}
641+
else {
642+
writer.add(factory.createStartDocument(getEncoding(), getVersion(), getStandalone()));
643+
}
610644

611645
// write root tag
612646
writer.add(factory.createStartElement(getRootTagNamespacePrefix(), getRootTagNamespace(), getRootTagName()));

spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/builder/StaxEventItemWriterBuilder.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2017-2020 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.
@@ -27,6 +27,7 @@
2727
* A builder for the {@link StaxEventItemWriter}.
2828
*
2929
* @author Michael Minella
30+
* @author Parikshit Dutta
3031
* @since 4.0
3132
* @see StaxEventItemWriter
3233
*/
@@ -50,6 +51,8 @@ public class StaxEventItemWriterBuilder<T> {
5051

5152
private String version = StaxEventItemWriter.DEFAULT_XML_VERSION;
5253

54+
private Boolean standalone = StaxEventItemWriter.DEFAULT_STANDALONE_DOCUMENT;
55+
5356
private String rootTagName = StaxEventItemWriter.DEFAULT_ROOT_TAG_NAME;
5457

5558
private Map<String, String> rootElementAttributes;
@@ -188,14 +191,29 @@ public StaxEventItemWriterBuilder<T> encoding(String encoding) {
188191
*
189192
* @param version XML version
190193
* @return the current instance of the builder
191-
* @see StaxEventItemWriter#version
194+
* @see StaxEventItemWriter#setVersion(String)
192195
*/
193196
public StaxEventItemWriterBuilder<T> version(String version) {
194197
this.version = version;
195198

196199
return this;
197200
}
198201

202+
/**
203+
* Standalone document declaration for the output document. Defaults to null.
204+
*
205+
* @param standalone Boolean standalone document declaration
206+
* @return the current instance of the builder
207+
* @see StaxEventItemWriter#setStandalone(Boolean)
208+
*
209+
* @since 4.3
210+
*/
211+
public StaxEventItemWriterBuilder<T> standalone(Boolean standalone) {
212+
this.standalone = standalone;
213+
214+
return this;
215+
}
216+
199217
/**
200218
* The name of the root tag for the output document.
201219
*
@@ -278,6 +296,7 @@ public StaxEventItemWriter<T> build() {
278296
writer.setTransactional(this.transactional);
279297
writer.setVersion(this.version);
280298
writer.setName(this.name);
299+
writer.setStandalone(this.standalone);
281300

282301
return writer;
283302
}

spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2008-2014 the original author or authors.
2+
* Copyright 2008-2020 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.
@@ -55,6 +55,8 @@
5555

5656
/**
5757
* Tests for {@link StaxEventItemWriter}.
58+
*
59+
* @author Parikshit Dutta
5860
*/
5961
public class StaxEventItemWriterTests {
6062

@@ -137,6 +139,35 @@ public void testAssertWriterIsInitialized() throws Exception {
137139
writer.write(Collections.singletonList("foo"));
138140
}
139141

142+
@Test
143+
public void testStandaloneDeclarationInHeaderWhenNotSet() throws Exception {
144+
writer.open(executionContext);
145+
writer.write(items);
146+
writer.close();
147+
String content = getOutputFileContent(writer.getEncoding(), false);
148+
assertFalse(content.contains("standalone="));
149+
}
150+
151+
@Test
152+
public void testStandaloneDeclarationInHeaderWhenSetToTrue() throws Exception {
153+
writer.setStandalone(true);
154+
writer.open(executionContext);
155+
writer.write(items);
156+
writer.close();
157+
String content = getOutputFileContent(writer.getEncoding(), false);
158+
assertTrue(content.contains("standalone='yes'"));
159+
}
160+
161+
@Test
162+
public void testStandaloneDeclarationInHeaderWhenSetToFalse() throws Exception {
163+
writer.setStandalone(false);
164+
writer.open(executionContext);
165+
writer.write(items);
166+
writer.close();
167+
String content = getOutputFileContent(writer.getEncoding(), false);
168+
assertTrue(content.contains("standalone='no'"));
169+
}
170+
140171
/**
141172
* Item is written to the output file only after flush.
142173
*/
@@ -982,12 +1013,28 @@ private String getOutputFileContent() throws IOException {
9821013
* @return output file content as String
9831014
*/
9841015
private String getOutputFileContent(String encoding) throws IOException {
1016+
return getOutputFileContent(encoding, true);
1017+
}
1018+
1019+
/**
1020+
* @param encoding the encoding
1021+
* @param discardHeader the flag to strip XML header
1022+
* @return output file content as String
1023+
*/
1024+
private String getOutputFileContent(String encoding, boolean discardHeader) throws IOException {
9851025
String value = FileUtils.readFileToString(resource.getFile(), encoding);
986-
value = value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
1026+
if (discardHeader) {
1027+
// standalone is omitted if not explicitly set, meaning it will be 'yes'/'no' or no standalone attribute
1028+
if (value.contains("standalone")) {
1029+
boolean standalone = value.contains("standalone='yes'");
1030+
return value.replace("<?xml version='1.0' encoding='" + encoding + "' " +
1031+
(standalone ? "standalone='yes'" : "standalone='no'") + "?>", "");
1032+
}
1033+
return value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
1034+
}
9871035
return value;
9881036
}
9891037

990-
9911038
/**
9921039
* @return new instance of fully configured writer
9931040
*/

spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/builder/StaxEventItemWriterBuilderTests.java

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017 the original author or authors.
2+
* Copyright 2017-2020 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.
@@ -46,6 +46,7 @@
4646

4747
/**
4848
* @author Michael Minella
49+
* @author Parikshit Dutta
4950
*/
5051
public class StaxEventItemWriterBuilderTests {
5152

@@ -224,9 +225,85 @@ public void testMissingNameValidation() {
224225
.build();
225226
}
226227

228+
@Test
229+
public void testStandaloneDeclarationInHeaderWhenNotSet() throws Exception {
230+
StaxEventItemWriter<Foo> staxEventItemWriter = new StaxEventItemWriterBuilder<Foo>()
231+
.name("fooWriter")
232+
.marshaller(marshaller)
233+
.resource(this.resource)
234+
.build();
235+
236+
staxEventItemWriter.afterPropertiesSet();
237+
238+
ExecutionContext executionContext = new ExecutionContext();
239+
staxEventItemWriter.open(executionContext);
240+
staxEventItemWriter.write(this.items);
241+
staxEventItemWriter.close();
242+
243+
String output = getOutputFileContent(staxEventItemWriter.getEncoding(), false);
244+
assertFalse(output.contains("standalone="));
245+
}
246+
247+
@Test
248+
public void testStandaloneDeclarationInHeaderWhenSetToTrue() throws Exception {
249+
StaxEventItemWriter<Foo> staxEventItemWriter = new StaxEventItemWriterBuilder<Foo>()
250+
.name("fooWriter")
251+
.marshaller(marshaller)
252+
.resource(this.resource)
253+
.standalone(true)
254+
.build();
255+
256+
staxEventItemWriter.afterPropertiesSet();
257+
258+
ExecutionContext executionContext = new ExecutionContext();
259+
staxEventItemWriter.open(executionContext);
260+
staxEventItemWriter.write(this.items);
261+
staxEventItemWriter.close();
262+
263+
String output = getOutputFileContent(staxEventItemWriter.getEncoding(), false);
264+
assertTrue(output.contains("standalone='yes'"));
265+
}
266+
267+
@Test
268+
public void testStandaloneDeclarationInHeaderWhenSetToFalse() throws Exception {
269+
StaxEventItemWriter<Foo> staxEventItemWriter = new StaxEventItemWriterBuilder<Foo>()
270+
.name("fooWriter")
271+
.marshaller(marshaller)
272+
.resource(this.resource)
273+
.standalone(false)
274+
.build();
275+
276+
staxEventItemWriter.afterPropertiesSet();
277+
278+
ExecutionContext executionContext = new ExecutionContext();
279+
staxEventItemWriter.open(executionContext);
280+
staxEventItemWriter.write(this.items);
281+
staxEventItemWriter.close();
282+
283+
String output = getOutputFileContent(staxEventItemWriter.getEncoding(), false);
284+
assertTrue(output.contains("standalone='no'"));
285+
}
286+
227287
private String getOutputFileContent(String encoding) throws IOException {
288+
return getOutputFileContent(encoding, true);
289+
}
290+
291+
/**
292+
* @param encoding the encoding
293+
* @param discardHeader the flag to strip XML header
294+
* @return output file content as String
295+
*/
296+
private String getOutputFileContent(String encoding, boolean discardHeader) throws IOException {
228297
String value = FileUtils.readFileToString(resource.getFile(), encoding);
229-
value = value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
298+
if (discardHeader) {
299+
// standalone is omitted if not explicitly set, meaning it will be 'yes'/'no' or no standalone attribute
300+
if (value.contains("standalone")) {
301+
boolean standalone = value.contains("standalone='yes'");
302+
return value.replace("<?xml version='1.0' encoding='" + encoding + "' " +
303+
(standalone ? "standalone='yes'" : "standalone='no'") + "?>", "");
304+
}
305+
return value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
306+
}
230307
return value;
231308
}
232309

0 commit comments

Comments
 (0)