Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ed20f2a
[IO-856] Try test on all OSs for GitHub CI
garydgregory Nov 10, 2024
cb5359f
Merge remote-tracking branch 'upstream/master'
garydgregory Oct 19, 2025
3fe03be
Merge remote-tracking branch 'upstream/master'
garydgregory Nov 3, 2025
b5747b1
Merge remote-tracking branch 'upstream/master'
garydgregory Dec 7, 2025
515ae1e
Merge remote-tracking branch 'upstream/master'
garydgregory Dec 10, 2025
8192a78
Merge remote-tracking branch 'upstream/master'
garydgregory Dec 13, 2025
c780069
Merge remote-tracking branch 'upstream/master'
garydgregory Dec 14, 2025
6924d71
Merge remote-tracking branch 'upstream/master'
garydgregory Jan 1, 2026
3b77da2
Merge remote-tracking branch 'upstream/master'
garydgregory Feb 5, 2026
abdd9e1
Merge remote-tracking branch 'upstream/master'
garydgregory Feb 15, 2026
fb91287
Merge remote-tracking branch 'upstream/master'
garydgregory Feb 19, 2026
b165180
Merge remote-tracking branch 'upstream/master'
garydgregory Feb 21, 2026
2dd0ddf
Merge remote-tracking branch 'upstream/master'
garydgregory Feb 21, 2026
bd3f8b5
Merge remote-tracking branch 'upstream/master'
garydgregory Feb 22, 2026
b34ea84
Merge remote-tracking branch 'upstream/master'
garydgregory Mar 25, 2026
c74f241
Merge remote-tracking branch 'upstream/master'
garydgregory Mar 25, 2026
1d2b754
Merge remote-tracking branch 'upstream/master'
garydgregory Mar 26, 2026
c884a14
Merge remote-tracking branch 'upstream/master'
garydgregory Mar 26, 2026
02cab72
Merge remote-tracking branch 'upstream/master'
garydgregory Mar 26, 2026
cd3271f
Merge remote-tracking branch 'upstream/master'
garydgregory Mar 28, 2026
c6a8cba
Merge remote-tracking branch 'upstream/master'
garydgregory Mar 30, 2026
21b928b
Merge remote-tracking branch 'upstream/master'
garydgregory Apr 5, 2026
270d342
Merge remote-tracking branch 'upstream/master'
garydgregory Apr 6, 2026
4f3d009
Merge remote-tracking branch 'upstream/master'
garydgregory Apr 7, 2026
c8c7881
Merge remote-tracking branch 'upstream/master'
garydgregory Apr 8, 2026
7f28a8d
Javadoc
garydgregory Apr 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@ public static Builder builder() {
/**
* Constructs a new channel backed directly by the given byte array.
*
* <p>The channel initially contains the full contents of the array, with its
* size set to {@code bytes.length} and its position set to {@code 0}.</p>
* <p>
* The channel initially contains the full contents of the array, with its size set to {@code bytes.length} and its position set to {@code 0}.
* </p>
*
* <p>Reads and writes operate on the shared array.
* If a write operation extends beyond the current capacity, the channel will
* automatically allocate a larger backing array and copy the existing contents.</p>
* <p>
* Reads and writes operate on the shared array. If a write operation extends beyond the current capacity, the channel will automatically allocate a larger
* backing array and copy the existing contents.
* </p>
*
* @param bytes The byte array to wrap, must not be {@code null}
* @return A new channel that uses the given array as its initial backing store.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@
/**
* Creates a close-shielding proxy for a {@link Channel}.
*
* <p>The returned proxy implements all {@link Channel} sub-interfaces that are both supported by this implementation and actually implemented by the given
* delegate.</p>
*
* <p>The following interfaces are supported:</p>
*
* <p>
* The returned proxy implements all {@link Channel} sub-interfaces that are both supported by this implementation and actually implemented by the given
* delegate.
* </p>
* <p>
* The following interfaces are supported:
* </p>
* <ul>
* <li>{@link AsynchronousChannel}</li>
* <li>{@link ByteChannel}</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
import java.util.Objects;
import java.util.Set;

/**
* An {@link InvocationHandler} supporting the implementation of {@link CloseShieldChannel}.
*/
final class CloseShieldChannelHandler implements InvocationHandler {

private static final Set<Class<? extends Channel>> SUPPORTED_INTERFACES;
Expand Down Expand Up @@ -154,7 +157,7 @@ private Object invokeObjectMethod(final Object proxy, final Method method, final
return false;
}
default:
// Not possible, all non-final Object methods are handled above
// Not possible, all non-final Object methods are handled above.
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@

/**
* A {@link ByteChannel} filter which delegates to the wrapped {@link ByteChannel}.
* <p>
* A {@code FilterByteChannel} wraps some other channel, which it uses as its basic source of data, possibly transforming the data along the way or providing
* additional functionality. The class {@code FilterByteChannel} itself simply overrides methods of {@code ByteChannel} with versions that pass all requests to
* the wrapped channel. Subclasses of {@code FilterByteChannel} may of course override any methods declared or inherited by {@code FilterByteChannel}, and may
* also provide additional fields and methods.
* </p>
* <p>
* You construct s simple instance with the {@link FilterByteChannel#FilterByteChannel(ByteChannel) channel constructor} and more advanced instances through the
* {@link Builder}.
* </p>
*
* @param <C> the {@link ByteChannel} type.
* @see FilterInputStream
Expand Down Expand Up @@ -94,6 +104,15 @@ public static Builder forByteChannel() {
super(builder);
}

/**
* Constructs a new instance.
*
* @param byteChannel The channel to wrap.
*/
public FilterByteChannel(final C byteChannel) {
super(byteChannel);
}

@Override
public int read(final ByteBuffer dst) throws IOException {
return channel.read(dst);
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/apache/commons/io/channels/FilterChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@

/**
* A {@link Channel} filter which delegates to the wrapped {@link Channel}.
* <p>
* A {@code FilterChannel} wraps some other channel, which it uses as its basic source of data, possibly transforming the data along the way or providing
* additional functionality. The class {@code FilterChannel} itself simply overrides methods of {@code Channel} with versions that pass all requests to the
* wrapped channel. Subclasses of {@code FilterChannel} may of course override any methods declared or inherited by {@code FilterChannel}, and may also provide
* additional fields and methods.
* </p>
* <p>
* You construct s simple instance with the {@link FilterChannel#FilterChannel(Channel) channel constructor} and more advanced instances through the
* {@link Builder}.
* </p>
*
* @param <C> the {@link Channel} type.
* @see FilterInputStream
Expand Down Expand Up @@ -103,6 +113,15 @@ public static Builder forChannel() {
channel = (C) builder.getChannel(Channel.class);
}

/**
* Constructs a new instance.
*
* @param channel The channel to wrap.
*/
public FilterChannel(final C channel) {
this.channel = channel;
}

@Override
public void close() throws IOException {
channel.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,89 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Objects;

import org.apache.commons.io.build.AbstractStreamBuilder;

/**
* Filters a {@link FileChannel}.
* <p>
* A {@code FilterFileChannel} wraps some other channel, which it uses as its basic source of data, possibly transforming the data along the way or providing
* additional functionality. The class {@code FilterFileChannel} itself simply overrides methods of {@code FileChannel} with versions that pass all requests to
* the wrapped channel. Subclasses of {@code FilterFileChannel} may of course override any methods declared or inherited by {@code FilterFileChannel}, and may
* also provide additional fields and methods.
* </p>
* <p>
* You construct s simple instance with the {@link FilterFileChannel#FilterFileChannel(FileChannel) channel constructor} and more advanced instances through the
* {@link Builder}.
* </p>
*
* @since 2.22.0
*/
public class FilterFileChannel extends FileChannel {

/**
* Builds instances of {@link FilterFileChannel} for subclasses.
*
* @param <F> The {@link FilterFileChannel} type.
* @param <C> The {@link Channel} type wrapped by the FilterChannel.
* @param <B> The builder type.
*/
public abstract static class AbstractBuilder<F extends FilterFileChannel, C extends FileChannel, B extends AbstractBuilder<F, C, B>>
extends AbstractStreamBuilder<F, AbstractBuilder<F, C, B>> {

/**
* Constructs instance for subclasses.
*/
protected AbstractBuilder() {
// empty
}
}

/**
* Builds instances of {@link FilterFileChannel}.
*/
public static class Builder extends AbstractBuilder<FilterFileChannel, FileChannel, Builder> {

/**
* Builds instances of {@link FilterChannel}.
*/
protected Builder() {
// empty
}

@Override
public FilterFileChannel get() throws IOException {
return new FilterFileChannel(this);
}
}

/**
* Creates a new {@link Builder}.
*
* @return a new {@link Builder}.
*/
public static Builder forFilterFileChannel() {
return new Builder();
}

final FileChannel fileChannel;

FilterFileChannel(final FileChannel fileChannel) {
private FilterFileChannel(final Builder builder) throws IOException {
this.fileChannel = builder.getChannel(FileChannel.class);
}

/**
* Constructs a new instance.
*
* @param fileChannel the file channel to wrap.
*/
public FilterFileChannel(final FileChannel fileChannel) {
this.fileChannel = Objects.requireNonNull(fileChannel, "fileChannel");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@

/**
* A {@link ReadableByteChannel} filter which delegates to the wrapped {@link ReadableByteChannel}.
* <p>
* A {@code FilterReadableByteChannel} wraps some other channel, which it uses as its basic source of data, possibly transforming the data along the way or
* providing additional functionality. The class {@code FilterReadableByteChannel} itself simply overrides methods of {@code ReadableByteChannel} with versions
* that pass all requests to the wrapped channel. Subclasses of {@code FilterReadableByteChannel} may of course override any methods declared or inherited by
* {@code FilterReadableByteChannel}, and may also provide additional fields and methods.
* </p>
* <p>
* You construct s simple instance with the {@link FilterReadableByteChannel#FilterReadableByteChannel(ReadableByteChannel) channel constructor} and more
* advanced instances through the {@link Builder}.
* </p>
*
* @param <C> the {@link ReadableByteChannel} type.
* @see FilterInputStream
Expand Down Expand Up @@ -94,6 +104,15 @@ public static Builder forReadableByteChannel() {
super(builder);
}

/**
* Constructs a new instance.
*
* @param channel The channel to wrap.
*/
public FilterReadableByteChannel(final C channel) {
super(channel);
}

@Override
public int read(final ByteBuffer dst) throws IOException {
return channel.read(dst);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@

/**
* A {@link SeekableByteChannel} filter which delegates to the wrapped {@link SeekableByteChannel}.
* <p>
* A {@code FilterSeekableByteChannel} wraps some other channel, which it uses as its basic source of data, possibly transforming the data along the way or
* providing additional functionality. The class {@code FilterSeekableByteChannel} itself simply overrides methods of {@code SeekableByteChannel} with versions
* that pass all requests to the wrapped channel. Subclasses of {@code FilterSeekableByteChannel} may of course override any methods declared or inherited by
* {@code FilterSeekableByteChannel}, and may also provide additional fields and methods.
* </p>
* <p>
* You construct s simple instance with the {@link FilterSeekableByteChannel#FilterSeekableByteChannel(SeekableByteChannel) Channel constructor} and more
* advanced instances through the {@link Builder}.
* </p>
*
* @param <C> the {@link SeekableByteChannel} type.
* @see FilterInputStream
Expand Down Expand Up @@ -93,6 +103,15 @@ public static Builder forSeekableByteChannel() {
super(builder);
}

/**
* Constructs a new instance.
*
* @param channel The channel to wrap.
*/
public FilterSeekableByteChannel(final C channel) {
super(channel);
}

@Override
public long position() throws IOException {
return channel.position();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@

/**
* A {@link WritableByteChannel} filter which delegates to the wrapped {@link WritableByteChannel}.
* <p>
* A {@code FilterWritableByteChannel} wraps some other channel, which it uses as its basic source of data, possibly transforming the data along the way or
* providing additional functionality. The class {@code FilterWritableByteChannel} itself simply overrides methods of {@code WritableByteChannel} with versions
* that pass all requests to the wrapped channel. Subclasses of {@code FilterWritableByteChannel} may of course override any methods declared or inherited by
* {@code WritableByteChannel}, and may also provide additional fields and methods.
* </p>
* <p>
* You construct s simple instance with the {@link FilterWritableByteChannel#FilterWritableByteChannel(WritableByteChannel) Channel constructor} and more
* advanced instances through the {@link Builder}.
* </p>
*
* @param <C> the {@link WritableByteChannel} type.
* @see FilterInputStream
Expand Down Expand Up @@ -94,6 +104,15 @@ public static Builder forWritableByteChannel() {
super(builder);
}

/**
* Constructs a new instance.
*
* @param channel The channel to wrap.
*/
public FilterWritableByteChannel(final C channel) {
super(channel);
}

@Override
public int write(final ByteBuffer src) throws IOException {
return channel.write(src);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class CloseShieldChannelFilterByteChannelTest {
@BeforeEach
void setUp() throws IOException {
mockChannel = mock(ByteChannel.class);
filterChannel = FilterByteChannel.forByteChannel().setChannel(mockChannel).get();
filterChannel = new FilterByteChannel<>(mockChannel);
shield = CloseShieldChannel.wrap(filterChannel);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,14 @@ private FileChannel mockFileChannel() {
return mock(FileChannel.class);
}

@Test
void testBuilderForNothing() throws IOException {
assertThrows(IllegalStateException.class, () -> FilterFileChannel.forFilterFileChannel().get());
}

@Test
void testConstructorRequiresNonNullChannel() {
assertThrows(NullPointerException.class, () -> new FilterFileChannel(null));
assertThrows(NullPointerException.class, () -> new FilterFileChannel((FileChannel) null));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
class FilterReadableByteChannelTest {

private FilterReadableByteChannel<ReadableByteChannel> build(final ReadableByteChannel channel) throws IOException {
return FilterReadableByteChannel.forReadableByteChannel().setChannel(channel).get();
return new FilterReadableByteChannel(channel);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
class FilterSeekableByteChannelTest {

private FilterSeekableByteChannel<SeekableByteChannel> build(final SeekableByteChannel channel) throws IOException {
return FilterSeekableByteChannel.forSeekableByteChannel().setChannel(channel).get();
return new FilterSeekableByteChannel(channel);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
class FilterWritableByteChannelTest {

private FilterWritableByteChannel<WritableByteChannel> build(final WritableByteChannel channel) throws IOException {
return FilterWritableByteChannel.forWritableByteChannel().setChannel(channel).get();
return new FilterWritableByteChannel(channel);
}

@Test
Expand Down
Loading