Browse Source

Merge branch '5.2.x'

pull/25021/head
Sam Brannen 6 years ago
parent
commit
4ca64684f6
  1. 20
      spring-oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java
  2. 102
      spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java

20
spring-oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 @@ -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 @@ -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;
}

102
spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java

@ -1,5 +1,5 @@ @@ -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; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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();
}
}

Loading…
Cancel
Save