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
This commit is contained in:
Xiaoyan Lin 2016-03-04 23:28:25 -08:00 committed by Norman Maurer
parent d8658989e1
commit e2d4e22243
4 changed files with 91 additions and 28 deletions

View File

@ -61,7 +61,7 @@ public final class ByteBufUtil {
private static final int MAX_CHAR_BUFFER_SIZE; private static final int MAX_CHAR_BUFFER_SIZE;
private static final int THREAD_LOCAL_BUFFER_SIZE; private static final int THREAD_LOCAL_BUFFER_SIZE;
private static final int MAX_BYTES_PER_CHAR_UTF8 = 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; static final ByteBufAllocator DEFAULT_ALLOCATOR;
@ -511,7 +511,7 @@ public final class ByteBufUtil {
} }
static ByteBuf encodeString0(ByteBufAllocator alloc, boolean enforceHeap, CharBuffer src, Charset charset) { 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()); int length = (int) ((double) src.remaining() * encoder.maxBytesPerChar());
boolean release = true; boolean release = true;
final ByteBuf dst; final ByteBuf dst;
@ -547,7 +547,7 @@ public final class ByteBufUtil {
if (len == 0) { if (len == 0) {
return StringUtil.EMPTY_STRING; return StringUtil.EMPTY_STRING;
} }
final CharsetDecoder decoder = CharsetUtil.getDecoder(charset); final CharsetDecoder decoder = CharsetUtil.decoder(charset);
final int maxLength = (int) ((double) len * decoder.maxCharsPerByte()); final int maxLength = (int) ((double) len * decoder.maxCharsPerByte());
CharBuffer dst = CHAR_BUFFERS.get(); CharBuffer dst = CHAR_BUFFERS.get();
if (dst.length() < maxLength) { if (dst.length() < maxLength) {

View File

@ -27,7 +27,7 @@ import java.nio.charset.CharsetEncoder;
* @see SocksAuthRequestDecoder * @see SocksAuthRequestDecoder
*/ */
public final class SocksAuthRequest extends SocksRequest { 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 static final SocksSubnegotiationVersion SUBNEGOTIATION_VERSION = SocksSubnegotiationVersion.AUTH_PASSWORD;
private final String username; private final String username;
private final String password; private final String password;

View File

@ -194,7 +194,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
*/ */
public AsciiString(char[] value, Charset charset, int start, int length) { public AsciiString(char[] value, Charset charset, int start, int length) {
CharBuffer cbuf = CharBuffer.wrap(value, start, 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)); ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * length));
encoder.encode(cbuf, nativeBuffer, true); encoder.encode(cbuf, nativeBuffer, true);
final int bufferOffset = nativeBuffer.arrayOffset(); final int bufferOffset = nativeBuffer.arrayOffset();
@ -241,7 +241,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
*/ */
public AsciiString(CharSequence value, Charset charset, int start, int length) { public AsciiString(CharSequence value, Charset charset, int start, int length) {
CharBuffer cbuf = CharBuffer.wrap(value, start, start + 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)); ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * length));
encoder.encode(cbuf, nativeBuffer, true); encoder.encode(cbuf, nativeBuffer, true);
final int offset = nativeBuffer.arrayOffset(); final int offset = nativeBuffer.arrayOffset();

View File

@ -16,6 +16,7 @@
package io.netty.util; package io.netty.util;
import io.netty.util.internal.InternalThreadLocalMap; import io.netty.util.internal.InternalThreadLocalMap;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetDecoder;
@ -67,51 +68,113 @@ public final class CharsetUtil {
public static Charset[] values() { return CHARSETS; } public static Charset[] values() { return CHARSETS; }
/** /**
* Returns a cached thread-local {@link CharsetEncoder} for the specified * @deprecated Use {@link #encoder(Charset)}.
* <tt>charset</tt>.
*/ */
@Deprecated
public static CharsetEncoder getEncoder(Charset charset) { public static CharsetEncoder getEncoder(Charset charset) {
if (charset == null) { return encoder(charset);
throw new NullPointerException("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 <code>charset</code>
*/
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 <code>charset</code>
*/
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 <code>charset</code>
*/
public static CharsetEncoder encoder(Charset charset) {
checkNotNull(charset, "charset");
Map<Charset, CharsetEncoder> map = InternalThreadLocalMap.get().charsetEncoderCache(); Map<Charset, CharsetEncoder> map = InternalThreadLocalMap.get().charsetEncoderCache();
CharsetEncoder e = map.get(charset); CharsetEncoder e = map.get(charset);
if (e != null) { if (e != null) {
e.reset(); e.reset().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
e.onMalformedInput(CodingErrorAction.REPLACE);
e.onUnmappableCharacter(CodingErrorAction.REPLACE);
return e; return e;
} }
e = charset.newEncoder(); e = encoder(charset, CodingErrorAction.REPLACE, CodingErrorAction.REPLACE);
e.onMalformedInput(CodingErrorAction.REPLACE);
e.onUnmappableCharacter(CodingErrorAction.REPLACE);
map.put(charset, e); map.put(charset, e);
return e; return e;
} }
/** /**
* Returns a cached thread-local {@link CharsetDecoder} for the specified * @deprecated Use {@link #decoder(Charset)}.
* <tt>charset</tt>.
*/ */
@Deprecated
public static CharsetDecoder getDecoder(Charset charset) { public static CharsetDecoder getDecoder(Charset charset) {
if (charset == null) { return decoder(charset);
throw new NullPointerException("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 <code>charset</code>
*/
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 <code>charset</code>
*/
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 <code>charset</code>
*/
public static CharsetDecoder decoder(Charset charset) {
checkNotNull(charset, "charset");
Map<Charset, CharsetDecoder> map = InternalThreadLocalMap.get().charsetDecoderCache(); Map<Charset, CharsetDecoder> map = InternalThreadLocalMap.get().charsetDecoderCache();
CharsetDecoder d = map.get(charset); CharsetDecoder d = map.get(charset);
if (d != null) { if (d != null) {
d.reset(); d.reset().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
d.onMalformedInput(CodingErrorAction.REPLACE);
d.onUnmappableCharacter(CodingErrorAction.REPLACE);
return d; return d;
} }
d = charset.newDecoder(); d = decoder(charset, CodingErrorAction.REPLACE, CodingErrorAction.REPLACE);
d.onMalformedInput(CodingErrorAction.REPLACE);
d.onUnmappableCharacter(CodingErrorAction.REPLACE);
map.put(charset, d); map.put(charset, d);
return d; return d;
} }