Skip to content

Commit 2d00bfc

Browse files
committed
GH-3238: Fix Unmarshaller to close File resource
Fixes #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** # Conflicts: # spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/UnmarshallingTransformer.java # spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/jaxbmarshaling/JaxbMarshallingIntegrationTests.java
1 parent 1f463a1 commit 2d00bfc

File tree

2 files changed

+67
-30
lines changed

2 files changed

+67
-30
lines changed

spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/UnmarshallingTransformer.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,7 +18,9 @@
1818

1919
import java.io.ByteArrayInputStream;
2020
import java.io.File;
21+
import java.io.FileInputStream;
2122
import java.io.IOException;
23+
import java.io.InputStream;
2224

2325
import javax.xml.transform.Source;
2426
import javax.xml.transform.dom.DOMSource;
@@ -37,11 +39,10 @@
3739

3840
/**
3941
* An implementation of {@link org.springframework.integration.transformer.Transformer}
40-
* that delegates to an OXM
41-
* {@link Unmarshaller}. Expects the payload to be of type {@link Document},
42-
* {@link String}, {@link File}, {@link Source} or to have an instance of
43-
* {@link SourceFactory} that can convert to a {@link Source}. If
44-
* {@link #alwaysUseSourceFactory} is set to true, then the {@link SourceFactory}
42+
* that delegates to an OXM {@link Unmarshaller}.
43+
* Expects the payload to be of type {@link Document}, {@link String}, {@link File}, {@link Source}
44+
* or to have an instance of {@link SourceFactory} that can convert to a {@link Source}.
45+
* If {@link #alwaysUseSourceFactory} is set to true, then the {@link SourceFactory}
4546
* will be used to create the {@link Source} regardless of payload type.
4647
* <p>
4748
* The {@link #alwaysUseSourceFactory} is ignored if payload is
@@ -98,6 +99,7 @@ public String getComponentType() {
9899
public Object transformPayload(Object payload) {
99100
Source source = null;
100101

102+
InputStream inputStream = null;
101103
try {
102104
if (this.mimeMessageUnmarshallerHelper != null) {
103105
Object result = this.mimeMessageUnmarshallerHelper.maybeUnmarshalMimeMessage(payload);
@@ -116,7 +118,9 @@ else if (payload instanceof byte[]) {
116118
source = new StreamSource(new ByteArrayInputStream((byte[]) payload));
117119
}
118120
else if (payload instanceof File) {
119-
source = new StreamSource((File) payload);
121+
File file = (File) payload;
122+
inputStream = new FileInputStream(file);
123+
source = new StreamSource(inputStream, file.toURI().toASCIIString());
120124
}
121125
else if (payload instanceof Document) {
122126
source = new DOMSource((Document) payload);
@@ -137,6 +141,16 @@ else if (payload instanceof Source) {
137141
catch (IOException e) {
138142
throw new MessagingException("failed to unmarshal payload", e);
139143
}
144+
finally {
145+
if (inputStream != null) {
146+
try {
147+
inputStream.close();
148+
}
149+
catch (IOException e) {
150+
// Ignore
151+
}
152+
}
153+
}
140154
}
141155

142156
private static class MimeMessageUnmarshallerHelper {
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,71 +16,94 @@
1616

1717
package org.springframework.integration.xml.transformer.jaxbmarshaling;
1818

19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
1921
import static org.junit.Assert.assertEquals;
2022
import static org.junit.Assert.assertNotNull;
2123
import static org.junit.Assert.assertTrue;
2224

23-
import javax.xml.transform.Result;
25+
import java.io.IOException;
26+
import java.nio.file.Files;
27+
import java.nio.file.Path;
28+
2429
import javax.xml.transform.Source;
2530
import javax.xml.transform.dom.DOMResult;
2631

27-
import org.junit.Test;
32+
import org.junit.jupiter.api.Test;
33+
import org.junit.jupiter.api.io.TempDir;
2834
import org.w3c.dom.Document;
2935

3036
import org.springframework.beans.factory.annotation.Autowired;
3137
import org.springframework.beans.factory.annotation.Qualifier;
38+
import org.springframework.integration.transformer.MessageTransformationException;
39+
import org.springframework.messaging.Message;
3240
import org.springframework.messaging.MessageChannel;
3341
import org.springframework.messaging.PollableChannel;
3442
import org.springframework.messaging.support.GenericMessage;
35-
import org.springframework.test.context.ContextConfiguration;
36-
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
43+
import org.springframework.oxm.UnmarshallingFailureException;
44+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
3745
import org.springframework.xml.transform.StringSource;
3846

3947
/**
4048
* @author Jonas Partner
49+
* @author Artem Bilan
4150
*/
42-
@ContextConfiguration
43-
public class JaxbMarshallingIntegrationTests extends AbstractJUnit4SpringContextTests {
51+
@SpringJUnitConfig
52+
public class JaxbMarshallingIntegrationTests {
4453

45-
@Autowired @Qualifier("marshallIn")
54+
@Autowired
55+
@Qualifier("marshallIn")
4656
MessageChannel marshallIn;
4757

48-
@Autowired @Qualifier("marshallOut")
58+
@Autowired
59+
@Qualifier("marshallOut")
4960
PollableChannel marshalledOut;
5061

51-
@Autowired @Qualifier("unmarshallIn")
62+
@Autowired
63+
@Qualifier("unmarshallIn")
5264
MessageChannel unmarshallIn;
5365

54-
@Autowired @Qualifier("unmarshallOut")
66+
@Autowired
67+
@Qualifier("unmarshallOut")
5568
PollableChannel unmarshallOut;
5669

70+
@TempDir
71+
Path tempDirectory;
5772

58-
@SuppressWarnings("unchecked")
5973
@Test
60-
public void testMarshalling() throws Exception {
74+
public void testMarshalling() {
6175
JaxbAnnotatedPerson person = new JaxbAnnotatedPerson();
6276
person.setFirstName("john");
63-
marshallIn.send(new GenericMessage<Object>(person));
64-
GenericMessage<Result> res = (GenericMessage<Result>) marshalledOut.receive(2000);
65-
assertNotNull("No response recevied", res);
66-
assertTrue("payload was not a DOMResult", res.getPayload() instanceof DOMResult);
77+
this.marshallIn.send(new GenericMessage<>(person));
78+
Message<?> res = this.marshalledOut.receive(2000);
79+
assertThat(res).as("No response received").isNotNull();
80+
assertThat(res.getPayload() instanceof DOMResult).as("payload was not a DOMResult").isTrue();
6781
Document doc = (Document) ((DOMResult) res.getPayload()).getNode();
6882
assertEquals("Wrong name for root element ", "person", doc.getDocumentElement().getLocalName());
6983
}
7084

7185

72-
@SuppressWarnings("unchecked")
7386
@Test
74-
public void testUnmarshalling() throws Exception {
87+
public void testUnmarshalling() {
7588
StringSource source = new StringSource("<person><firstname>bob</firstname></person>");
76-
unmarshallIn.send(new GenericMessage<Source>(source));
77-
GenericMessage<Object> res = (GenericMessage<Object>) unmarshallOut.receive(2000);
89+
this.unmarshallIn.send(new GenericMessage<Source>(source));
90+
Message<?> res = this.unmarshallOut.receive(2000);
7891
assertNotNull("No response", res);
7992
assertTrue("Not a Person ", res.getPayload() instanceof JaxbAnnotatedPerson);
8093
JaxbAnnotatedPerson person = (JaxbAnnotatedPerson) res.getPayload();
81-
assertEquals("Worng firstname", "bob", person.getFirstName());
82-
94+
assertThat(person.getFirstName()).as("Wrong firstname").isEqualTo("bob");
8395
}
8496

97+
@Test
98+
public void testFileUnlockedAfterUnmarshallingFailure() throws IOException {
99+
Path tempFile = Files.createTempFile(this.tempDirectory, null, null);
100+
Files.write(tempFile, "junk".getBytes());
101+
assertThatExceptionOfType(MessageTransformationException.class)
102+
.isThrownBy(() -> this.unmarshallIn.send(new GenericMessage<>(tempFile.toFile())))
103+
.withCauseInstanceOf(UnmarshallingFailureException.class)
104+
.withStackTraceContaining("Content is not allowed in prolog.");
105+
106+
Files.delete(tempFile);
107+
}
85108

86109
}

0 commit comments

Comments
 (0)