Add marshalling hooks in Jaxb2RootElementHttpMessageConverter
Allow Jaxb2RootElementHttpMessageConverter subclasses to customize the {@link Marshaller} and the {@link Unmarshaller} created by the message converter. Issue: SPR-11488
This commit is contained in:
parent
474142a862
commit
45be8c0692
|
@ -28,7 +28,6 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
|
@ -39,7 +38,6 @@ import org.springframework.http.converter.HttpMessageConversionException;
|
|||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.xml.StaxUtils;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
@ -53,6 +51,7 @@ import org.xml.sax.helpers.XMLReaderFactory;
|
|||
* annotated with with {@link XmlRootElement}, or subclasses thereof.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
* @since 3.0
|
||||
*/
|
||||
public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessageConverter<Object> {
|
||||
|
@ -90,6 +89,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
|
|||
try {
|
||||
source = processSource(source);
|
||||
Unmarshaller unmarshaller = createUnmarshaller(clazz);
|
||||
this.customizeUnmarshaller(unmarshaller);
|
||||
if (clazz.isAnnotationPresent(XmlRootElement.class)) {
|
||||
return unmarshaller.unmarshal(source);
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
|
|||
try {
|
||||
Class<?> clazz = ClassUtils.getUserClass(o);
|
||||
Marshaller marshaller = createMarshaller(clazz);
|
||||
this.customizeMarshaller(marshaller);
|
||||
setCharset(headers.getContentType(), marshaller);
|
||||
marshaller.marshal(o, result);
|
||||
}
|
||||
|
@ -149,4 +150,26 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the {@link Marshaller} created by this
|
||||
* message converter before using it to write the object to the output.
|
||||
* @param marshaller the marshaller to customize
|
||||
* @see #createMarshaller(Class)
|
||||
* @since 4.0.3
|
||||
*/
|
||||
protected void customizeMarshaller(Marshaller marshaller) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the {@link Unmarshaller} created by this
|
||||
* message converter before using it to read the object from the input.
|
||||
* @param unmarshaller the unmarshaller to customize
|
||||
* @see #createUnmarshaller(Class)
|
||||
* @since 4.0.3
|
||||
*/
|
||||
protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,15 +17,20 @@
|
|||
package org.springframework.http.converter.xml;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import static org.custommonkey.xmlunit.XMLAssert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -37,10 +42,13 @@ import org.springframework.core.io.Resource;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MockHttpInputMessage;
|
||||
import org.springframework.http.MockHttpOutputMessage;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
/**
|
||||
* Tests for {@link Jaxb2RootElementHttpMessageConverter}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class Jaxb2RootElementHttpMessageConverterTests {
|
||||
|
||||
private Jaxb2RootElementHttpMessageConverter converter;
|
||||
|
@ -146,6 +154,25 @@ public class Jaxb2RootElementHttpMessageConverterTests {
|
|||
outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customizeMarshaller() throws Exception {
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
MyJaxb2RootElementHttpMessageConverter myConverter = new MyJaxb2RootElementHttpMessageConverter();
|
||||
myConverter.write(new MyRootElement(new MyCustomElement("a", "b")), null, outputMessage);
|
||||
assertXMLEqual("Invalid result", "<myRootElement><element>a|||b</element></myRootElement>",
|
||||
outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customizeUnmarshaller() throws Exception {
|
||||
byte[] body = "<myRootElement><element>a|||b</element></myRootElement>".getBytes("UTF-8");
|
||||
MyJaxb2RootElementHttpMessageConverter myConverter = new MyJaxb2RootElementHttpMessageConverter();
|
||||
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body);
|
||||
MyRootElement result = (MyRootElement) myConverter.read(MyRootElement.class, inputMessage);
|
||||
assertEquals("a", result.getElement().getField1());
|
||||
assertEquals("b", result.getElement().getField2());
|
||||
}
|
||||
|
||||
@XmlRootElement
|
||||
public static class RootElement {
|
||||
|
||||
|
@ -176,4 +203,84 @@ public class Jaxb2RootElementHttpMessageConverterTests {
|
|||
|
||||
}
|
||||
|
||||
public static class MyJaxb2RootElementHttpMessageConverter extends Jaxb2RootElementHttpMessageConverter {
|
||||
|
||||
@Override
|
||||
protected void customizeMarshaller(Marshaller marshaller) {
|
||||
marshaller.setAdapter(new MyCustomElementAdapter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
|
||||
unmarshaller.setAdapter(new MyCustomElementAdapter());
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyCustomElement {
|
||||
private String field1;
|
||||
private String field2;
|
||||
|
||||
public MyCustomElement() {
|
||||
}
|
||||
|
||||
public MyCustomElement(String field1, String field2) {
|
||||
this.field1 = field1;
|
||||
this.field2 = field2;
|
||||
}
|
||||
|
||||
public String getField1() {
|
||||
return field1;
|
||||
}
|
||||
|
||||
public void setField1(String field1) {
|
||||
this.field1 = field1;
|
||||
}
|
||||
|
||||
public String getField2() {
|
||||
return field2;
|
||||
}
|
||||
|
||||
public void setField2(String field2) {
|
||||
this.field2 = field2;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlRootElement
|
||||
public static class MyRootElement {
|
||||
|
||||
private MyCustomElement element;
|
||||
|
||||
public MyRootElement() {
|
||||
|
||||
}
|
||||
|
||||
public MyRootElement(MyCustomElement element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
@XmlJavaTypeAdapter(MyCustomElementAdapter.class)
|
||||
public MyCustomElement getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public void setElement(MyCustomElement element) {
|
||||
this.element = element;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyCustomElementAdapter extends XmlAdapter<String, MyCustomElement> {
|
||||
|
||||
@Override
|
||||
public String marshal(MyCustomElement c) throws Exception {
|
||||
return c.getField1() + "|||" + c.getField2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyCustomElement unmarshal(String c) throws Exception {
|
||||
String[] t = c.split("\\|\\|\\|");
|
||||
return new MyCustomElement(t[0], t[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue