Skip to content

Commit 0f5bd4a

Browse files
artembilangaryrussell
authored andcommitted
INT-3494: Resolve dir for writing as a Resource (#3109)
* INT-3494: Resolve dir for writing as a Resource JIRA: https://jira.spring.io/browse/INT-3494 The expression for local directory can be resolved into a `Resource` or resource location. * Fix `ExpressionUtils.expressionToFile()` to support `Resource` and also use `ResourceUtils.getFile(path)` when expression result is a string * Modify tests to ensure that resource is resolved properly * Upgrade affected tests to JUnit 5 * Mention an new functionality in docs * * Improve Java doc for `ExpressionUtils.expressionToFile()` * Finish the sentence in the `file.adoc`
1 parent 069d873 commit 0f5bd4a

File tree

7 files changed

+165
-212
lines changed

7 files changed

+165
-212
lines changed

spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionUtils.java

+44-20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.springframework.integration.expression;
1818

1919
import java.io.File;
20+
import java.io.FileNotFoundException;
21+
import java.io.IOException;
2022

2123
import org.apache.commons.logging.Log;
2224
import org.apache.commons.logging.LogFactory;
@@ -25,6 +27,7 @@
2527
import org.springframework.context.expression.BeanFactoryResolver;
2628
import org.springframework.context.expression.MapAccessor;
2729
import org.springframework.core.convert.ConversionService;
30+
import org.springframework.core.io.Resource;
2831
import org.springframework.expression.EvaluationContext;
2932
import org.springframework.expression.Expression;
3033
import org.springframework.expression.ExpressionParser;
@@ -39,6 +42,7 @@
3942
import org.springframework.lang.Nullable;
4043
import org.springframework.messaging.Message;
4144
import org.springframework.util.Assert;
45+
import org.springframework.util.ResourceUtils;
4246

4347
/**
4448
* Utility class with static methods for helping with evaluation of SpEL expressions.
@@ -53,7 +57,7 @@ public final class ExpressionUtils {
5357

5458
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
5559

56-
private static final Log logger = LogFactory.getLog(ExpressionUtils.class);
60+
private static final Log LOGGER = LogFactory.getLog(ExpressionUtils.class);
5761

5862
private ExpressionUtils() {
5963
super();
@@ -84,7 +88,7 @@ public static SimpleEvaluationContext createSimpleEvaluationContext() {
8488
*/
8589
public static StandardEvaluationContext createStandardEvaluationContext(@Nullable BeanFactory beanFactory) {
8690
if (beanFactory == null) {
87-
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
91+
LOGGER.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
8892
}
8993
return (StandardEvaluationContext) doCreateContext(beanFactory, false);
9094
}
@@ -98,7 +102,7 @@ public static StandardEvaluationContext createStandardEvaluationContext(@Nullabl
98102
*/
99103
public static SimpleEvaluationContext createSimpleEvaluationContext(@Nullable BeanFactory beanFactory) {
100104
if (beanFactory == null) {
101-
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
105+
LOGGER.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
102106
}
103107
return (SimpleEvaluationContext) doCreateContext(beanFactory, true);
104108
}
@@ -161,36 +165,56 @@ private static EvaluationContext createEvaluationContext(@Nullable ConversionSer
161165
* @param expression the expression.
162166
* @param evaluationContext the evaluation context.
163167
* @param message the message (if available).
164-
* @param name the name of the result of the evaluation.
168+
* @param propertyName the property name the expression is evaluated for.
165169
* @return the File.
166170
* @since 5.0
167171
*/
168172
public static File expressionToFile(Expression expression, EvaluationContext evaluationContext,
169-
@Nullable Message<?> message, String name) {
170-
171-
File file;
172-
Object value = message == null
173-
? expression.getValue(evaluationContext)
174-
: expression.getValue(evaluationContext, message);
175-
if (value == null) {
176-
throw new IllegalStateException(String.format("The provided %s expression (%s) must not evaluate to null.",
177-
name, expression.getExpressionString()));
178-
}
179-
else if (value instanceof File) {
180-
file = (File) value;
173+
@Nullable Message<?> message, String propertyName) {
174+
175+
Object value =
176+
message == null
177+
? expression.getValue(evaluationContext)
178+
: expression.getValue(evaluationContext, message);
179+
180+
Assert.state(value != null, () ->
181+
String.format("The provided %s expression (%s) must not evaluate to null.",
182+
propertyName, expression.getExpressionString()));
183+
184+
if (value instanceof File) {
185+
return (File) value;
181186
}
182187
else if (value instanceof String) {
183188
String path = (String) value;
184-
Assert.hasText(path, String.format("Unable to resolve %s for the provided Expression '%s'.", name,
189+
Assert.hasText(path, String.format("Unable to resolve %s for the provided Expression '%s'.", propertyName,
185190
expression.getExpressionString()));
186-
file = new File(path);
191+
try {
192+
return ResourceUtils.getFile(path);
193+
}
194+
catch (FileNotFoundException ex) {
195+
throw new IllegalStateException(
196+
String.format("Unable to resolve %s for the provided Expression '%s'.",
197+
propertyName, expression.getExpressionString()),
198+
ex);
199+
}
200+
}
201+
else if (value instanceof Resource) {
202+
try {
203+
return ((Resource) value).getFile();
204+
}
205+
catch (IOException ex) {
206+
throw new IllegalStateException(
207+
String.format("Unable to resolve %s for the provided Expression '%s'.",
208+
propertyName, expression.getExpressionString()),
209+
ex);
210+
}
187211
}
188212
else {
189213
throw new IllegalStateException(String.format(
190-
"The provided %s expression (%s) must evaluate to type java.io.File or String, not %s.", name,
214+
"The provided %s expression (%s) must evaluate to type java.io.File, String " +
215+
"or org.springframework.core.io.Resource, not %s.", propertyName,
191216
expression.getExpressionString(), value.getClass().getName()));
192217
}
193-
return file;
194218
}
195219

196220
/**

spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests-context.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<si:header-enricher>
1919
<si:header name="#{T(org.springframework.integration.file.FileHeaders).FILENAME}" value="${test.file}"/>
2020
</si:header-enricher>
21-
<file:outbound-channel-adapter id="file-outbound-channel-adapter-within-chain" directory="${work.dir}"/>
21+
<file:outbound-channel-adapter id="file-outbound-channel-adapter-within-chain" directory-expression="${work.dir}"/>
2222
</si:chain>
2323

2424
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">

spring-integration-file/src/test/java/org/springframework/integration/file/FileOutboundChannelAdapterInsideChainTests.java

+16-38
Original file line numberDiff line numberDiff line change
@@ -22,69 +22,47 @@
2222
import java.io.IOException;
2323
import java.util.Properties;
2424

25-
import org.junit.AfterClass;
26-
import org.junit.BeforeClass;
27-
import org.junit.Test;
28-
import org.junit.runner.RunWith;
25+
import org.junit.jupiter.api.BeforeAll;
26+
import org.junit.jupiter.api.Test;
27+
import org.junit.jupiter.api.io.TempDir;
2928

3029
import org.springframework.beans.factory.annotation.Autowired;
3130
import org.springframework.integration.support.MessageBuilder;
3231
import org.springframework.messaging.Message;
3332
import org.springframework.messaging.MessageChannel;
34-
import org.springframework.test.context.ContextConfiguration;
35-
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
33+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
3634
import org.springframework.util.FileCopyUtils;
3735

3836
/**
39-
* //INT-2275
40-
*
4137
* @author Artem Bilan
4238
* @author Gary Russell
4339
*/
44-
@ContextConfiguration
45-
@RunWith(SpringJUnit4ClassRunner.class)
40+
@SpringJUnitConfig
4641
public class FileOutboundChannelAdapterInsideChainTests {
4742

48-
public static final String TEST_FILE_NAME = FileOutboundChannelAdapterInsideChainTests.class.getSimpleName();
43+
static final String TEST_FILE_NAME = FileOutboundChannelAdapterInsideChainTests.class.getSimpleName();
4944

50-
public static final String WORK_DIR_NAME = System.getProperty("java.io.tmpdir") + "/" + FileOutboundChannelAdapterInsideChainTests.class.getSimpleName() + "Dir";
45+
static final String SAMPLE_CONTENT = "test";
5146

52-
public static final String SAMPLE_CONTENT = "test";
47+
@TempDir
48+
static File WORK_DIR;
5349

5450
public static Properties placeholderProperties = new Properties();
5551

56-
static {
57-
placeholderProperties.put("test.file", TEST_FILE_NAME);
58-
placeholderProperties.put("work.dir", WORK_DIR_NAME);
59-
}
60-
6152
@Autowired
6253
private MessageChannel outboundChainChannel;
6354

64-
private static File workDir;
65-
66-
@BeforeClass
67-
public static void setupClass() {
68-
workDir = new File(WORK_DIR_NAME);
69-
workDir.mkdir();
70-
workDir.deleteOnExit();
71-
}
72-
73-
@AfterClass
74-
public static void cleanUp() {
75-
if (workDir != null && workDir.exists()) {
76-
for (File file : workDir.listFiles()) {
77-
file.delete();
78-
}
79-
}
80-
workDir.delete();
55+
@BeforeAll
56+
static void setupClass() {
57+
placeholderProperties.put("test.file", TEST_FILE_NAME);
58+
placeholderProperties.put("work.dir", "'file://" + WORK_DIR.getAbsolutePath() + '\'');
8159
}
8260

83-
@Test //INT-2275
84-
public void testFileOutboundChannelAdapterWithinChain() throws IOException {
61+
@Test
62+
void testFileOutboundChannelAdapterWithinChain() throws IOException {
8563
Message<String> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
8664
outboundChainChannel.send(message);
87-
File testFile = new File(workDir, TEST_FILE_NAME);
65+
File testFile = new File(WORK_DIR, TEST_FILE_NAME);
8866
assertThat(testFile.exists()).isTrue();
8967
byte[] testFileContent = FileCopyUtils.copyToByteArray(testFile);
9068
assertThat(SAMPLE_CONTENT).isEqualTo(new String(testFileContent));

0 commit comments

Comments
 (0)