GH-9594: Fix FileReadingMessageSource for FileHeaders.RELATIVE_PATH
Fixes: #9594
Issue link: https://github.com/spring-projects/spring-integration/issues/9594
The `String.replaceFirst()` for directory with `[]` or `()` leads to a regex execution
which does not really replace the root path because of mismatch between regex and file path.
Essentially, the `Matcher.quoteReplacement()` does not do the trick we would expect from it.
* Use `Path.relativize()` API instead which works in canonical paths and proper file separators
(cherry picked from commit 91494094ac)
This commit is contained in:
committed by
Spring Builds
parent
eab39c0b0b
commit
44d035fcaa
@@ -42,7 +42,6 @@ import java.util.concurrent.ConcurrentMap;
|
|||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
|
|
||||||
import org.springframework.context.Lifecycle;
|
import org.springframework.context.Lifecycle;
|
||||||
import org.springframework.integration.endpoint.AbstractMessageSource;
|
import org.springframework.integration.endpoint.AbstractMessageSource;
|
||||||
@@ -388,10 +387,7 @@ public class FileReadingMessageSource extends AbstractMessageSource<File> implem
|
|||||||
if (file != null) {
|
if (file != null) {
|
||||||
return getMessageBuilderFactory()
|
return getMessageBuilderFactory()
|
||||||
.withPayload(file)
|
.withPayload(file)
|
||||||
.setHeader(FileHeaders.RELATIVE_PATH,
|
.setHeader(FileHeaders.RELATIVE_PATH, this.directory.toPath().relativize(file.toPath()).toString())
|
||||||
file.getAbsolutePath()
|
|
||||||
.replaceFirst(Matcher.quoteReplacement(
|
|
||||||
this.directory.getAbsolutePath() + File.separator), ""))
|
|
||||||
.setHeader(FileHeaders.FILENAME, file.getName())
|
.setHeader(FileHeaders.FILENAME, file.getName())
|
||||||
.setHeader(FileHeaders.ORIGINAL_FILE, file);
|
.setHeader(FileHeaders.ORIGINAL_FILE, file);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,15 +17,12 @@
|
|||||||
package org.springframework.integration.file;
|
package org.springframework.integration.file;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -42,43 +39,40 @@ import static org.mockito.Mockito.when;
|
|||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
class FileReadingMessageSourceTests {
|
||||||
public class FileReadingMessageSourceTests {
|
|
||||||
|
|
||||||
private FileReadingMessageSource source;
|
private FileReadingMessageSource source;
|
||||||
|
|
||||||
@Mock
|
private final File inputDirectoryMock = mock();
|
||||||
private File inputDirectoryMock;
|
|
||||||
|
|
||||||
@Mock
|
private final File fileMock = mock();
|
||||||
private File fileMock;
|
|
||||||
|
|
||||||
@Mock
|
private final FileLocker locker = mock();
|
||||||
private FileLocker locker;
|
|
||||||
|
|
||||||
@Mock
|
private final Comparator<File> comparator = mock();
|
||||||
private Comparator<File> comparator;
|
|
||||||
|
|
||||||
public void prepResource() {
|
public void prepResource() {
|
||||||
when(inputDirectoryMock.getAbsolutePath()).thenReturn("foo/bar");
|
when(inputDirectoryMock.toPath()).thenReturn(Path.of("[dir]"));
|
||||||
when(fileMock.getAbsolutePath()).thenReturn("foo/bar/fileMock");
|
when(fileMock.toPath()).thenReturn(Path.of("[dir]/fileMock"));
|
||||||
when(locker.lock(isA(File.class))).thenReturn(true);
|
when(locker.lock(isA(File.class))).thenReturn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
prepResource();
|
prepResource();
|
||||||
this.source = new FileReadingMessageSource(comparator);
|
this.source = new FileReadingMessageSource(comparator);
|
||||||
this.source.setDirectory(inputDirectoryMock);
|
this.source.setDirectory(inputDirectoryMock);
|
||||||
this.source.setLocker(locker);
|
this.source.setLocker(locker);
|
||||||
this.source.setBeanFactory(mock(BeanFactory.class));
|
this.source.setBeanFactory(mock());
|
||||||
this.source.afterPropertiesSet();
|
this.source.afterPropertiesSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void straightProcess() {
|
public void straightProcess() {
|
||||||
when(inputDirectoryMock.listFiles()).thenReturn(new File[] {fileMock});
|
when(inputDirectoryMock.listFiles()).thenReturn(new File[] {fileMock});
|
||||||
assertThat(source.receive().getPayload()).isEqualTo(fileMock);
|
Message<File> fileMessage = source.receive();
|
||||||
|
assertThat(fileMessage.getPayload()).isEqualTo(fileMock);
|
||||||
|
assertThat(fileMessage.getHeaders()).containsEntry(FileHeaders.RELATIVE_PATH, "fileMock");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -88,13 +82,13 @@ public class FileReadingMessageSourceTests {
|
|||||||
assertThat(received).isNotNull();
|
assertThat(received).isNotNull();
|
||||||
source.onFailure(received);
|
source.onFailure(received);
|
||||||
assertThat(source.receive().getPayload()).isEqualTo(received.getPayload());
|
assertThat(source.receive().getPayload()).isEqualTo(received.getPayload());
|
||||||
verify(inputDirectoryMock, times(1)).listFiles();
|
verify(inputDirectoryMock).listFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void scanEachPoll() {
|
public void scanEachPoll() {
|
||||||
File anotherFileMock = mock(File.class);
|
File anotherFileMock = mock();
|
||||||
when(anotherFileMock.getAbsolutePath()).thenReturn("foo/bar/anotherFileMock");
|
when(anotherFileMock.toPath()).thenReturn(Path.of("[dir]/anotherFileMock"));
|
||||||
when(inputDirectoryMock.listFiles()).thenReturn(new File[] {fileMock, anotherFileMock});
|
when(inputDirectoryMock.listFiles()).thenReturn(new File[] {fileMock, anotherFileMock});
|
||||||
source.setScanEachPoll(true);
|
source.setScanEachPoll(true);
|
||||||
assertThat(source.receive()).isNotNull();
|
assertThat(source.receive()).isNotNull();
|
||||||
@@ -139,12 +133,12 @@ public class FileReadingMessageSourceTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void orderedReception() {
|
public void orderedReception() {
|
||||||
File file1 = mock(File.class);
|
File file1 = mock();
|
||||||
when(file1.getAbsolutePath()).thenReturn("foo/bar/file1");
|
when(file1.toPath()).thenReturn(Path.of("[dir]/file1"));
|
||||||
File file2 = mock(File.class);
|
File file2 = mock();
|
||||||
when(file2.getAbsolutePath()).thenReturn("foo/bar/file2");
|
when(file2.toPath()).thenReturn(Path.of("[dir]/file2"));
|
||||||
File file3 = mock(File.class);
|
File file3 = mock();
|
||||||
when(file3.getAbsolutePath()).thenReturn("foo/bar/file3");
|
when(file3.toPath()).thenReturn(Path.of("[dir]/file3"));
|
||||||
|
|
||||||
// record the comparator to reverse order the files
|
// record the comparator to reverse order the files
|
||||||
when(comparator.compare(file1, file2)).thenReturn(1);
|
when(comparator.compare(file1, file2)).thenReturn(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user