From e2d4e222431014506d592af7d379824e21034970 Mon Sep 17 00:00:00 2001 From: Xiaoyan Lin Date: Fri, 4 Mar 2016 23:28:25 -0800 Subject: [PATCH] Add CharsetUtil.encoder/decoder() methods Motivation: See #3321 Modifications: 1. Add CharsetUtil.encoder/decoder() methods 2. Deprecate CharsetUtil.getEncoder/getDecoder() methods Result: Users can use new CharsetUtil.encoder/decoder() to specify error actions --- .../java/io/netty/buffer/ByteBufUtil.java | 6 +- .../handler/codec/socks/SocksAuthRequest.java | 2 +- .../main/java/io/netty/util/AsciiString.java | 4 +- .../main/java/io/netty/util/CharsetUtil.java | 107 ++++++++++++++---- 4 files changed, 91 insertions(+), 28 deletions(-) diff --git a/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java b/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java index 0bcde1330c..8f049fac5a 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBufUtil.java @@ -61,7 +61,7 @@ public final class ByteBufUtil { private static final int MAX_CHAR_BUFFER_SIZE; private static final int THREAD_LOCAL_BUFFER_SIZE; private static final int MAX_BYTES_PER_CHAR_UTF8 = - (int) CharsetUtil.getEncoder(CharsetUtil.UTF_8).maxBytesPerChar(); + (int) CharsetUtil.encoder(CharsetUtil.UTF_8).maxBytesPerChar(); static final ByteBufAllocator DEFAULT_ALLOCATOR; @@ -511,7 +511,7 @@ public final class ByteBufUtil { } static ByteBuf encodeString0(ByteBufAllocator alloc, boolean enforceHeap, CharBuffer src, Charset charset) { - final CharsetEncoder encoder = CharsetUtil.getEncoder(charset); + final CharsetEncoder encoder = CharsetUtil.encoder(charset); int length = (int) ((double) src.remaining() * encoder.maxBytesPerChar()); boolean release = true; final ByteBuf dst; @@ -547,7 +547,7 @@ public final class ByteBufUtil { if (len == 0) { return StringUtil.EMPTY_STRING; } - final CharsetDecoder decoder = CharsetUtil.getDecoder(charset); + final CharsetDecoder decoder = CharsetUtil.decoder(charset); final int maxLength = (int) ((double) len * decoder.maxCharsPerByte()); CharBuffer dst = CHAR_BUFFERS.get(); if (dst.length() < maxLength) { diff --git a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequest.java b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequest.java index 5b6d56f0b3..83196a0eaf 100644 --- a/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequest.java +++ b/codec-socks/src/main/java/io/netty/handler/codec/socks/SocksAuthRequest.java @@ -27,7 +27,7 @@ import java.nio.charset.CharsetEncoder; * @see SocksAuthRequestDecoder */ public final class SocksAuthRequest extends SocksRequest { - private static final CharsetEncoder asciiEncoder = CharsetUtil.getEncoder(CharsetUtil.US_ASCII); + private static final CharsetEncoder asciiEncoder = CharsetUtil.encoder(CharsetUtil.US_ASCII); private static final SocksSubnegotiationVersion SUBNEGOTIATION_VERSION = SocksSubnegotiationVersion.AUTH_PASSWORD; private final String username; private final String password; diff --git a/common/src/main/java/io/netty/util/AsciiString.java b/common/src/main/java/io/netty/util/AsciiString.java index 8431a7c095..98c9b3aee8 100644 --- a/common/src/main/java/io/netty/util/AsciiString.java +++ b/common/src/main/java/io/netty/util/AsciiString.java @@ -194,7 +194,7 @@ public final class AsciiString implements CharSequence, Comparable */ public AsciiString(char[] value, Charset charset, int start, int length) { CharBuffer cbuf = CharBuffer.wrap(value, start, length); - CharsetEncoder encoder = CharsetUtil.getEncoder(charset); + CharsetEncoder encoder = CharsetUtil.encoder(charset); ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * length)); encoder.encode(cbuf, nativeBuffer, true); final int bufferOffset = nativeBuffer.arrayOffset(); @@ -241,7 +241,7 @@ public final class AsciiString implements CharSequence, Comparable */ public AsciiString(CharSequence value, Charset charset, int start, int length) { CharBuffer cbuf = CharBuffer.wrap(value, start, start + length); - CharsetEncoder encoder = CharsetUtil.getEncoder(charset); + CharsetEncoder encoder = CharsetUtil.encoder(charset); ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * length)); encoder.encode(cbuf, nativeBuffer, true); final int offset = nativeBuffer.arrayOffset(); diff --git a/common/src/main/java/io/netty/util/CharsetUtil.java b/common/src/main/java/io/netty/util/CharsetUtil.java index 7da00dd749..8c6c0965de 100644 --- a/common/src/main/java/io/netty/util/CharsetUtil.java +++ b/common/src/main/java/io/netty/util/CharsetUtil.java @@ -16,6 +16,7 @@ package io.netty.util; import io.netty.util.internal.InternalThreadLocalMap; +import static io.netty.util.internal.ObjectUtil.checkNotNull; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; @@ -67,51 +68,113 @@ public final class CharsetUtil { public static Charset[] values() { return CHARSETS; } /** - * Returns a cached thread-local {@link CharsetEncoder} for the specified - * charset. + * @deprecated Use {@link #encoder(Charset)}. */ + @Deprecated public static CharsetEncoder getEncoder(Charset charset) { - if (charset == null) { - throw new NullPointerException("charset"); - } + return encoder(charset); + } + + /** + * Returns a new {@link CharsetEncoder} for the {@link Charset} with specified error actions. + * + * @param charset The specified charset + * @param malformedInputAction The encoder's action for malformed-input errors + * @param unmappableCharacterAction The encoder's action for unmappable-character errors + * @return The encoder for the specified charset + */ + public static CharsetEncoder encoder(Charset charset, CodingErrorAction malformedInputAction, + CodingErrorAction unmappableCharacterAction) { + checkNotNull(charset, "charset"); + CharsetEncoder e = charset.newEncoder(); + e.onMalformedInput(malformedInputAction).onUnmappableCharacter(unmappableCharacterAction); + return e; + } + + /** + * Returns a new {@link CharsetEncoder} for the {@link Charset} with the specified error action. + * + * @param charset The specified charset + * @param codingErrorAction The encoder's action for malformed-input and unmappable-character errors + * @return The encoder for the specified charset + */ + public static CharsetEncoder encoder(Charset charset, CodingErrorAction codingErrorAction) { + return encoder(charset, codingErrorAction, codingErrorAction); + } + + /** + * Returns a cached thread-local {@link CharsetEncoder} for the specified {@link Charset}. + * + * @param charset The specified charset + * @return The encoder for the specified charset + */ + public static CharsetEncoder encoder(Charset charset) { + checkNotNull(charset, "charset"); Map map = InternalThreadLocalMap.get().charsetEncoderCache(); CharsetEncoder e = map.get(charset); if (e != null) { - e.reset(); - e.onMalformedInput(CodingErrorAction.REPLACE); - e.onUnmappableCharacter(CodingErrorAction.REPLACE); + e.reset().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE); return e; } - e = charset.newEncoder(); - e.onMalformedInput(CodingErrorAction.REPLACE); - e.onUnmappableCharacter(CodingErrorAction.REPLACE); + e = encoder(charset, CodingErrorAction.REPLACE, CodingErrorAction.REPLACE); map.put(charset, e); return e; } /** - * Returns a cached thread-local {@link CharsetDecoder} for the specified - * charset. + * @deprecated Use {@link #decoder(Charset)}. */ + @Deprecated public static CharsetDecoder getDecoder(Charset charset) { - if (charset == null) { - throw new NullPointerException("charset"); - } + return decoder(charset); + } + + /** + * Returns a new {@link CharsetDecoder} for the {@link Charset} with specified error actions. + * + * @param charset The specified charset + * @param malformedInputAction The decoder's action for malformed-input errors + * @param unmappableCharacterAction The decoder's action for unmappable-character errors + * @return The decoder for the specified charset + */ + public static CharsetDecoder decoder(Charset charset, CodingErrorAction malformedInputAction, + CodingErrorAction unmappableCharacterAction) { + checkNotNull(charset, "charset"); + CharsetDecoder d = charset.newDecoder(); + d.onMalformedInput(malformedInputAction).onUnmappableCharacter(unmappableCharacterAction); + return d; + } + + /** + * Returns a new {@link CharsetDecoder} for the {@link Charset} with the specified error action. + * + * @param charset The specified charset + * @param codingErrorAction The decoder's action for malformed-input and unmappable-character errors + * @return The decoder for the specified charset + */ + public static CharsetDecoder decoder(Charset charset, CodingErrorAction codingErrorAction) { + return decoder(charset, codingErrorAction, codingErrorAction); + } + + /** + * Returns a cached thread-local {@link CharsetDecoder} for the specified {@link Charset}. + * + * @param charset The specified charset + * @return The decoder for the specified charset + */ + public static CharsetDecoder decoder(Charset charset) { + checkNotNull(charset, "charset"); Map map = InternalThreadLocalMap.get().charsetDecoderCache(); CharsetDecoder d = map.get(charset); if (d != null) { - d.reset(); - d.onMalformedInput(CodingErrorAction.REPLACE); - d.onUnmappableCharacter(CodingErrorAction.REPLACE); + d.reset().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE); return d; } - d = charset.newDecoder(); - d.onMalformedInput(CodingErrorAction.REPLACE); - d.onUnmappableCharacter(CodingErrorAction.REPLACE); + d = decoder(charset, CodingErrorAction.REPLACE, CodingErrorAction.REPLACE); map.put(charset, d); return d; }