From a5e2557738fcdecc2ae5dc1870ff117184e8502c Mon Sep 17 00:00:00 2001 From: Thomas Deblock Date: Thu, 18 Jul 2024 18:11:13 +0200 Subject: [PATCH 1/2] Support JAXBElement in Jaxb2RootElementHttpMessageConverter See gh-33233 --- .../Jaxb2RootElementHttpMessageConverter.java | 13 +++++++++++-- ...xb2RootElementHttpMessageConverterTests.java | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java index dda603995a1..9bd7b646721 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java @@ -121,7 +121,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @Override public boolean canWrite(Class clazz, @Nullable MediaType mediaType) { - return (AnnotationUtils.findAnnotation(clazz, XmlRootElement.class) != null && canWrite(mediaType)); + return ((JAXBElement.class.isAssignableFrom(clazz) || AnnotationUtils.findAnnotation(clazz, XmlRootElement.class) != null) && canWrite(mediaType)); } @Override @@ -192,7 +192,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @Override protected void writeToResult(Object o, HttpHeaders headers, Result result) throws Exception { try { - Class clazz = ClassUtils.getUserClass(o); + Class clazz = getMarshallerType(o); Marshaller marshaller = createMarshaller(clazz); setCharset(headers.getContentType(), marshaller); marshaller.marshal(o, result); @@ -205,6 +205,15 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa } } + private static Class getMarshallerType(Object o) { + if (o instanceof JAXBElement jaxbElement) { + return jaxbElement.getDeclaredType(); + } + else { + return ClassUtils.getUserClass(o); + } + } + private void setCharset(@Nullable MediaType contentType, Marshaller marshaller) throws PropertyException { if (contentType != null && contentType.getCharset() != null) { marshaller.setProperty(Marshaller.JAXB_ENCODING, contentType.getCharset().name()); diff --git a/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java index a54aeb77946..4c5c1e6cf87 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java @@ -18,6 +18,9 @@ package org.springframework.http.converter.xml; import java.nio.charset.StandardCharsets; +import javax.xml.namespace.QName; + +import jakarta.xml.bind.JAXBElement; import jakarta.xml.bind.Marshaller; import jakarta.xml.bind.Unmarshaller; import jakarta.xml.bind.annotation.XmlAttribute; @@ -93,6 +96,8 @@ class Jaxb2RootElementHttpMessageConverterTests { .as("Converter does not support writing @XmlRootElement subclass").isTrue(); assertThat(converter.canWrite(rootElementCglib.getClass(), null)) .as("Converter does not support writing @XmlRootElement subclass").isTrue(); + assertThat(converter.canWrite(JAXBElement.class, null)) + .as("Converter does not support writing JAXBElement").isTrue(); assertThat(converter.canWrite(Type.class, null)) .as("Converter supports writing @XmlType").isFalse(); } @@ -186,6 +191,18 @@ class Jaxb2RootElementHttpMessageConverterTests { .isSimilarTo("", ev); } + @Test + void writeJaxbElementRootElement() throws Exception { + MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); + JAXBElement jaxbElement = new JAXBElement<>(new QName("custom"), MyCustomElement.class, new MyCustomElement("field1", "field2")); + converter.write(jaxbElement, null, outputMessage); + assertThat(outputMessage.getHeaders().getContentType()) + .as("Invalid content-type").isEqualTo(MediaType.APPLICATION_XML); + DifferenceEvaluator ev = chain(Default, downgradeDifferencesToEqual(XML_STANDALONE)); + assertThat(XmlContent.of(outputMessage.getBodyAsString(StandardCharsets.UTF_8))) + .isSimilarTo("field1field2", ev); + } + @Test void writeXmlRootElementSubclass() throws Exception { MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); From f4b28867753d32f2466a571b6eb188920fe4f901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 19 Jul 2024 10:13:13 +0200 Subject: [PATCH 2/2] Polish "Support JAXBElement in Jaxb2RootElementHttpMessageConverter" See gh-33233 --- .../Jaxb2RootElementHttpMessageConverter.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java index 9bd7b646721..ee11dec759b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java @@ -121,7 +121,9 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @Override public boolean canWrite(Class clazz, @Nullable MediaType mediaType) { - return ((JAXBElement.class.isAssignableFrom(clazz) || AnnotationUtils.findAnnotation(clazz, XmlRootElement.class) != null) && canWrite(mediaType)); + boolean supportedType = (JAXBElement.class.isAssignableFrom(clazz) || + AnnotationUtils.findAnnotation(clazz, XmlRootElement.class) != null); + return (supportedType && canWrite(mediaType)); } @Override @@ -190,12 +192,12 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa } @Override - protected void writeToResult(Object o, HttpHeaders headers, Result result) throws Exception { + protected void writeToResult(Object value, HttpHeaders headers, Result result) throws Exception { try { - Class clazz = getMarshallerType(o); + Class clazz = getMarshallerType(value); Marshaller marshaller = createMarshaller(clazz); setCharset(headers.getContentType(), marshaller); - marshaller.marshal(o, result); + marshaller.marshal(value, result); } catch (MarshalException ex) { throw ex; @@ -205,12 +207,12 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa } } - private static Class getMarshallerType(Object o) { - if (o instanceof JAXBElement jaxbElement) { + private static Class getMarshallerType(Object value) { + if (value instanceof JAXBElement jaxbElement) { return jaxbElement.getDeclaredType(); } else { - return ClassUtils.getUserClass(o); + return ClassUtils.getUserClass(value); } }