Add support for 'standalone' attribute in StaxEventItemWriter

Issue #758
This commit is contained in:
Parikshit Dutta
2020-08-20 12:41:05 +05:30
committed by Mahmoud Ben Hassine
parent b309ddc0a9
commit d65203e2d3
5 changed files with 189 additions and 12 deletions

View File

@@ -94,7 +94,7 @@ allprojects {
servletApiVersion = '4.0.1'
sqlfireclientVersion = '1.0.3'
sqliteVersion = '3.32.3.2'
woodstoxVersion = '6.2.0'
woodstoxVersion = '6.2.1'
xmlunitVersion = '2.7.0'
xstreamVersion = '1.4.12'
jrubyVersion = '1.7.27'

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2017 the original author or authors.
* Copyright 2006-2020 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.
@@ -72,7 +72,7 @@ import org.springframework.util.StringUtils;
* @author Peter Zozom
* @author Robert Kasanicky
* @author Michael Minella
*
* @author Parikshit Dutta
*/
public class StaxEventItemWriter<T> extends AbstractItemStreamItemWriter<T> implements
ResourceAwareItemWriterItemStream<T>, InitializingBean {
@@ -85,6 +85,9 @@ ResourceAwareItemWriterItemStream<T>, InitializingBean {
// default encoding
public static final String DEFAULT_XML_VERSION = "1.0";
// default standalone document declaration, value not set
public static final Boolean DEFAULT_STANDALONE_DOCUMENT = null;
// default root tag name
public static final String DEFAULT_ROOT_TAG_NAME = "root";
@@ -109,6 +112,9 @@ ResourceAwareItemWriterItemStream<T>, InitializingBean {
// XML version
private String version = DEFAULT_XML_VERSION;
// standalone header attribute
private Boolean standalone = DEFAULT_STANDALONE_DOCUMENT;
// name of the root tag
private String rootTagName = DEFAULT_ROOT_TAG_NAME;
@@ -270,6 +276,29 @@ ResourceAwareItemWriterItemStream<T>, InitializingBean {
this.version = version;
}
/**
* Get used standalone document declaration.
*
* @return the standalone document declaration used
*
* @since 4.3
*/
public Boolean getStandalone() {
return standalone;
}
/**
* Set standalone document declaration to be used for output XML. If not set,
* standalone document declaration will be omitted.
*
* @param standalone the XML standalone document declaration to be used
*
* @since 4.3
*/
public void setStandalone(Boolean standalone) {
this.standalone = standalone;
}
/**
* Get the tag name of the root element.
*
@@ -606,7 +635,12 @@ ResourceAwareItemWriterItemStream<T>, InitializingBean {
XMLEventFactory factory = createXmlEventFactory();
// write start document
writer.add(factory.createStartDocument(getEncoding(), getVersion()));
if (getStandalone()==null) {
writer.add(factory.createStartDocument(getEncoding(), getVersion()));
}
else {
writer.add(factory.createStartDocument(getEncoding(), getVersion(), getStandalone()));
}
// write root tag
writer.add(factory.createStartElement(getRootTagNamespacePrefix(), getRootTagNamespace(), getRootTagName()));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2020 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.
@@ -27,6 +27,7 @@ import org.springframework.util.Assert;
* A builder for the {@link StaxEventItemWriter}.
*
* @author Michael Minella
* @author Parikshit Dutta
* @since 4.0
* @see StaxEventItemWriter
*/
@@ -50,6 +51,8 @@ public class StaxEventItemWriterBuilder<T> {
private String version = StaxEventItemWriter.DEFAULT_XML_VERSION;
private Boolean standalone = StaxEventItemWriter.DEFAULT_STANDALONE_DOCUMENT;
private String rootTagName = StaxEventItemWriter.DEFAULT_ROOT_TAG_NAME;
private Map<String, String> rootElementAttributes;
@@ -188,7 +191,7 @@ public class StaxEventItemWriterBuilder<T> {
*
* @param version XML version
* @return the current instance of the builder
* @see StaxEventItemWriter#version
* @see StaxEventItemWriter#setVersion(String)
*/
public StaxEventItemWriterBuilder<T> version(String version) {
this.version = version;
@@ -196,6 +199,21 @@ public class StaxEventItemWriterBuilder<T> {
return this;
}
/**
* Standalone document declaration for the output document. Defaults to null.
*
* @param standalone Boolean standalone document declaration
* @return the current instance of the builder
* @see StaxEventItemWriter#setStandalone(Boolean)
*
* @since 4.3
*/
public StaxEventItemWriterBuilder<T> standalone(Boolean standalone) {
this.standalone = standalone;
return this;
}
/**
* The name of the root tag for the output document.
*
@@ -278,6 +296,7 @@ public class StaxEventItemWriterBuilder<T> {
writer.setTransactional(this.transactional);
writer.setVersion(this.version);
writer.setName(this.name);
writer.setStandalone(this.standalone);
return writer;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2014 the original author or authors.
* Copyright 2008-2020 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.
@@ -55,6 +55,8 @@ import static org.mockito.Mockito.when;
/**
* Tests for {@link StaxEventItemWriter}.
*
* @author Parikshit Dutta
*/
public class StaxEventItemWriterTests {
@@ -137,6 +139,35 @@ public class StaxEventItemWriterTests {
writer.write(Collections.singletonList("foo"));
}
@Test
public void testStandaloneDeclarationInHeaderWhenNotSet() throws Exception {
writer.open(executionContext);
writer.write(items);
writer.close();
String content = getOutputFileContent(writer.getEncoding(), false);
assertFalse(content.contains("standalone="));
}
@Test
public void testStandaloneDeclarationInHeaderWhenSetToTrue() throws Exception {
writer.setStandalone(true);
writer.open(executionContext);
writer.write(items);
writer.close();
String content = getOutputFileContent(writer.getEncoding(), false);
assertTrue(content.contains("standalone='yes'"));
}
@Test
public void testStandaloneDeclarationInHeaderWhenSetToFalse() throws Exception {
writer.setStandalone(false);
writer.open(executionContext);
writer.write(items);
writer.close();
String content = getOutputFileContent(writer.getEncoding(), false);
assertTrue(content.contains("standalone='no'"));
}
/**
* Item is written to the output file only after flush.
*/
@@ -982,11 +1013,27 @@ public class StaxEventItemWriterTests {
* @return output file content as String
*/
private String getOutputFileContent(String encoding) throws IOException {
String value = FileUtils.readFileToString(resource.getFile(), encoding);
value = value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
return value;
return getOutputFileContent(encoding, true);
}
/**
* @param encoding the encoding
* @param discardHeader the flag to strip XML header
* @return output file content as String
*/
private String getOutputFileContent(String encoding, boolean discardHeader) throws IOException {
String value = FileUtils.readFileToString(resource.getFile(), encoding);
if (discardHeader) {
// standalone is omitted if not explicitly set, meaning it will be 'yes'/'no' or no standalone attribute
if (value.contains("standalone")) {
boolean standalone = value.contains("standalone='yes'");
return value.replace("<?xml version='1.0' encoding='" + encoding + "' " +
(standalone ? "standalone='yes'" : "standalone='no'") + "?>", "");
}
return value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
}
return value;
}
/**
* @return new instance of fully configured writer

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2020 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.
@@ -46,6 +46,7 @@ import static org.junit.Assert.assertTrue;
/**
* @author Michael Minella
* @author Parikshit Dutta
*/
public class StaxEventItemWriterBuilderTests {
@@ -224,9 +225,85 @@ public class StaxEventItemWriterBuilderTests {
.build();
}
@Test
public void testStandaloneDeclarationInHeaderWhenNotSet() throws Exception {
StaxEventItemWriter<Foo> staxEventItemWriter = new StaxEventItemWriterBuilder<Foo>()
.name("fooWriter")
.marshaller(marshaller)
.resource(this.resource)
.build();
staxEventItemWriter.afterPropertiesSet();
ExecutionContext executionContext = new ExecutionContext();
staxEventItemWriter.open(executionContext);
staxEventItemWriter.write(this.items);
staxEventItemWriter.close();
String output = getOutputFileContent(staxEventItemWriter.getEncoding(), false);
assertFalse(output.contains("standalone="));
}
@Test
public void testStandaloneDeclarationInHeaderWhenSetToTrue() throws Exception {
StaxEventItemWriter<Foo> staxEventItemWriter = new StaxEventItemWriterBuilder<Foo>()
.name("fooWriter")
.marshaller(marshaller)
.resource(this.resource)
.standalone(true)
.build();
staxEventItemWriter.afterPropertiesSet();
ExecutionContext executionContext = new ExecutionContext();
staxEventItemWriter.open(executionContext);
staxEventItemWriter.write(this.items);
staxEventItemWriter.close();
String output = getOutputFileContent(staxEventItemWriter.getEncoding(), false);
assertTrue(output.contains("standalone='yes'"));
}
@Test
public void testStandaloneDeclarationInHeaderWhenSetToFalse() throws Exception {
StaxEventItemWriter<Foo> staxEventItemWriter = new StaxEventItemWriterBuilder<Foo>()
.name("fooWriter")
.marshaller(marshaller)
.resource(this.resource)
.standalone(false)
.build();
staxEventItemWriter.afterPropertiesSet();
ExecutionContext executionContext = new ExecutionContext();
staxEventItemWriter.open(executionContext);
staxEventItemWriter.write(this.items);
staxEventItemWriter.close();
String output = getOutputFileContent(staxEventItemWriter.getEncoding(), false);
assertTrue(output.contains("standalone='no'"));
}
private String getOutputFileContent(String encoding) throws IOException {
return getOutputFileContent(encoding, true);
}
/**
* @param encoding the encoding
* @param discardHeader the flag to strip XML header
* @return output file content as String
*/
private String getOutputFileContent(String encoding, boolean discardHeader) throws IOException {
String value = FileUtils.readFileToString(resource.getFile(), encoding);
value = value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
if (discardHeader) {
// standalone is omitted if not explicitly set, meaning it will be 'yes'/'no' or no standalone attribute
if (value.contains("standalone")) {
boolean standalone = value.contains("standalone='yes'");
return value.replace("<?xml version='1.0' encoding='" + encoding + "' " +
(standalone ? "standalone='yes'" : "standalone='no'") + "?>", "");
}
return value.replace("<?xml version='1.0' encoding='" + encoding + "'?>", "");
}
return value;
}