This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch fix/close-shield-interfaces2
in repository https://gitbox.apache.org/repos/asf/commons-io.git
The following commit(s) were added to refs/heads/fix/close-shield-interfaces2
by this push:
new f4c52d3c1 Fixes interface discovery in `CloseShieldChannel`
f4c52d3c1 is described below
commit f4c52d3c10f8999088d79b27de011edc46983254
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Tue Oct 14 19:12:06 2025 +0200
Fixes interface discovery in `CloseShieldChannel`
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.
---
.../commons/io/channels/CloseShieldChannel.java | 10 ++++++---
.../io/channels/CloseShieldChannelTest.java | 24 ++++++++++++++++++++++
2 files changed, 31 insertions(+), 3 deletions(-)
diff --git
a/src/main/java/org/apache/commons/io/channels/CloseShieldChannel.java
b/src/main/java/org/apache/commons/io/channels/CloseShieldChannel.java
index a9a462da7..bde0feb25 100644
--- a/src/main/java/org/apache/commons/io/channels/CloseShieldChannel.java
+++ b/src/main/java/org/apache/commons/io/channels/CloseShieldChannel.java
@@ -40,11 +40,15 @@ public final class CloseShieldChannel {
private static final Class<?>[] EMPTY = {};
private static Set<Class<?>> collectChannelInterfaces(final Class<?> type,
final Set<Class<?>> out) {
+ Class<?> currentType = type;
// Visit interfaces
- for (final Class<?> iface : type.getInterfaces()) {
- if (Channel.class.isAssignableFrom(iface) && out.add(iface)) {
- collectChannelInterfaces(iface, out);
+ while (currentType != null) {
+ for (final Class<?> iface : currentType.getInterfaces()) {
+ if (Channel.class.isAssignableFrom(iface) && out.add(iface)) {
+ collectChannelInterfaces(iface, out);
+ }
}
+ currentType = currentType.getSuperclass();
}
return out;
}
diff --git
a/src/test/java/org/apache/commons/io/channels/CloseShieldChannelTest.java
b/src/test/java/org/apache/commons/io/channels/CloseShieldChannelTest.java
index ac7e85b7a..42a23f0af 100644
--- a/src/test/java/org/apache/commons/io/channels/CloseShieldChannelTest.java
+++ b/src/test/java/org/apache/commons/io/channels/CloseShieldChannelTest.java
@@ -20,6 +20,7 @@
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -32,11 +33,13 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import java.io.IOException;
import java.nio.channels.AsynchronousByteChannel;
import java.nio.channels.AsynchronousChannel;
import java.nio.channels.ByteChannel;
import java.nio.channels.Channel;
import java.nio.channels.ClosedChannelException;
+import java.nio.channels.FileChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.InterruptibleChannel;
import java.nio.channels.MulticastChannel;
@@ -45,9 +48,12 @@
import java.nio.channels.ScatteringByteChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.channels.WritableByteChannel;
+import java.nio.file.Path;
import java.util.stream.Stream;
+import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@@ -280,4 +286,22 @@ void testWritableByteChannelMethods() throws Exception {
assertThrows(ClosedChannelException.class, () -> shield.write(null));
verifyNoMoreInteractions(channel);
}
+
+ @Test
+ void testCorrectlyDetectsInterfaces(@TempDir Path tempDir) throws
IOException {
+ final Path testFile = tempDir.resolve("test.txt");
+ FileUtils.touch(testFile.toFile());
+ try (FileChannel channel = FileChannel.open(testFile); Channel shield
= CloseShieldChannel.wrap(channel)) {
+ assertInstanceOf(SeekableByteChannel.class, shield);
+ assertInstanceOf(GatheringByteChannel.class, shield);
+ assertInstanceOf(WritableByteChannel.class, shield);
+ assertInstanceOf(ScatteringByteChannel.class, shield);
+ assertInstanceOf(ReadableByteChannel.class, shield);
+ assertInstanceOf(InterruptibleChannel.class, shield);
+ assertInstanceOf(ByteChannel.class, shield);
+ assertInstanceOf(Channel.class, shield);
+ // These are not interfaces, so can not be implemented
+ assertFalse(shield instanceof FileChannel, "not FileChannel");
+ }
+ }
}