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** # 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
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.springframework.integration.xml.transformer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
@@ -35,11 +37,11 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.xml.transform.StringSource;
|
||||
|
||||
/**
|
||||
* An implementation of {@link 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
|
||||
* alwaysUseSourceFactory is set to true, then the {@link SourceFactory}
|
||||
* 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}
|
||||
* will be used to create the {@link Source} regardless of payload type.
|
||||
* <p>
|
||||
* The Unmarshaller may return a Message, but if the return value is not
|
||||
@@ -88,35 +90,50 @@ public class UnmarshallingTransformer extends AbstractPayloadTransformer<Object,
|
||||
|
||||
@Override
|
||||
public Object transformPayload(Object payload) {
|
||||
Source source = null;
|
||||
if (this.alwaysUseSourceFactory) {
|
||||
source = this.sourceFactory.createSource(payload);
|
||||
}
|
||||
else if (payload instanceof String) {
|
||||
source = new StringSource((String) payload);
|
||||
}
|
||||
else if (payload instanceof File) {
|
||||
source = new StreamSource((File) payload);
|
||||
}
|
||||
else if (payload instanceof Document) {
|
||||
source = new DOMSource((Document) payload);
|
||||
}
|
||||
else if (payload instanceof Source) {
|
||||
source = (Source) payload;
|
||||
}
|
||||
else {
|
||||
source = this.sourceFactory.createSource(payload);
|
||||
}
|
||||
if (source == null) {
|
||||
throw new MessagingException(
|
||||
"failed to transform message, payload not assignable from javax.xml.transform.Source and no conversion possible");
|
||||
}
|
||||
Source source;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
if (this.alwaysUseSourceFactory) {
|
||||
source = this.sourceFactory.createSource(payload);
|
||||
}
|
||||
else if (payload instanceof String) {
|
||||
source = new StringSource((String) payload);
|
||||
}
|
||||
else if (payload instanceof File) {
|
||||
File file = (File) payload;
|
||||
inputStream = new FileInputStream(file);
|
||||
source = new StreamSource(inputStream, file.toURI().toASCIIString());
|
||||
}
|
||||
else if (payload instanceof Document) {
|
||||
source = new DOMSource((Document) payload);
|
||||
}
|
||||
else if (payload instanceof Source) {
|
||||
source = (Source) payload;
|
||||
}
|
||||
else {
|
||||
source = this.sourceFactory.createSource(payload);
|
||||
}
|
||||
if (source == null) {
|
||||
throw new MessagingException(
|
||||
"failed to transform message, payload not assignable from javax.xml.transform.Source and no " +
|
||||
"conversion possible");
|
||||
}
|
||||
|
||||
return this.unmarshaller.unmarshal(source);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new MessagingException("failed to unmarshal payload", e);
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -20,67 +20,96 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import javax.xml.transform.Result;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.transformer.MessageTransformationException;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
import org.springframework.oxm.UnmarshallingFailureException;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.xml.transform.StringSource;
|
||||
|
||||
/**
|
||||
* @author Jonas Partner
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@ContextConfiguration
|
||||
public class JaxbMarshallingIntegrationTests extends AbstractJUnit4SpringContextTests {
|
||||
@RunWith(SpringRunner.class)
|
||||
public class JaxbMarshallingIntegrationTests {
|
||||
|
||||
@Autowired @Qualifier("marshallIn")
|
||||
@Autowired
|
||||
@Qualifier("marshallIn")
|
||||
MessageChannel marshallIn;
|
||||
|
||||
@Autowired @Qualifier("marshallOut")
|
||||
@Autowired
|
||||
@Qualifier("marshallOut")
|
||||
PollableChannel marshalledOut;
|
||||
|
||||
@Autowired @Qualifier("unmarshallIn")
|
||||
@Autowired
|
||||
@Qualifier("unmarshallIn")
|
||||
MessageChannel unmarshallIn;
|
||||
|
||||
@Autowired @Qualifier("unmarshallOut")
|
||||
@Autowired
|
||||
@Qualifier("unmarshallOut")
|
||||
PollableChannel unmarshallOut;
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tempDirectory = new TemporaryFolder();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testMarshalling() throws Exception {
|
||||
public void testMarshalling() {
|
||||
JaxbAnnotatedPerson person = new JaxbAnnotatedPerson();
|
||||
person.setFirstName("john");
|
||||
marshallIn.send(new GenericMessage<Object>(person));
|
||||
GenericMessage<Result> res = (GenericMessage<Result>) marshalledOut.receive(2000);
|
||||
assertNotNull("No response recevied", res);
|
||||
assertTrue("payload was not a DOMResult", res.getPayload() instanceof DOMResult);
|
||||
this.marshallIn.send(new GenericMessage<>(person));
|
||||
Message<?> res = this.marshalledOut.receive(2000);
|
||||
assertNotNull(res);
|
||||
assertTrue(res.getPayload() instanceof DOMResult);
|
||||
Document doc = (Document) ((DOMResult) res.getPayload()).getNode();
|
||||
assertEquals("Wrong name for root element ", "person", doc.getDocumentElement().getLocalName());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testUnmarshalling() throws Exception {
|
||||
public void testUnmarshalling() {
|
||||
StringSource source = new StringSource("<person><firstname>bob</firstname></person>");
|
||||
unmarshallIn.send(new GenericMessage<Source>(source));
|
||||
GenericMessage<Object> res = (GenericMessage<Object>) unmarshallOut.receive(2000);
|
||||
this.unmarshallIn.send(new GenericMessage<Source>(source));
|
||||
Message<?> res = this.unmarshallOut.receive(2000);
|
||||
assertNotNull("No response", res);
|
||||
assertTrue("Not a Person ", res.getPayload() instanceof JaxbAnnotatedPerson);
|
||||
JaxbAnnotatedPerson person = (JaxbAnnotatedPerson) res.getPayload();
|
||||
assertEquals("Worng firstname", "bob", person.getFirstName());
|
||||
|
||||
assertEquals("bob", person.getFirstName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileUnlockedAfterUnmarshallingFailure() throws IOException {
|
||||
File tempFile = tempDirectory.newFile();
|
||||
FileWriter myWriter = new FileWriter(tempFile);
|
||||
myWriter.write("junk");
|
||||
myWriter.close();
|
||||
|
||||
try {
|
||||
this.unmarshallIn.send(new GenericMessage<>(tempFile));
|
||||
}
|
||||
catch (MessageTransformationException ex) {
|
||||
assertTrue(ex.getCause() instanceof UnmarshallingFailureException);
|
||||
assertTrue(ex.getMessage().contains("Content is not allowed in prolog."));
|
||||
}
|
||||
|
||||
assertTrue(tempFile.delete());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user