Skip to content

Commit 43c5519

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 # 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 3ab990a commit 43c5519

File tree

2 files changed

+97
-51
lines changed

2 files changed

+97
-51
lines changed

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

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 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.
@@ -17,7 +17,9 @@
1717
package org.springframework.integration.xml.transformer;
1818

1919
import java.io.File;
20+
import java.io.FileInputStream;
2021
import java.io.IOException;
22+
import java.io.InputStream;
2123

2224
import javax.xml.transform.Source;
2325
import javax.xml.transform.dom.DOMSource;
@@ -35,11 +37,11 @@
3537
import org.springframework.xml.transform.StringSource;
3638

3739
/**
38-
* An implementation of {@link Transformer} that delegates to an OXM
39-
* {@link Unmarshaller}. Expects the payload to be of type {@link Document},
40-
* {@link String}, {@link File}, {@link Source} or to have an instance of
41-
* {@link SourceFactory} that can convert to a {@link Source}. If
42-
* alwaysUseSourceFactory is set to true, then the {@link SourceFactory}
40+
* An implementation of {@link org.springframework.integration.transformer.Transformer}
41+
* that delegates to an OXM {@link Unmarshaller}.
42+
* Expects the payload to be of type {@link Document}, {@link String}, {@link File}, {@link Source}
43+
* or to have an instance of {@link SourceFactory} that can convert to a {@link Source}.
44+
* If {@link #alwaysUseSourceFactory} is set to true, then the {@link SourceFactory}
4345
* will be used to create the {@link Source} regardless of payload type.
4446
* <p>
4547
* The Unmarshaller may return a Message, but if the return value is not
@@ -88,35 +90,50 @@ public String getComponentType() {
8890

8991
@Override
9092
public Object transformPayload(Object payload) {
91-
Source source = null;
92-
if (this.alwaysUseSourceFactory) {
93-
source = this.sourceFactory.createSource(payload);
94-
}
95-
else if (payload instanceof String) {
96-
source = new StringSource((String) payload);
97-
}
98-
else if (payload instanceof File) {
99-
source = new StreamSource((File) payload);
100-
}
101-
else if (payload instanceof Document) {
102-
source = new DOMSource((Document) payload);
103-
}
104-
else if (payload instanceof Source) {
105-
source = (Source) payload;
106-
}
107-
else {
108-
source = this.sourceFactory.createSource(payload);
109-
}
110-
if (source == null) {
111-
throw new MessagingException(
112-
"failed to transform message, payload not assignable from javax.xml.transform.Source and no conversion possible");
113-
}
93+
Source source;
94+
InputStream inputStream = null;
11495
try {
96+
if (this.alwaysUseSourceFactory) {
97+
source = this.sourceFactory.createSource(payload);
98+
}
99+
else if (payload instanceof String) {
100+
source = new StringSource((String) payload);
101+
}
102+
else if (payload instanceof File) {
103+
File file = (File) payload;
104+
inputStream = new FileInputStream(file);
105+
source = new StreamSource(inputStream, file.toURI().toASCIIString());
106+
}
107+
else if (payload instanceof Document) {
108+
source = new DOMSource((Document) payload);
109+
}
110+
else if (payload instanceof Source) {
111+
source = (Source) payload;
112+
}
113+
else {
114+
source = this.sourceFactory.createSource(payload);
115+
}
116+
if (source == null) {
117+
throw new MessagingException(
118+
"failed to transform message, payload not assignable from javax.xml.transform.Source and no " +
119+
"conversion possible");
120+
}
121+
115122
return this.unmarshaller.unmarshal(source);
116123
}
117124
catch (IOException e) {
118125
throw new MessagingException("failed to unmarshal payload", e);
119126
}
127+
finally {
128+
if (inputStream != null) {
129+
try {
130+
inputStream.close();
131+
}
132+
catch (IOException e) {
133+
// Ignore
134+
}
135+
}
136+
}
120137
}
121138

122139
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 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.
@@ -20,67 +20,96 @@
2020
import static org.junit.Assert.assertNotNull;
2121
import static org.junit.Assert.assertTrue;
2222

23-
import javax.xml.transform.Result;
23+
import java.io.File;
24+
import java.io.FileWriter;
25+
import java.io.IOException;
26+
2427
import javax.xml.transform.Source;
2528
import javax.xml.transform.dom.DOMResult;
2629

30+
import org.junit.Rule;
2731
import org.junit.Test;
32+
import org.junit.rules.TemporaryFolder;
33+
import org.junit.runner.RunWith;
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.junit4.SpringRunner;
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+
@RunWith(SpringRunner.class)
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+
@Rule
71+
public TemporaryFolder tempDirectory = new TemporaryFolder();
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+
assertNotNull(res);
80+
assertTrue(res.getPayload() instanceof DOMResult);
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+
assertEquals("bob", person.getFirstName());
8395
}
8496

97+
@Test
98+
public void testFileUnlockedAfterUnmarshallingFailure() throws IOException {
99+
File tempFile = tempDirectory.newFile();
100+
FileWriter myWriter = new FileWriter(tempFile);
101+
myWriter.write("junk");
102+
myWriter.close();
103+
104+
try {
105+
this.unmarshallIn.send(new GenericMessage<>(tempFile));
106+
}
107+
catch (MessageTransformationException ex) {
108+
assertTrue(ex.getCause() instanceof UnmarshallingFailureException);
109+
assertTrue(ex.getMessage().contains("Content is not allowed in prolog."));
110+
}
111+
112+
assertTrue(tempFile.delete());
113+
}
85114

86115
}

0 commit comments

Comments
 (0)