Fix memory leak for Jaxb2XmlEncoder
This commit fixes a memory leak in Jaxb2XmlEncoder that occurs when the input stream contains an error. Test added as well. Issue: SPR-17419
This commit is contained in:
@@ -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<Object> {
|
||||
@Override
|
||||
protected Flux<DataBuffer> encode(Object value, DataBufferFactory dataBufferFactory,
|
||||
ResolvableType type, @Nullable MimeType mimeType, @Nullable Map<String, Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Pojo> source = Flux.error(RuntimeException::new);
|
||||
Flux<DataBuffer> 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<Container> source = Mono.just(new Container());
|
||||
|
||||
Reference in New Issue
Block a user