From 7e52f35ef1136fcc4bdfab42e966a1aefd9a4ccb Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Thu, 2 Apr 2020 13:04:15 -0400 Subject: [PATCH] GH-3238: Fix Unmarshaller to close File resource Fixes https://github.com/spring-projects/spring-integration/issues/3238 * Extract an `InputStream` from a `File` payload in the `UnmarshallingTransformer` before parsing an XML. Close this `InputStream` in the `finally` block to release the file resource **Cherry-pick to 5.2.x, 5.1.x & 4.3.x** --- .../transformer/UnmarshallingTransformer.java | 28 ++++++-- .../JaxbMarshallingIntegrationTests.java | 66 ++++++++++++------- 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/UnmarshallingTransformer.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/UnmarshallingTransformer.java index 1f1e6dafd8..31dc2c1835 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/UnmarshallingTransformer.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/UnmarshallingTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,9 @@ package org.springframework.integration.xml.transformer; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.UncheckedIOException; import javax.xml.transform.Source; @@ -37,11 +39,10 @@ import org.springframework.xml.transform.StringSource; /** * An implementation of {@link org.springframework.integration.transformer.Transformer} - * that delegates to an OXM - * {@link Unmarshaller}. Expects the payload to be of type {@link Document}, - * {@link String}, {@link File}, {@link Source} or to have an instance of - * {@link SourceFactory} that can convert to a {@link Source}. If - * {@link #alwaysUseSourceFactory} is set to true, then the {@link SourceFactory} + * that delegates to an OXM {@link Unmarshaller}. + * Expects the payload to be of type {@link Document}, {@link String}, {@link File}, {@link Source} + * or to have an instance of {@link SourceFactory} that can convert to a {@link Source}. + * If {@link #alwaysUseSourceFactory} is set to true, then the {@link SourceFactory} * will be used to create the {@link Source} regardless of payload type. *

* The {@link #alwaysUseSourceFactory} is ignored if payload is @@ -97,6 +98,7 @@ public class UnmarshallingTransformer extends AbstractPayloadTransformer(person)); - GenericMessage res = (GenericMessage) marshalledOut.receive(2000); - assertThat(res).as("No response recevied").isNotNull(); + this.marshallIn.send(new GenericMessage<>(person)); + Message res = this.marshalledOut.receive(2000); + assertThat(res).as("No response received").isNotNull(); assertThat(res.getPayload() instanceof DOMResult).as("payload was not a DOMResult").isTrue(); Document doc = (Document) ((DOMResult) res.getPayload()).getNode(); assertThat(doc.getDocumentElement().getLocalName()).as("Wrong name for root element ").isEqualTo("person"); } - @SuppressWarnings("unchecked") @Test - public void testUnmarshalling() throws Exception { + public void testUnmarshalling() { StringSource source = new StringSource("bob"); - unmarshallIn.send(new GenericMessage(source)); - GenericMessage res = (GenericMessage) unmarshallOut.receive(2000); + this.unmarshallIn.send(new GenericMessage(source)); + Message res = this.unmarshallOut.receive(2000); assertThat(res).as("No response").isNotNull(); assertThat(res.getPayload() instanceof JaxbAnnotatedPerson).as("Not a Person ").isTrue(); JaxbAnnotatedPerson person = (JaxbAnnotatedPerson) res.getPayload(); - assertThat(person.getFirstName()).as("Worng firstname").isEqualTo("bob"); - + assertThat(person.getFirstName()).as("Wrong firstname").isEqualTo("bob"); } + @Test + public void testFileUnlockedAfterUnmarshallingFailure() throws IOException { + Path tempFile = Files.createTempFile(this.tempDirectory, null, null); + Files.write(tempFile, "junk".getBytes()); + assertThatExceptionOfType(MessageTransformationException.class) + .isThrownBy(() -> this.unmarshallIn.send(new GenericMessage<>(tempFile.toFile()))) + .withCauseInstanceOf(UnmarshallingFailureException.class) + .withStackTraceContaining("Content is not allowed in prolog."); + + Files.delete(tempFile); + } }