I am using Java NIO for my socket connections, and my protocol is text based, so I need to be able to convert Strings to ByteBuffers before writing them to the SocketChannel
Answer by Adamski is a good one and describes the steps in an encoding operation when using the general encode method (that takes a byte buffer as one of the inputs)
However, the method in question (in this discussion) is a variant of encode - encode(CharBuffer in). This is a convenience method that implements the entire encoding operation. (Please see java docs reference in P.S.)
As per the docs, This method should therefore not be invoked if an encoding operation is already in progress (which is what is happening in ZenBlender's code -- using static encoder/decoder in a multi threaded environment).
Personally, I like to use convenience methods (over the more general encode/decode methods) as they take away the burden by performing all the steps under the covers.
ZenBlender and Adamski have already suggested multiple ways options to safely do this in their comments. Listing them all here:
P.S.
java docs references:
Unless things have changed, you're better off with
public static ByteBuffer str_to_bb(String msg, Charset charset){
return ByteBuffer.wrap(msg.getBytes(charset));
}
public static String bb_to_str(ByteBuffer buffer, Charset charset){
byte[] bytes;
if(buffer.hasArray()) {
bytes = buffer.array();
} else {
bytes = new byte[buffer.remaining()];
buffer.get(bytes);
}
return new String(bytes, charset);
}
Usually buffer.hasArray() will be either always true or always false depending on your use case. In practice, unless you really want it to work under any circumstances, it's safe to optimize away the branch you don't need.
Check out the CharsetEncoder and CharsetDecoder API descriptions - You should follow a specific sequence of method calls to avoid this problem. For example, for CharsetEncoder
:
reset
method, unless it has not been used before;encode
method zero or more times, as long as additional input may be available, passing false
for the endOfInput argument and filling the input buffer and flushing the output buffer between invocations;encode
method one final time, passing true
for the endOfInput argument; and thenflush
method so that the encoder can flush any internal state to the output buffer.By the way, this is the same approach I am using for NIO although some of my colleagues are converting each char directly to a byte in the knowledge they are only using ASCII, which I can imagine is probably faster.