Skip to content

Commit 2542ebc

Browse files
authored
Fixes interface discovery in CloseShieldChannel (#800)
This PR is split from #799. The `CloseShieldChannel` implementation only inspects interfaces **directly** implemented by the given channel’s class, ignoring those inherited from its superclasses. As a result, proxies for types such as `FileChannel` does not expose any of the interfaces declared on `FileChannel` itself.
1 parent b95cbfa commit 2542ebc

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

src/main/java/org/apache/commons/io/channels/CloseShieldChannel.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@ public final class CloseShieldChannel {
4040
private static final Class<?>[] EMPTY = {};
4141

4242
private static Set<Class<?>> collectChannelInterfaces(final Class<?> type, final Set<Class<?>> out) {
43+
Class<?> currentType = type;
4344
// Visit interfaces
44-
for (final Class<?> iface : type.getInterfaces()) {
45-
if (Channel.class.isAssignableFrom(iface) && out.add(iface)) {
46-
collectChannelInterfaces(iface, out);
45+
while (currentType != null) {
46+
for (final Class<?> iface : currentType.getInterfaces()) {
47+
if (Channel.class.isAssignableFrom(iface) && out.add(iface)) {
48+
collectChannelInterfaces(iface, out);
49+
}
4750
}
51+
currentType = currentType.getSuperclass();
4852
}
4953
return out;
5054
}

src/test/java/org/apache/commons/io/channels/CloseShieldChannelTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
2121
import static org.junit.jupiter.api.Assertions.assertEquals;
2222
import static org.junit.jupiter.api.Assertions.assertFalse;
23+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
2324
import static org.junit.jupiter.api.Assertions.assertNotSame;
2425
import static org.junit.jupiter.api.Assertions.assertSame;
2526
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -32,11 +33,13 @@
3233
import static org.mockito.Mockito.verifyNoMoreInteractions;
3334
import static org.mockito.Mockito.when;
3435

36+
import java.io.IOException;
3537
import java.nio.channels.AsynchronousByteChannel;
3638
import java.nio.channels.AsynchronousChannel;
3739
import java.nio.channels.ByteChannel;
3840
import java.nio.channels.Channel;
3941
import java.nio.channels.ClosedChannelException;
42+
import java.nio.channels.FileChannel;
4043
import java.nio.channels.GatheringByteChannel;
4144
import java.nio.channels.InterruptibleChannel;
4245
import java.nio.channels.MulticastChannel;
@@ -45,9 +48,12 @@
4548
import java.nio.channels.ScatteringByteChannel;
4649
import java.nio.channels.SeekableByteChannel;
4750
import java.nio.channels.WritableByteChannel;
51+
import java.nio.file.Path;
4852
import java.util.stream.Stream;
4953

54+
import org.apache.commons.io.FileUtils;
5055
import org.junit.jupiter.api.Test;
56+
import org.junit.jupiter.api.io.TempDir;
5157
import org.junit.jupiter.params.ParameterizedTest;
5258
import org.junit.jupiter.params.provider.MethodSource;
5359

@@ -280,4 +286,22 @@ void testWritableByteChannelMethods() throws Exception {
280286
assertThrows(ClosedChannelException.class, () -> shield.write(null));
281287
verifyNoMoreInteractions(channel);
282288
}
289+
290+
@Test
291+
void testCorrectlyDetectsInterfaces(@TempDir Path tempDir) throws IOException {
292+
final Path testFile = tempDir.resolve("test.txt");
293+
FileUtils.touch(testFile.toFile());
294+
try (FileChannel channel = FileChannel.open(testFile); Channel shield = CloseShieldChannel.wrap(channel)) {
295+
assertInstanceOf(SeekableByteChannel.class, shield);
296+
assertInstanceOf(GatheringByteChannel.class, shield);
297+
assertInstanceOf(WritableByteChannel.class, shield);
298+
assertInstanceOf(ScatteringByteChannel.class, shield);
299+
assertInstanceOf(ReadableByteChannel.class, shield);
300+
assertInstanceOf(InterruptibleChannel.class, shield);
301+
assertInstanceOf(ByteChannel.class, shield);
302+
assertInstanceOf(Channel.class, shield);
303+
// These are not interfaces, so can not be implemented
304+
assertFalse(shield instanceof FileChannel, "not FileChannel");
305+
}
306+
}
283307
}

0 commit comments

Comments
 (0)