ByteProcessor shouldn't throw checked exception

Motivation:
There is no need for ByteProcessor to throw a checked exception.
The declared checked exception causes unnecessary code complications just to propagate it.
This can be cleaned up.

Modification:
ByteProcessor.process no longer declares to throw a checked exception, and all the places that were trying to cope with the checked exception have been simplified.

Result:
Simpler code.
This commit is contained in:
Chris Vest 2020-11-03 16:12:13 +01:00
parent 2a1e031fa3
commit b70d0fa6e3
16 changed files with 72 additions and 128 deletions

View File

@ -1262,58 +1262,37 @@ public abstract class AbstractByteBuf extends ByteBuf {
@Override
public int forEachByte(ByteProcessor processor) {
ensureAccessible();
try {
return forEachByteAsc0(readerIndex, writerIndex, processor);
} catch (Exception e) {
PlatformDependent.throwException(e);
return -1;
}
return forEachByteAsc0(readerIndex, writerIndex, processor);
}
@Override
public int forEachByte(int index, int length, ByteProcessor processor) {
checkIndex(index, length);
try {
return forEachByteAsc0(index, index + length, processor);
} catch (Exception e) {
PlatformDependent.throwException(e);
return -1;
}
return forEachByteAsc0(index, index + length, processor);
}
int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
int forEachByteAsc0(int start, int end, ByteProcessor processor) {
for (; start < end; ++start) {
if (!processor.process(_getByte(start))) {
return start;
}
}
return -1;
}
@Override
public int forEachByteDesc(ByteProcessor processor) {
ensureAccessible();
try {
return forEachByteDesc0(writerIndex - 1, readerIndex, processor);
} catch (Exception e) {
PlatformDependent.throwException(e);
return -1;
}
return forEachByteDesc0(writerIndex - 1, readerIndex, processor);
}
@Override
public int forEachByteDesc(int index, int length, ByteProcessor processor) {
checkIndex(index, length);
try {
return forEachByteDesc0(index + length - 1, index, processor);
} catch (Exception e) {
PlatformDependent.throwException(e);
return -1;
}
return forEachByteDesc0(index + length - 1, index, processor);
}
int forEachByteDesc0(int rStart, final int rEnd, ByteProcessor processor) throws Exception {
int forEachByteDesc0(int rStart, final int rEnd, ByteProcessor processor) {
for (; rStart >= rEnd; --rStart) {
if (!processor.process(_getByte(rStart))) {
return rStart;

View File

@ -660,7 +660,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
}
@Override
protected int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
protected int forEachByteAsc0(int start, int end, ByteProcessor processor) {
if (end <= start) {
return -1;
}
@ -686,7 +686,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
}
@Override
protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) throws Exception {
protected int forEachByteDesc0(int rStart, int rEnd, ByteProcessor processor) {
if (rEnd > rStart) { // rStart *and* rEnd are inclusive
return -1;
}

View File

@ -2284,7 +2284,7 @@ public abstract class AbstractByteBufTest {
int i = CAPACITY / 4;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
assertThat(value, is((byte) (i + 1)));
lastIndex.set(i);
i ++;
@ -2307,7 +2307,7 @@ public abstract class AbstractByteBufTest {
int i = CAPACITY / 3;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
assertThat(value, is((byte) (i + 1)));
if (i == stop) {
return false;
@ -4608,7 +4608,7 @@ public abstract class AbstractByteBufTest {
private int index = bytes.length - 1;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
bytes[index--] = value;
return true;
}
@ -4631,7 +4631,7 @@ public abstract class AbstractByteBufTest {
private int index;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
bytes[index++] = value;
return true;
}
@ -4804,7 +4804,7 @@ public abstract class AbstractByteBufTest {
private static final class TestByteProcessor implements ByteProcessor {
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
return true;
}
}

View File

@ -24,7 +24,6 @@ import io.netty.handler.codec.HeadersUtils;
import io.netty.handler.codec.ValueConverter;
import io.netty.util.AsciiString;
import io.netty.util.ByteProcessor;
import io.netty.util.internal.PlatformDependent;
import java.util.ArrayList;
import java.util.Calendar;
@ -50,14 +49,10 @@ public class DefaultHttpHeaders extends HttpHeaders {
};
static final NameValidator<CharSequence> HttpNameValidator = name -> {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException("empty headers are not allowed [" + name + "]");
throw new IllegalArgumentException("empty headers are not allowed [" + name + ']');
}
if (name instanceof AsciiString) {
try {
((AsciiString) name).forEachByte(HEADER_NAME_VALIDATOR);
} catch (Exception e) {
PlatformDependent.throwException(e);
}
((AsciiString) name).forEachByte(HEADER_NAME_VALIDATOR);
} else {
// Go through each character in the name
for (int index = 0; index < name.length(); ++index) {
@ -73,7 +68,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
/**
* <b>Warning!</b> Setting <code>validate</code> to <code>false</code> will mean that Netty won't
* <b>Warning!</b> Setting {@code validate} to {@code false} will mean that Netty won't
* validate & protect against user-supplied header values that are malicious.
* This can leave your server implementation vulnerable to
* <a href="https://cwe.mitre.org/data/definitions/113.html">

View File

@ -936,7 +936,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
}
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
char nextByte = (char) (value & 0xFF);
if (nextByte == HttpConstants.LF) {
int len = seq.length();
@ -983,7 +983,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
}
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
if (currentState == State.SKIP_CONTROL_CHARS) {
char c = (char) (value & 0xFF);
if (Character.isISOControl(c) || Character.isWhitespace(c)) {

View File

@ -706,7 +706,7 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
private static final class UrlEncodedDetector implements ByteProcessor {
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
return value != '%' && value != '+';
}
}

View File

@ -84,7 +84,7 @@ final class Utf8Validator implements ByteProcessor {
}
@Override
public boolean process(byte b) throws Exception {
public boolean process(byte b) {
byte type = TYPES[b & 0xFF];
codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;

View File

@ -38,18 +38,7 @@ public class DefaultHttp2Headers
"empty headers are not allowed [%s]", name));
}
if (name instanceof AsciiString) {
final int index;
try {
index = ((AsciiString) name).forEachByte(HTTP2_NAME_VALIDATOR_PROCESSOR);
} catch (Http2Exception e) {
PlatformDependent.throwException(e);
return;
} catch (Throwable t) {
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR, t,
"unexpected error. invalid header name [%s]", name));
return;
}
int index = ((AsciiString) name).forEachByte(HTTP2_NAME_VALIDATOR_PROCESSOR);
if (index != -1) {
PlatformDependent.throwException(connectionError(PROTOCOL_ERROR,
"invalid header name [%s]", name));
@ -109,7 +98,7 @@ public class DefaultHttp2Headers
@Override
public Http2Headers clear() {
this.firstNonPseudo = head;
firstNonPseudo = head;
return super.clear();
}

View File

@ -70,11 +70,9 @@ final class HpackHuffmanEncoder {
requireNonNull(out, "out");
if (data instanceof AsciiString) {
AsciiString string = (AsciiString) data;
encodeProcessor.out = out;
try {
encodeProcessor.out = out;
string.forEachByte(encodeProcessor);
} catch (Exception e) {
PlatformDependent.throwException(e);
} finally {
encodeProcessor.end();
}
@ -118,14 +116,9 @@ final class HpackHuffmanEncoder {
int getEncodedLength(CharSequence data) {
if (data instanceof AsciiString) {
AsciiString string = (AsciiString) data;
try {
encodedLengthProcessor.reset();
string.forEachByte(encodedLengthProcessor);
return encodedLengthProcessor.length();
} catch (Exception e) {
PlatformDependent.throwException(e);
return -1;
}
encodedLengthProcessor.reset();
string.forEachByte(encodedLengthProcessor);
return encodedLengthProcessor.length();
} else {
return getEncodedLengthSlowPath(data);
}

View File

@ -427,23 +427,17 @@ public final class HttpConversionUtil {
while (valuesIter.hasNext()) {
AsciiString lowerCased = AsciiString.of(valuesIter.next()).toLowerCase();
try {
int index = lowerCased.forEachByte(FIND_COMMA);
if (index != -1) {
int start = 0;
do {
result.add(lowerCased.subSequence(start, index, false).trim(), EMPTY_STRING);
start = index + 1;
} while (start < lowerCased.length() &&
(index = lowerCased.forEachByte(start, lowerCased.length() - start, FIND_COMMA)) != -1);
result.add(lowerCased.subSequence(start, lowerCased.length(), false).trim(), EMPTY_STRING);
} else {
result.add(lowerCased.trim(), EMPTY_STRING);
}
} catch (Exception e) {
// This is not expect to happen because FIND_COMMA never throws but must be caught
// because of the ByteProcessor interface.
throw new IllegalStateException(e);
int index = lowerCased.forEachByte(FIND_COMMA);
if (index != -1) {
int start = 0;
do {
result.add(lowerCased.subSequence(start, index, false).trim(), EMPTY_STRING);
start = index + 1;
} while (start < lowerCased.length() &&
(index = lowerCased.forEachByte(start, lowerCased.length() - start, FIND_COMMA)) != -1);
result.add(lowerCased.subSequence(start, lowerCased.length(), false).trim(), EMPTY_STRING);
} else {
result.add(lowerCased.trim(), EMPTY_STRING);
}
}
return result;
@ -489,27 +483,21 @@ public final class HttpConversionUtil {
AsciiString value = AsciiString.of(entry.getValue());
// split up cookies to allow for better compression
// https://tools.ietf.org/html/rfc7540#section-8.1.2.5
try {
int index = value.forEachByte(FIND_SEMI_COLON);
if (index != -1) {
int start = 0;
do {
out.add(COOKIE, value.subSequence(start, index, false));
// skip 2 characters "; " (see https://tools.ietf.org/html/rfc6265#section-4.2.1)
start = index + 2;
} while (start < value.length() &&
(index = value.forEachByte(start, value.length() - start, FIND_SEMI_COLON)) != -1);
if (start >= value.length()) {
throw new IllegalArgumentException("cookie value is of unexpected format: " + value);
}
out.add(COOKIE, value.subSequence(start, value.length(), false));
} else {
out.add(COOKIE, value);
int index = value.forEachByte(FIND_SEMI_COLON);
if (index != -1) {
int start = 0;
do {
out.add(COOKIE, value.subSequence(start, index, false));
// skip 2 characters "; " (see https://tools.ietf.org/html/rfc6265#section-4.2.1)
start = index + 2;
} while (start < value.length() &&
(index = value.forEachByte(start, value.length() - start, FIND_SEMI_COLON)) != -1);
if (start >= value.length()) {
throw new IllegalArgumentException("cookie value is of unexpected format: " + value);
}
} catch (Exception e) {
// This is not expect to happen because FIND_SEMI_COLON never throws but must be caught
// because of the ByteProcessor interface.
throw new IllegalStateException(e);
out.add(COOKIE, value.subSequence(start, value.length(), false));
} else {
out.add(COOKIE, value);
}
} else {
out.add(aName, entry.getValue());

View File

@ -311,7 +311,7 @@ public final class RedisDecoder extends ByteToMessageDecoder {
private long result;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
if (value < '0' || value > '9') {
throw new RedisCodecException("bad byte in number: " + value);
}

View File

@ -274,7 +274,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
}
@Override
public boolean process(byte nextByte) throws Exception {
public boolean process(byte nextByte) {
if (nextByte == StompConstants.CR) {
++lineLength;
return true;
@ -353,7 +353,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
}
@Override
public boolean process(byte nextByte) throws Exception {
public boolean process(byte nextByte) {
if (nextByte == StompConstants.COLON) {
if (name == null) {
AppendableCharSequence charSeq = charSequence();

View File

@ -331,7 +331,7 @@ public final class Base64 {
}
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
if (value > 0) {
byte sbiDecode = decodabet[value];
if (sbiDecode >= WHITE_SPACE_ENC) { // White space, Equals sign or better

View File

@ -255,7 +255,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
* @return {@code -1} if the processor iterated to or beyond the end of the readable bytes.
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
*/
public int forEachByte(ByteProcessor visitor) throws Exception {
public int forEachByte(ByteProcessor visitor) {
return forEachByte0(0, length(), visitor);
}
@ -266,7 +266,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
* @return {@code -1} if the processor iterated to or beyond the end of the specified area.
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
*/
public int forEachByte(int index, int length, ByteProcessor visitor) throws Exception {
public int forEachByte(int index, int length, ByteProcessor visitor) {
if (isOutOfBounds(index, length, length())) {
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
+ ") <= " + "length(" + length() + ')');
@ -274,7 +274,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
return forEachByte0(index, length, visitor);
}
private int forEachByte0(int index, int length, ByteProcessor visitor) throws Exception {
private int forEachByte0(int index, int length, ByteProcessor visitor) {
final int len = offset + index + length;
for (int i = offset + index; i < len; ++i) {
if (!visitor.process(value[i])) {
@ -290,7 +290,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
* @return {@code -1} if the processor iterated to or beyond the beginning of the readable bytes.
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
*/
public int forEachByteDesc(ByteProcessor visitor) throws Exception {
public int forEachByteDesc(ByteProcessor visitor) {
return forEachByteDesc0(0, length(), visitor);
}
@ -301,7 +301,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
* @return {@code -1} if the processor iterated to or beyond the beginning of the specified area.
* The last-visited index If the {@link ByteProcessor#process(byte)} returned {@code false}.
*/
public int forEachByteDesc(int index, int length, ByteProcessor visitor) throws Exception {
public int forEachByteDesc(int index, int length, ByteProcessor visitor) {
if (isOutOfBounds(index, length, length())) {
throw new IndexOutOfBoundsException("expected: " + "0 <= index(" + index + ") <= start + length(" + length
+ ") <= " + "length(" + length() + ')');
@ -309,7 +309,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
return forEachByteDesc0(index, length, visitor);
}
private int forEachByteDesc0(int index, int length, ByteProcessor visitor) throws Exception {
private int forEachByteDesc0(int index, int length, ByteProcessor visitor) {
final int end = offset + index;
for (int i = offset + index + length - 1; i >= end; --i) {
if (!visitor.process(value[i])) {

View File

@ -124,5 +124,5 @@ public interface ByteProcessor {
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
* {@code false} if the processor wants to stop handling bytes and abort the loop.
*/
boolean process(byte value) throws Exception;
boolean process(byte value);
}

View File

@ -78,13 +78,13 @@ public class AsciiStringMemoryTest {
}
@Test
public void forEachTest() throws Exception {
public void forEachTest() {
final AtomicReference<Integer> aCount = new AtomicReference<>(0);
final AtomicReference<Integer> bCount = new AtomicReference<>(0);
aAsciiString.forEachByte(new ByteProcessor() {
int i;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
assertEquals("failed at index: " + i, value, bAsciiString.byteAt(i++));
aCount.set(aCount.get() + 1);
return true;
@ -93,7 +93,7 @@ public class AsciiStringMemoryTest {
bAsciiString.forEachByte(new ByteProcessor() {
int i;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
assertEquals("failed at index: " + i, value, aAsciiString.byteAt(i++));
bCount.set(bCount.get() + 1);
return true;
@ -104,25 +104,25 @@ public class AsciiStringMemoryTest {
}
@Test
public void forEachWithIndexEndTest() throws Exception {
public void forEachWithIndexEndTest() {
assertNotEquals(-1, aAsciiString.forEachByte(aAsciiString.length() - 1,
1, new IndexOfProcessor(aAsciiString.byteAt(aAsciiString.length() - 1))));
}
@Test
public void forEachWithIndexBeginTest() throws Exception {
public void forEachWithIndexBeginTest() {
assertNotEquals(-1, aAsciiString.forEachByte(0,
1, new IndexOfProcessor(aAsciiString.byteAt(0))));
}
@Test
public void forEachDescTest() throws Exception {
public void forEachDescTest() {
final AtomicReference<Integer> aCount = new AtomicReference<>(0);
final AtomicReference<Integer> bCount = new AtomicReference<>(0);
aAsciiString.forEachByteDesc(new ByteProcessor() {
int i = 1;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
assertEquals("failed at index: " + i, value, bAsciiString.byteAt(bAsciiString.length() - (i++)));
aCount.set(aCount.get() + 1);
return true;
@ -131,7 +131,7 @@ public class AsciiStringMemoryTest {
bAsciiString.forEachByteDesc(new ByteProcessor() {
int i = 1;
@Override
public boolean process(byte value) throws Exception {
public boolean process(byte value) {
assertEquals("failed at index: " + i, value, aAsciiString.byteAt(aAsciiString.length() - (i++)));
bCount.set(bCount.get() + 1);
return true;
@ -142,13 +142,13 @@ public class AsciiStringMemoryTest {
}
@Test
public void forEachDescWithIndexEndTest() throws Exception {
public void forEachDescWithIndexEndTest() {
assertNotEquals(-1, bAsciiString.forEachByteDesc(bAsciiString.length() - 1,
1, new IndexOfProcessor(bAsciiString.byteAt(bAsciiString.length() - 1))));
}
@Test
public void forEachDescWithIndexBeginTest() throws Exception {
public void forEachDescWithIndexBeginTest() {
assertNotEquals(-1, bAsciiString.forEachByteDesc(0,
1, new IndexOfProcessor(bAsciiString.byteAt(0))));
}