Browse Source

SPR-7636 - XStreamMarshaller - Add support for configuring XStream with aliases by class (type) and also defining multiple attributes for the same class.

3.0.x
Arjen Poutsma 15 years ago
parent
commit
043ec2c8b2
  1. 83
      org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java
  2. 24
      org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/FlightSubclass.java
  3. 38
      org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java

83
org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java

@ -23,6 +23,8 @@ import java.io.OutputStream; @@ -23,6 +23,8 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
@ -152,20 +154,48 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin @@ -152,20 +154,48 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
* @see XStream#alias(String, Class)
*/
public void setAliases(Map<String, ?> aliases) throws ClassNotFoundException {
for (Map.Entry<String, ?> entry : aliases.entrySet()) {
String alias = entry.getKey();
Map<String, Class<?>> classMap = toClassMap(aliases);
for (Map.Entry<String, Class<?>> entry : classMap.entrySet()) {
this.getXStream().alias(entry.getKey(), entry.getValue());
}
}
/**
* Sets the aliases by type map, consisting of string aliases mapped to classes. Any class that is assignable to
* this type will be aliased to the same name. Keys are aliases; values are either
* {@code Class} instances, or String class names.
*
* @see XStream#aliasType(String, Class)
*/
public void setAliasesByType(Map<String, ?> aliases) throws ClassNotFoundException {
Map<String, Class<?>> classMap = toClassMap(aliases);
for (Map.Entry<String, Class<?>> entry : classMap.entrySet()) {
this.getXStream().aliasType(entry.getKey(), entry.getValue());
}
}
private Map<String, Class<?>> toClassMap(Map<String, ?> map) throws ClassNotFoundException {
Map<String, Class<?>> result = new LinkedHashMap<String, Class<?>>(map.size());
for (Map.Entry<String, ?> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
Class type;
if (value instanceof Class) {
type = (Class) value;
} else if (value instanceof String) {
}
else if (value instanceof String) {
String s = (String) value;
type = ClassUtils.forName(s, classLoader);
} else {
}
else {
throw new IllegalArgumentException("Unknown value [" + value + "], expected String or Class");
}
this.getXStream().alias(alias, type);
result.put(key, type);
}
return result;
}
/**
@ -203,22 +233,47 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin @@ -203,22 +233,47 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
/**
* Set the types to use XML attributes for. The given map can contain
* either <code>&lt;String, Class&gt;</code> pairs, in which case
* {@link XStream#useAttributeFor(String, Class)} is called,
* or <code>&lt;Class, String&gt;</code> pairs, which results in
* either {@code <String, Class>} pairs, in which case
* {@link XStream#useAttributeFor(String, Class)} is called.
* Alternatively, the map can contain {@code <Class, String>}
* or {@code <Class, List<String>>} pairs, which results in
* {@link XStream#useAttributeFor(Class, String)} calls.
*/
public void setUseAttributeFor(Map<?, ?> attributes) {
for (Map.Entry<?, ?> entry : attributes.entrySet()) {
if (entry.getKey() instanceof String && entry.getValue() instanceof Class) {
this.getXStream().useAttributeFor((String) entry.getKey(), (Class) entry.getValue());
if (entry.getKey() instanceof String) {
if (entry.getValue() instanceof Class) {
this.getXStream().useAttributeFor((String) entry.getKey(), (Class) entry.getValue());
}
else {
throw new IllegalArgumentException(
"Invalid argument 'attributes'. 'useAttributesFor' property takes map of <String, Class>," +
" when using a map key of type String");
}
}
else if (entry.getKey() instanceof Class && entry.getValue() instanceof String) {
this.getXStream().useAttributeFor((Class) entry.getKey(), (String) entry.getValue());
else if (entry.getKey() instanceof Class) {
Class<?> key = (Class<?>) entry.getKey();
if (entry.getValue() instanceof String) {
this.getXStream().useAttributeFor(key, (String) entry.getValue());
}
else if (entry.getValue() instanceof List) {
List list = (List) entry.getValue();
for (Object o : list) {
if (o instanceof String) {
this.getXStream().useAttributeFor(key, (String) o);
}
}
}
else {
throw new IllegalArgumentException("Invalid argument 'attributes'. " +
"'useAttributesFor' property takes either <Class, String> or <Class, List<String>> map," +
" when using a map key of type Class");
}
}
else {
throw new IllegalArgumentException("Invalid attribute key and value pair. " +
"'useAttributesFor' property takes either a <String, Class> map or a <Class, String> map");
throw new IllegalArgumentException("Invalid argument 'attributes. " +
"'useAttributesFor' property takes either a map key of type String or Class");
}
}
}

24
org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/FlightSubclass.java

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
/*
* Copyright 2002-2010 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.oxm.xstream;
/**
* @author Arjen Poutsma
*/
public class FlightSubclass extends Flight {
}

38
org.springframework.oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java

@ -217,6 +217,42 @@ public class XStreamMarshallerTests { @@ -217,6 +217,42 @@ public class XStreamMarshallerTests {
assertXMLEqual("Marshaller does not use attributes", expected, writer.toString());
}
@Test
public void useAttributesForClassStringListMap() throws Exception {
marshaller
.setUseAttributeFor(Collections.singletonMap(Flight.class, Collections.singletonList("flightNumber")));
Writer writer = new StringWriter();
marshaller.marshal(flight, new StreamResult(writer));
String expected = "<flight flightNumber=\"42\" />";
assertXMLEqual("Marshaller does not use attributes", expected, writer.toString());
}
@Test
public void aliasesByTypeStringClassMap() throws Exception {
Map<String, Class<?>> aliases = new HashMap<String, Class<?>>();
aliases.put("flight", Flight.class);
FlightSubclass flight = new FlightSubclass();
flight.setFlightNumber(42);
marshaller.setAliasesByType(aliases);
Writer writer = new StringWriter();
marshaller.marshal(flight, new StreamResult(writer));
assertXMLEqual("Marshaller does not use attributes", EXPECTED_STRING, writer.toString());
}
@Test
public void aliasesByTypeStringStringMap() throws Exception {
Map<String, String> aliases = new HashMap<String, String>();
aliases.put("flight", Flight.class.getName());
FlightSubclass flight = new FlightSubclass();
flight.setFlightNumber(42);
marshaller.setAliasesByType(aliases);
Writer writer = new StringWriter();
marshaller.marshal(flight, new StreamResult(writer));
assertXMLEqual("Marshaller does not use attributes", EXPECTED_STRING, writer.toString());
}
@Test
public void fieldAliases() throws Exception {
marshaller.setFieldAliases(Collections.singletonMap("org.springframework.oxm.xstream.Flight.flightNumber", "flightNo"));
@ -288,7 +324,7 @@ public class XStreamMarshallerTests { @@ -288,7 +324,7 @@ public class XStreamMarshallerTests {
}
@Test
public void testAnnotatedMarshalStreamResultWriter() throws Exception {
public void annotatedMarshalStreamResultWriter() throws Exception {
marshaller.setAnnotatedClass(Flight.class);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);

Loading…
Cancel
Save