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:
Arjen Poutsma
2018-10-24 10:52:17 +02:00
parent 11a017d8b7
commit 611019b73c
2 changed files with 38 additions and 17 deletions

View File

@@ -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);
}
}
}
}