diff --git a/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlEncoder.java index e1b71e08c0..46d2f8dfde 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/xml/Jaxb2XmlEncoder.java @@ -34,6 +34,7 @@ import org.springframework.core.codec.EncodingException; import org.springframework.core.codec.Hints; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.log.LogFormatUtils; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; @@ -78,27 +79,38 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder { @Override protected Flux encode(Object value, DataBufferFactory dataBufferFactory, ResolvableType type, @Nullable MimeType mimeType, @Nullable Map hints) { + + if (!Hints.isLoggingSuppressed(hints)) { + LogFormatUtils.traceDebug(logger, traceOn -> { + String formatted = LogFormatUtils.formatValue(value, !traceOn); + return Hints.getLogPrefix(hints) + "Encoding [" + formatted + "]"; + }); + } + + boolean release = true; + DataBuffer buffer = dataBufferFactory.allocateBuffer(1024); + OutputStream outputStream = buffer.asOutputStream(); + Class clazz = ClassUtils.getUserClass(value); + try { - if (!Hints.isLoggingSuppressed(hints)) { - LogFormatUtils.traceDebug(logger, traceOn -> { - String formatted = LogFormatUtils.formatValue(value, !traceOn); - return Hints.getLogPrefix(hints) + "Encoding [" + formatted + "]"; - }); - } - DataBuffer buffer = dataBufferFactory.allocateBuffer(1024); - OutputStream outputStream = buffer.asOutputStream(); - Class clazz = ClassUtils.getUserClass(value); Marshaller marshaller = this.jaxbContexts.createMarshaller(clazz); marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name()); marshaller.marshal(value, outputStream); + release = false; return Flux.just(buffer); } catch (MarshalException ex) { - return Flux.error(new EncodingException("Could not marshal " + value.getClass() + " to XML", ex)); + return Flux.error(new EncodingException( + "Could not marshal " + value.getClass() + " to XML", ex)); } catch (JAXBException ex) { return Flux.error(new CodecException("Invalid JAXB configuration", ex)); } + finally { + if (release) { + DataBufferUtils.release(buffer); + } + } } } diff --git a/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlEncoderTests.java b/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlEncoderTests.java index 7295d173d2..5dfa149035 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlEncoderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/xml/Jaxb2XmlEncoderTests.java @@ -20,6 +20,9 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.List; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; import org.junit.Test; import reactor.core.publisher.Flux; @@ -34,15 +37,9 @@ import org.springframework.core.io.buffer.support.DataBufferTestUtils; import org.springframework.http.MediaType; import org.springframework.http.codec.Pojo; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import static org.xmlunit.matchers.CompareMatcher.isSimilarTo; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElements; -import javax.xml.bind.annotation.XmlRootElement; - /** * @author Sebastien Deleuze * @author Arjen Poutsma @@ -94,6 +91,18 @@ public class Jaxb2XmlEncoderTests extends AbstractDataBufferAllocatingTestCase { .verifyComplete(); } + @Test + public void encodeError() { + Flux source = Flux.error(RuntimeException::new); + Flux output = this.encoder.encode(source, this.bufferFactory, + ResolvableType.forClass(Pojo.class), + MediaType.APPLICATION_XML, Collections.emptyMap()); + + StepVerifier.create(output) + .expectError(RuntimeException.class) + .verify(); + } + @Test public void encodeElementsWithCommonType() { Mono source = Mono.just(new Container());