Merge branch '5.2.x'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -113,6 +113,7 @@ import org.springframework.util.xml.StaxUtils;
|
||||
* @author Peter Meijer
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLoaderAware, InitializingBean {
|
||||
@@ -187,7 +188,7 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
|
||||
private ClassLoader beanClassLoader = new CompositeClassLoader();
|
||||
|
||||
@Nullable
|
||||
private XStream xstream;
|
||||
private volatile XStream xstream;
|
||||
|
||||
|
||||
/**
|
||||
@@ -616,12 +617,21 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
|
||||
* <p><b>NOTE: This method has been marked as final as of Spring 4.0.</b>
|
||||
* It can be used to access the fully configured XStream for marshalling
|
||||
* but not configuration purposes anymore.
|
||||
* <p>As of Spring Framework 5.2.7, creation of the {@link XStream} instance
|
||||
* returned by this method is thread safe.
|
||||
*/
|
||||
public final XStream getXStream() {
|
||||
if (this.xstream == null) {
|
||||
this.xstream = buildXStream();
|
||||
XStream xs = this.xstream;
|
||||
if (xs == null) {
|
||||
synchronized (this) {
|
||||
xs = this.xstream;
|
||||
if (xs == null) {
|
||||
xs = buildXStream();
|
||||
this.xstream = xs;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.xstream;
|
||||
return xs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -21,11 +21,10 @@ import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
@@ -69,28 +68,24 @@ import static org.mockito.Mockito.mock;
|
||||
* @author Arjen Poutsma
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class XStreamMarshallerTests {
|
||||
class XStreamMarshallerTests {
|
||||
|
||||
private static final String EXPECTED_STRING = "<flight><flightNumber>42</flightNumber></flight>";
|
||||
|
||||
private XStreamMarshaller marshaller;
|
||||
private final XStreamMarshaller marshaller = new XStreamMarshaller();
|
||||
|
||||
private Flight flight;
|
||||
private final Flight flight = new Flight();
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void createMarshaller() {
|
||||
marshaller = new XStreamMarshaller();
|
||||
Map<String, String> aliases = new HashMap<>();
|
||||
aliases.put("flight", Flight.class.getName());
|
||||
marshaller.setAliases(aliases);
|
||||
flight = new Flight();
|
||||
void createMarshaller() {
|
||||
marshaller.setAliases(Collections.singletonMap("flight", Flight.class.getName()));
|
||||
flight.setFlightNumber(42L);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void marshalDOMResult() throws Exception {
|
||||
void marshalDOMResult() throws Exception {
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document document = builder.newDocument();
|
||||
@@ -108,7 +103,7 @@ public class XStreamMarshallerTests {
|
||||
|
||||
// see SWS-392
|
||||
@Test
|
||||
public void marshalDOMResultToExistentDocument() throws Exception {
|
||||
void marshalDOMResultToExistentDocument() throws Exception {
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document existent = builder.newDocument();
|
||||
@@ -136,7 +131,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalStreamResultWriter() throws Exception {
|
||||
void marshalStreamResultWriter() throws Exception {
|
||||
StringWriter writer = new StringWriter();
|
||||
StreamResult result = new StreamResult(writer);
|
||||
marshaller.marshal(flight, result);
|
||||
@@ -144,7 +139,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalStreamResultOutputStream() throws Exception {
|
||||
void marshalStreamResultOutputStream() throws Exception {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
StreamResult result = new StreamResult(os);
|
||||
marshaller.marshal(flight, result);
|
||||
@@ -153,7 +148,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalSaxResult() throws Exception {
|
||||
void marshalSaxResult() throws Exception {
|
||||
ContentHandler contentHandler = mock(ContentHandler.class);
|
||||
SAXResult result = new SAXResult(contentHandler);
|
||||
marshaller.marshal(flight, result);
|
||||
@@ -168,7 +163,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalStaxResultXMLStreamWriter() throws Exception {
|
||||
void marshalStaxResultXMLStreamWriter() throws Exception {
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
StringWriter writer = new StringWriter();
|
||||
XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(writer);
|
||||
@@ -178,7 +173,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void marshalStaxResultXMLEventWriter() throws Exception {
|
||||
void marshalStaxResultXMLEventWriter() throws Exception {
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
StringWriter writer = new StringWriter();
|
||||
XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);
|
||||
@@ -188,19 +183,29 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converters() throws Exception {
|
||||
void converters() throws Exception {
|
||||
marshaller.setConverters(new EncodedByteArrayConverter());
|
||||
byte[] buf = new byte[]{0x1, 0x2};
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(buf, new StreamResult(writer));
|
||||
assertThat(XmlContent.from(writer)).isSimilarTo("<byte-array>AQI=</byte-array>");
|
||||
Reader reader = new StringReader(writer.toString());
|
||||
byte[] bufResult = (byte[]) marshaller.unmarshal(new StreamSource(reader));
|
||||
assertThat(Arrays.equals(buf, bufResult)).as("Invalid result").isTrue();
|
||||
byte[] buf = {0x1, 0x2};
|
||||
|
||||
// Execute multiple times concurrently to ensure there are no concurrency issues.
|
||||
// See https://github.com/spring-projects/spring-framework/issues/25017
|
||||
IntStream.rangeClosed(1, 100).parallel().forEach(n -> {
|
||||
try {
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(buf, new StreamResult(writer));
|
||||
assertThat(XmlContent.from(writer)).isSimilarTo("<byte-array>AQI=</byte-array>");
|
||||
Reader reader = new StringReader(writer.toString());
|
||||
byte[] bufResult = (byte[]) marshaller.unmarshal(new StreamSource(reader));
|
||||
assertThat(bufResult).as("Invalid result").isEqualTo(buf);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useAttributesFor() throws Exception {
|
||||
void useAttributesFor() throws Exception {
|
||||
marshaller.setUseAttributeForTypes(Long.TYPE);
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flight, new StreamResult(writer));
|
||||
@@ -209,7 +214,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useAttributesForStringClassMap() throws Exception {
|
||||
void useAttributesForStringClassMap() throws Exception {
|
||||
marshaller.setUseAttributeFor(Collections.singletonMap("flightNumber", Long.TYPE));
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flight, new StreamResult(writer));
|
||||
@@ -218,7 +223,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useAttributesForClassStringMap() throws Exception {
|
||||
void useAttributesForClassStringMap() throws Exception {
|
||||
marshaller.setUseAttributeFor(Collections.singletonMap(Flight.class, "flightNumber"));
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flight, new StreamResult(writer));
|
||||
@@ -227,7 +232,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useAttributesForClassStringListMap() throws Exception {
|
||||
void useAttributesForClassStringListMap() throws Exception {
|
||||
marshaller.setUseAttributeFor(Collections.singletonMap(Flight.class, Collections.singletonList("flightNumber")));
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flight, new StreamResult(writer));
|
||||
@@ -236,7 +241,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliasesByTypeStringClassMap() throws Exception {
|
||||
void aliasesByTypeStringClassMap() throws Exception {
|
||||
Map<String, Class<?>> aliases = new HashMap<>();
|
||||
aliases.put("flight", Flight.class);
|
||||
FlightSubclass flight = new FlightSubclass();
|
||||
@@ -249,7 +254,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliasesByTypeStringStringMap() throws Exception {
|
||||
void aliasesByTypeStringStringMap() throws Exception {
|
||||
Map<String, String> aliases = new HashMap<>();
|
||||
aliases.put("flight", Flight.class.getName());
|
||||
FlightSubclass flight = new FlightSubclass();
|
||||
@@ -262,7 +267,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fieldAliases() throws Exception {
|
||||
void fieldAliases() throws Exception {
|
||||
marshaller.setFieldAliases(Collections.singletonMap("org.springframework.oxm.xstream.Flight.flightNumber", "flightNo"));
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flight, new StreamResult(writer));
|
||||
@@ -272,17 +277,17 @@ public class XStreamMarshallerTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void omitFields() throws Exception {
|
||||
void omitFields() throws Exception {
|
||||
Map omittedFieldsMap = Collections.singletonMap(Flight.class, "flightNumber");
|
||||
marshaller.setOmittedFields(omittedFieldsMap);
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flight, new StreamResult(writer));
|
||||
assertXpathNotExists("/flight/flightNumber", writer.toString());
|
||||
assertXpathDoesNotExist("/flight/flightNumber", writer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void implicitCollections() throws Exception {
|
||||
void implicitCollections() throws Exception {
|
||||
Flights flights = new Flights();
|
||||
flights.getFlights().add(flight);
|
||||
flights.getStrings().add("42");
|
||||
@@ -298,14 +303,14 @@ public class XStreamMarshallerTests {
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flights, new StreamResult(writer));
|
||||
String result = writer.toString();
|
||||
assertXpathNotExists("/flights/flights", result);
|
||||
assertXpathDoesNotExist("/flights/flights", result);
|
||||
assertXpathExists("/flights/flight", result);
|
||||
assertXpathNotExists("/flights/strings", result);
|
||||
assertXpathDoesNotExist("/flights/strings", result);
|
||||
assertXpathExists("/flights/string", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jettisonDriver() throws Exception {
|
||||
void jettisonDriver() throws Exception {
|
||||
marshaller.setStreamDriver(new JettisonMappedXmlDriver());
|
||||
Writer writer = new StringWriter();
|
||||
marshaller.marshal(flight, new StreamResult(writer));
|
||||
@@ -318,7 +323,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonDriver() throws Exception {
|
||||
void jsonDriver() throws Exception {
|
||||
marshaller.setStreamDriver(new JsonHierarchicalStreamDriver() {
|
||||
@Override
|
||||
public HierarchicalStreamWriter createWriter(Writer writer) {
|
||||
@@ -334,7 +339,7 @@ public class XStreamMarshallerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annotatedMarshalStreamResultWriter() throws Exception {
|
||||
void annotatedMarshalStreamResultWriter() throws Exception {
|
||||
marshaller.setAnnotatedClasses(Flight.class);
|
||||
StringWriter writer = new StringWriter();
|
||||
StreamResult result = new StreamResult(writer);
|
||||
@@ -349,20 +354,13 @@ public class XStreamMarshallerTests {
|
||||
private static void assertXpathExists(String xPathExpression, String inXMLString){
|
||||
Source source = Input.fromString(inXMLString).build();
|
||||
Iterable<Node> nodes = new JAXPXPathEngine().selectNodes(xPathExpression, source);
|
||||
assertThat(count(nodes) > 0).as("Expecting to find matches for Xpath " + xPathExpression).isTrue();
|
||||
assertThat(nodes).as("Expecting to find matches for Xpath " + xPathExpression).hasSizeGreaterThan(0);
|
||||
}
|
||||
|
||||
private static void assertXpathNotExists(String xPathExpression, String inXMLString){
|
||||
private static void assertXpathDoesNotExist(String xPathExpression, String inXMLString){
|
||||
Source source = Input.fromString(inXMLString).build();
|
||||
Iterable<Node> nodes = new JAXPXPathEngine().selectNodes(xPathExpression, source);
|
||||
assertThat(count(nodes)).as("Should be zero matches for Xpath " + xPathExpression).isEqualTo(0);
|
||||
}
|
||||
|
||||
private static int count(Iterable<Node> nodes) {
|
||||
assertThat(nodes).isNotNull();
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
nodes.forEach(n -> count.incrementAndGet());
|
||||
return count.get();
|
||||
assertThat(nodes).as("Should be zero matches for Xpath " + xPathExpression).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user