Convenient configuration of type permissions for XStream 1.4.18
Closes gh-27343
This commit is contained in:
parent
164dcef6ae
commit
837301fdb3
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2020 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -63,6 +63,8 @@ import com.thoughtworks.xstream.io.xml.XppDriver;
|
||||||
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
|
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
|
||||||
import com.thoughtworks.xstream.mapper.Mapper;
|
import com.thoughtworks.xstream.mapper.Mapper;
|
||||||
import com.thoughtworks.xstream.mapper.MapperWrapper;
|
import com.thoughtworks.xstream.mapper.MapperWrapper;
|
||||||
|
import com.thoughtworks.xstream.security.ForbiddenClassException;
|
||||||
|
import com.thoughtworks.xstream.security.TypePermission;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
@ -106,7 +108,7 @@ import org.springframework.util.xml.StaxUtils;
|
||||||
* Therefore, it has limited namespace support. As such, it is rather unsuitable for
|
* Therefore, it has limited namespace support. As such, it is rather unsuitable for
|
||||||
* usage within Web Services.
|
* usage within Web Services.
|
||||||
*
|
*
|
||||||
* <p>This marshaller requires XStream 1.4.5 or higher, as of Spring 4.3.
|
* <p>This marshaller requires XStream 1.4.7 or higher, as of Spring 5.2.17.
|
||||||
* Note that {@link XStream} construction has been reworked in 4.0, with the
|
* Note that {@link XStream} construction has been reworked in 4.0, with the
|
||||||
* stream driver and the class loader getting passed into XStream itself now.
|
* stream driver and the class loader getting passed into XStream itself now.
|
||||||
*
|
*
|
||||||
|
@ -146,6 +148,9 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
|
||||||
@Nullable
|
@Nullable
|
||||||
private ConverterMatcher[] converters;
|
private ConverterMatcher[] converters;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private TypePermission[] typePermissions;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MarshallingStrategy marshallingStrategy;
|
private MarshallingStrategy marshallingStrategy;
|
||||||
|
|
||||||
|
@ -268,6 +273,20 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
|
||||||
this.converters = converters;
|
this.converters = converters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set XStream type permissions such as
|
||||||
|
* {@link com.thoughtworks.xstream.security.AnyTypePermission},
|
||||||
|
* {@link com.thoughtworks.xstream.security.ExplicitTypePermission} etc,
|
||||||
|
* as an alternative to overriding the {@link #customizeXStream} method.
|
||||||
|
* <p>Note: As of XStream 1.4.18, the default type permissions are
|
||||||
|
* restricted to well-known core JDK types. For any custom types,
|
||||||
|
* explicit type permissions need to be registered.
|
||||||
|
* @since 5.2.17
|
||||||
|
*/
|
||||||
|
public void setTypePermissions(TypePermission... typePermissions) {
|
||||||
|
this.typePermissions = typePermissions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a custom XStream {@link MarshallingStrategy} to use.
|
* Set a custom XStream {@link MarshallingStrategy} to use.
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
|
@ -407,7 +426,7 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
// no-op due to use of SingletonSupplier for the XStream field.
|
// no-op due to use of SingletonSupplier for the XStream field
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -479,6 +498,12 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.typePermissions != null) {
|
||||||
|
for (TypePermission permission : this.typePermissions) {
|
||||||
|
xstream.addPermission(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.marshallingStrategy != null) {
|
if (this.marshallingStrategy != null) {
|
||||||
xstream.setMarshallingStrategy(this.marshallingStrategy);
|
xstream.setMarshallingStrategy(this.marshallingStrategy);
|
||||||
}
|
}
|
||||||
|
@ -844,7 +869,7 @@ public class XStreamMarshaller extends AbstractMarshaller implements BeanClassLo
|
||||||
*/
|
*/
|
||||||
protected XmlMappingException convertXStreamException(Exception ex, boolean marshalling) {
|
protected XmlMappingException convertXStreamException(Exception ex, boolean marshalling) {
|
||||||
if (ex instanceof StreamException || ex instanceof CannotResolveClassException ||
|
if (ex instanceof StreamException || ex instanceof CannotResolveClassException ||
|
||||||
ex instanceof ConversionException) {
|
ex instanceof ForbiddenClassException || ex instanceof ConversionException) {
|
||||||
if (marshalling) {
|
if (marshalling) {
|
||||||
return new MarshallingFailureException("XStream marshalling exception", ex);
|
return new MarshallingFailureException("XStream marshalling exception", ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2020 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -43,6 +43,7 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||||
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
|
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
|
||||||
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
|
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
|
||||||
import com.thoughtworks.xstream.io.json.JsonWriter;
|
import com.thoughtworks.xstream.io.json.JsonWriter;
|
||||||
|
import com.thoughtworks.xstream.security.AnyTypePermission;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
|
@ -67,18 +68,21 @@ import static org.mockito.Mockito.mock;
|
||||||
/**
|
/**
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
|
* @author Juergen Hoeller
|
||||||
*/
|
*/
|
||||||
class XStreamMarshallerTests {
|
class XStreamMarshallerTests {
|
||||||
|
|
||||||
private static final String EXPECTED_STRING = "<flight><flightNumber>42</flightNumber></flight>";
|
private static final String EXPECTED_STRING = "<flight><flightNumber>42</flightNumber></flight>";
|
||||||
|
|
||||||
private final XStreamMarshaller marshaller = new XStreamMarshaller();
|
|
||||||
|
|
||||||
private final Flight flight = new Flight();
|
private final Flight flight = new Flight();
|
||||||
|
|
||||||
|
private XStreamMarshaller marshaller;
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void createMarshaller() {
|
void createMarshaller() {
|
||||||
|
marshaller = new XStreamMarshaller();
|
||||||
|
marshaller.setTypePermissions(AnyTypePermission.ANY);
|
||||||
marshaller.setAliases(Collections.singletonMap("flight", Flight.class.getName()));
|
marshaller.setAliases(Collections.singletonMap("flight", Flight.class.getName()));
|
||||||
flight.setFlightNumber(42L);
|
flight.setFlightNumber(42L);
|
||||||
}
|
}
|
||||||
|
@ -143,7 +147,7 @@ class XStreamMarshallerTests {
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
StreamResult result = new StreamResult(os);
|
StreamResult result = new StreamResult(os);
|
||||||
marshaller.marshal(flight, result);
|
marshaller.marshal(flight, result);
|
||||||
String s = new String(os.toByteArray(), "UTF-8");
|
String s = os.toString("UTF-8");
|
||||||
assertThat(XmlContent.of(s)).isSimilarTo(EXPECTED_STRING);
|
assertThat(XmlContent.of(s)).isSimilarTo(EXPECTED_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.oxm.xstream;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ import javax.xml.transform.Source;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
|
||||||
|
import com.thoughtworks.xstream.security.AnyTypePermission;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
@ -40,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
|
* @author Juergen Hoeller
|
||||||
*/
|
*/
|
||||||
public class XStreamUnmarshallerTests {
|
public class XStreamUnmarshallerTests {
|
||||||
|
|
||||||
|
@ -47,21 +50,16 @@ public class XStreamUnmarshallerTests {
|
||||||
|
|
||||||
private XStreamMarshaller unmarshaller;
|
private XStreamMarshaller unmarshaller;
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void createUnmarshaller() throws Exception {
|
public void createUnmarshaller() {
|
||||||
unmarshaller = new XStreamMarshaller();
|
unmarshaller = new XStreamMarshaller();
|
||||||
|
unmarshaller.setTypePermissions(AnyTypePermission.ANY);
|
||||||
Map<String, Class<?>> aliases = new HashMap<>();
|
Map<String, Class<?>> aliases = new HashMap<>();
|
||||||
aliases.put("flight", Flight.class);
|
aliases.put("flight", Flight.class);
|
||||||
unmarshaller.setAliases(aliases);
|
unmarshaller.setAliases(aliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testFlight(Object o) {
|
|
||||||
boolean condition = o instanceof Flight;
|
|
||||||
assertThat(condition).as("Unmarshalled object is not Flights").isTrue();
|
|
||||||
Flight flight = (Flight) o;
|
|
||||||
assertThat(flight).as("Flight is null").isNotNull();
|
|
||||||
assertThat(flight.getFlightNumber()).as("Number is invalid").isEqualTo(42L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void unmarshalDomSource() throws Exception {
|
public void unmarshalDomSource() throws Exception {
|
||||||
|
@ -83,7 +81,7 @@ public class XStreamUnmarshallerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void unmarshalStreamSourceInputStream() throws Exception {
|
public void unmarshalStreamSourceInputStream() throws Exception {
|
||||||
StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes("UTF-8")));
|
StreamSource source = new StreamSource(new ByteArrayInputStream(INPUT_STRING.getBytes(StandardCharsets.UTF_8)));
|
||||||
Object flights = unmarshaller.unmarshal(source);
|
Object flights = unmarshaller.unmarshal(source);
|
||||||
testFlight(flights);
|
testFlight(flights);
|
||||||
}
|
}
|
||||||
|
@ -94,5 +92,15 @@ public class XStreamUnmarshallerTests {
|
||||||
Object flights = unmarshaller.unmarshal(source);
|
Object flights = unmarshaller.unmarshal(source);
|
||||||
testFlight(flights);
|
testFlight(flights);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void testFlight(Object o) {
|
||||||
|
boolean condition = o instanceof Flight;
|
||||||
|
assertThat(condition).as("Unmarshalled object is not Flights").isTrue();
|
||||||
|
Flight flight = (Flight) o;
|
||||||
|
assertThat(flight).as("Flight is null").isNotNull();
|
||||||
|
assertThat(flight.getFlightNumber()).as("Number is invalid").isEqualTo(42L);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue