Skip to content

Commit 9c931f6

Browse files
committed
Convenient configuration of type permissions for XStream 1.4.18
Closes gh-27343 (cherry picked from commit 837301f)
1 parent b7e6169 commit 9c931f6

File tree

3 files changed

+55
-18
lines changed

3 files changed

+55
-18
lines changed

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -64,6 +64,8 @@
6464
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
6565
import com.thoughtworks.xstream.mapper.Mapper;
6666
import com.thoughtworks.xstream.mapper.MapperWrapper;
67+
import com.thoughtworks.xstream.security.ForbiddenClassException;
68+
import com.thoughtworks.xstream.security.TypePermission;
6769
import org.w3c.dom.Document;
6870
import org.w3c.dom.Element;
6971
import org.w3c.dom.Node;
@@ -106,7 +108,7 @@
106108
* Therefore, it has limited namespace support. As such, it is rather unsuitable for
107109
* usage within Web Services.
108110
*
109-
* <p>This marshaller requires XStream 1.4.5 or higher, as of Spring 4.3.
111+
* <p>This marshaller requires XStream 1.4.7 or higher, as of Spring 5.2.17.
110112
* Note that {@link XStream} construction has been reworked in 4.0, with the
111113
* stream driver and the class loader getting passed into XStream itself now.
112114
*
@@ -146,6 +148,9 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
146148
@Nullable
147149
private ConverterMatcher[] converters;
148150

151+
@Nullable
152+
private TypePermission[] typePermissions;
153+
149154
@Nullable
150155
private MarshallingStrategy marshallingStrategy;
151156

@@ -268,6 +273,20 @@ public void setConverters(ConverterMatcher... converters) {
268273
this.converters = converters;
269274
}
270275

276+
/**
277+
* Set XStream type permissions such as
278+
* {@link com.thoughtworks.xstream.security.AnyTypePermission},
279+
* {@link com.thoughtworks.xstream.security.ExplicitTypePermission} etc,
280+
* as an alternative to overriding the {@link #customizeXStream} method.
281+
* <p>Note: As of XStream 1.4.18, the default type permissions are
282+
* restricted to well-known core JDK types. For any custom types,
283+
* explicit type permissions need to be registered.
284+
* @since 5.2.17
285+
*/
286+
public void setTypePermissions(TypePermission... typePermissions) {
287+
this.typePermissions = typePermissions;
288+
}
289+
271290
/**
272291
* Set a custom XStream {@link MarshallingStrategy} to use.
273292
* @since 4.0
@@ -407,7 +426,7 @@ public void setBeanClassLoader(ClassLoader classLoader) {
407426

408427
@Override
409428
public void afterPropertiesSet() {
410-
// no-op due to use of SingletonSupplier for the XStream field.
429+
// no-op due to use of SingletonSupplier for the XStream field
411430
}
412431

413432
/**
@@ -479,6 +498,12 @@ else if (this.converters[i] instanceof SingleValueConverter) {
479498
}
480499
}
481500

501+
if (this.typePermissions != null) {
502+
for (TypePermission permission : this.typePermissions) {
503+
xstream.addPermission(permission);
504+
}
505+
}
506+
482507
if (this.marshallingStrategy != null) {
483508
xstream.setMarshallingStrategy(this.marshallingStrategy);
484509
}
@@ -844,7 +869,7 @@ private Object doUnmarshal(HierarchicalStreamReader streamReader, @Nullable Data
844869
*/
845870
protected XmlMappingException convertXStreamException(Exception ex, boolean marshalling) {
846871
if (ex instanceof StreamException || ex instanceof CannotResolveClassException ||
847-
ex instanceof ConversionException) {
872+
ex instanceof ForbiddenClassException || ex instanceof ConversionException) {
848873
if (marshalling) {
849874
return new MarshallingFailureException("XStream marshalling exception", ex);
850875
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -43,6 +43,7 @@
4343
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
4444
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
4545
import com.thoughtworks.xstream.io.json.JsonWriter;
46+
import com.thoughtworks.xstream.security.AnyTypePermission;
4647
import org.junit.jupiter.api.BeforeEach;
4748
import org.junit.jupiter.api.Test;
4849
import org.mockito.InOrder;
@@ -67,18 +68,21 @@
6768
/**
6869
* @author Arjen Poutsma
6970
* @author Sam Brannen
71+
* @author Juergen Hoeller
7072
*/
7173
class XStreamMarshallerTests {
7274

7375
private static final String EXPECTED_STRING = "<flight><flightNumber>42</flightNumber></flight>";
7476

75-
private final XStreamMarshaller marshaller = new XStreamMarshaller();
76-
7777
private final Flight flight = new Flight();
7878

79+
private XStreamMarshaller marshaller;
80+
7981

8082
@BeforeEach
8183
void createMarshaller() {
84+
marshaller = new XStreamMarshaller();
85+
marshaller.setTypePermissions(AnyTypePermission.ANY);
8286
marshaller.setAliases(Collections.singletonMap("flight", Flight.class.getName()));
8387
flight.setFlightNumber(42L);
8488
}
@@ -143,7 +147,7 @@ void marshalStreamResultOutputStream() throws Exception {
143147
ByteArrayOutputStream os = new ByteArrayOutputStream();
144148
StreamResult result = new StreamResult(os);
145149
marshaller.marshal(flight, result);
146-
String s = new String(os.toByteArray(), "UTF-8");
150+
String s = os.toString("UTF-8");
147151
assertThat(XmlContent.of(s)).isSimilarTo(EXPECTED_STRING);
148152
}
149153

spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTests.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 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.
@@ -18,6 +18,7 @@
1818

1919
import java.io.ByteArrayInputStream;
2020
import java.io.StringReader;
21+
import java.nio.charset.StandardCharsets;
2122
import java.util.HashMap;
2223
import java.util.Map;
2324

@@ -29,6 +30,7 @@
2930
import javax.xml.transform.dom.DOMSource;
3031
import javax.xml.transform.stream.StreamSource;
3132

33+
import com.thoughtworks.xstream.security.AnyTypePermission;
3234
import org.junit.jupiter.api.BeforeEach;
3335
import org.junit.jupiter.api.Test;
3436
import org.w3c.dom.Document;
@@ -40,28 +42,24 @@
4042

4143
/**
4244
* @author Arjen Poutsma
45+
* @author Juergen Hoeller
4346
*/
4447
public class XStreamUnmarshallerTests {
4548

4649
protected static final String INPUT_STRING = "<flight><flightNumber>42</flightNumber></flight>";
4750

4851
private XStreamMarshaller unmarshaller;
4952

53+
5054
@BeforeEach
51-
public void createUnmarshaller() throws Exception {
55+
public void createUnmarshaller() {
5256
unmarshaller = new XStreamMarshaller();
57+
unmarshaller.setTypePermissions(AnyTypePermission.ANY);
5358
Map<String, Class<?>> aliases = new HashMap<>();
5459
aliases.put("flight", Flight.class);
5560
unmarshaller.setAliases(aliases);
5661
}
5762

58-
private void testFlight(Object o) {
59-
boolean condition = o instanceof Flight;
60-
assertThat(condition).as("Unmarshalled object is not Flights").isTrue();
61-
Flight flight = (Flight) o;
62-
assertThat(flight).as("Flight is null").isNotNull();
63-
assertThat(flight.getFlightNumber()).as("Number is invalid").isEqualTo(42L);
64-
}
6563

6664
@Test
6765
public void unmarshalDomSource() throws Exception {
@@ -83,7 +81,7 @@ public void unmarshalStaxSourceXmlStreamReader() throws Exception {
8381

8482
@Test
8583
public void unmarshalStreamSourceInputStream() throws Exception {
86-
StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes("UTF-8")));
84+
StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes(StandardCharsets.UTF_8)));
8785
Object flights = unmarshaller.unmarshal(source);
8886
testFlight(flights);
8987
}
@@ -94,5 +92,15 @@ public void unmarshalStreamSourceReader() throws Exception {
9492
Object flights = unmarshaller.unmarshal(source);
9593
testFlight(flights);
9694
}
95+
96+
97+
private void testFlight(Object o) {
98+
boolean condition = o instanceof Flight;
99+
assertThat(condition).as("Unmarshalled object is not Flights").isTrue();
100+
Flight flight = (Flight) o;
101+
assertThat(flight).as("Flight is null").isNotNull();
102+
assertThat(flight.getFlightNumber()).as("Number is invalid").isEqualTo(42L);
103+
}
104+
97105
}
98106

0 commit comments

Comments
 (0)