Skip to content

Commit

Permalink
Make ByteCursor implementations static final inner classes (#11662)
Browse files Browse the repository at this point in the history
Motivation:
People might be tempted to use mocking tools like Mockito.spy() on the ByteCursors.
By returning instances where the concrete classes are final, we will be forcing integrators to use stub-like wrappers instead.
Such stubs are more well-behaved since they are implemented in terms of the real instance.
This prevents the mocked objects from (easily) producing behaviour that violates the API specification.

Modification:
All ByteCursor implementations have changed from using anonymous inner classes, to using static-final named inner classes.

Result:
The concrete ByteCursor classes can no longer be extended via byte code generation, such as from mocking tools.
  • Loading branch information
chrisvest committed Sep 8, 2021
1 parent 3a23094 commit 3cbb41a
Show file tree
Hide file tree
Showing 4 changed files with 303 additions and 237 deletions.
224 changes: 126 additions & 98 deletions buffer/src/main/java/io/netty/buffer/api/CompositeBuffer.java
Expand Up @@ -518,54 +518,7 @@ public ByteCursor openCursor(int fromOffset, int length) {
int off = fromOffset - offsets[startBufferIndex];
Buffer startBuf = bufs[startBufferIndex];
ByteCursor startCursor = startBuf.openCursor(off, Math.min(startBuf.capacity() - off, length));
return new ByteCursor() {
int index = fromOffset;
final int end = fromOffset + length;
int bufferIndex = startBufferIndex;
int initOffset = startCursor.currentOffset();
ByteCursor cursor = startCursor;
byte byteValue = -1;

@Override
public boolean readByte() {
if (cursor.readByte()) {
byteValue = cursor.getByte();
return true;
}
if (bytesLeft() > 0) {
nextCursor();
cursor.readByte();
byteValue = cursor.getByte();
return true;
}
return false;
}

private void nextCursor() {
bufferIndex++;
Buffer nextBuf = bufs[bufferIndex];
cursor = nextBuf.openCursor(0, Math.min(nextBuf.capacity(), bytesLeft()));
initOffset = 0;
}

@Override
public byte getByte() {
return byteValue;
}

@Override
public int currentOffset() {
int currOff = cursor.currentOffset();
index += currOff - initOffset;
initOffset = currOff;
return index;
}

@Override
public int bytesLeft() {
return end - currentOffset();
}
};
return new ForwardCompositeByteCursor(bufs, fromOffset, length, startBufferIndex, startCursor);
}

@Override
Expand All @@ -584,56 +537,7 @@ public ByteCursor openReverseCursor(int fromOffset, int length) {
int off = fromOffset - offsets[startBufferIndex];
Buffer startBuf = bufs[startBufferIndex];
ByteCursor startCursor = startBuf.openReverseCursor(off, Math.min(off + 1, length));
return new ByteCursor() {
int index = fromOffset;
final int end = fromOffset - length;
int bufferIndex = startBufferIndex;
int initOffset = startCursor.currentOffset();
ByteCursor cursor = startCursor;
byte byteValue = -1;

@Override
public boolean readByte() {
if (cursor.readByte()) {
byteValue = cursor.getByte();
return true;
}
if (bytesLeft() > 0) {
nextCursor();
cursor.readByte();
byteValue = cursor.getByte();
return true;
}
return false;
}

private void nextCursor() {
bufferIndex--;
Buffer nextBuf = bufs[bufferIndex];
int length = Math.min(nextBuf.capacity(), bytesLeft());
int offset = nextBuf.capacity() - 1;
cursor = nextBuf.openReverseCursor(offset, length);
initOffset = offset;
}

@Override
public byte getByte() {
return byteValue;
}

@Override
public int currentOffset() {
int currOff = cursor.currentOffset();
index -= initOffset - currOff;
initOffset = currOff;
return index;
}

@Override
public int bytesLeft() {
return currentOffset() - end;
}
};
return new ReverseCompositeByteCursor(bufs, fromOffset, length, startBufferIndex, startCursor);
}

@Override
Expand Down Expand Up @@ -1732,4 +1636,128 @@ private void write(int woff, int value) {
}
}
// </editor-fold>

private static final class ForwardCompositeByteCursor implements ByteCursor {
final Buffer[] bufs;
int index;
final int end;
int bufferIndex;
int initOffset;
ByteCursor cursor;
byte byteValue;

ForwardCompositeByteCursor(Buffer[] bufs, int fromOffset, int length, int startBufferIndex,
ByteCursor startCursor) {
this.bufs = bufs;
index = fromOffset;
end = fromOffset + length;
bufferIndex = startBufferIndex;
initOffset = startCursor.currentOffset();
cursor = startCursor;
byteValue = -1;
}

@Override
public boolean readByte() {
if (cursor.readByte()) {
byteValue = cursor.getByte();
return true;
}
if (bytesLeft() > 0) {
nextCursor();
cursor.readByte();
byteValue = cursor.getByte();
return true;
}
return false;
}

private void nextCursor() {
bufferIndex++;
Buffer nextBuf = bufs[bufferIndex];
cursor = nextBuf.openCursor(0, Math.min(nextBuf.capacity(), bytesLeft()));
initOffset = 0;
}

@Override
public byte getByte() {
return byteValue;
}

@Override
public int currentOffset() {
int currOff = cursor.currentOffset();
index += currOff - initOffset;
initOffset = currOff;
return index;
}

@Override
public int bytesLeft() {
return end - currentOffset();
}
}

private static final class ReverseCompositeByteCursor implements ByteCursor {
final Buffer[] bufs;
int index;
final int end;
int bufferIndex;
int initOffset;
ByteCursor cursor;
byte byteValue;

ReverseCompositeByteCursor(Buffer[] bufs, int fromOffset, int length,
int startBufferIndex, ByteCursor startCursor) {
this.bufs = bufs;
index = fromOffset;
end = fromOffset - length;
bufferIndex = startBufferIndex;
initOffset = startCursor.currentOffset();
cursor = startCursor;
byteValue = -1;
}

@Override
public boolean readByte() {
if (cursor.readByte()) {
byteValue = cursor.getByte();
return true;
}
if (bytesLeft() > 0) {
nextCursor();
cursor.readByte();
byteValue = cursor.getByte();
return true;
}
return false;
}

private void nextCursor() {
bufferIndex--;
Buffer nextBuf = bufs[bufferIndex];
int length = Math.min(nextBuf.capacity(), bytesLeft());
int offset = nextBuf.capacity() - 1;
cursor = nextBuf.openReverseCursor(offset, length);
initOffset = offset;
}

@Override
public byte getByte() {
return byteValue;
}

@Override
public int currentOffset() {
int currOff = cursor.currentOffset();
index -= initOffset - currOff;
initOffset = currOff;
return index;
}

@Override
public int bytesLeft() {
return currentOffset() - end;
}
}
}

0 comments on commit 3cbb41a

Please sign in to comment.