views:

122

answers:

2

Hi,

While writing a message on wire, I want to write down the number of bytes in the data followed by the data.

Message format:

{num of bytes in data}{data}

I can do this by writing the data to a temporary byteArrayOutput stream and then obtaining the byte array size from it, writing the size followed by the byte array. This approach involves a lot of overhead, viz. unnecessary creation of temporary byte arrays, creation of temporary streams, etc.

Do we have a better (considering both CPU and garbage creation) way of achieving this?

A: 

Here’s what I would do, in order of preference.

  1. Don’t bother about memory consumption and stuff. Most likely this already is the optimal solution unless it takes a lot of time to create the byte representation of your data so that creating it twice is a noticable impact.
  2. (Actually this would be more like #37 on my list, with #2 to #36 being empty.) Include a method in your all your data objects that can calculate the size of the byte representation and takes less resources than it would to create the byte representation.
Bombe
@Bombe: This mixes code concerned with the wire protocol representation in with the business logic of each object. I much prefer to have separate classes to handle protocol encoding / decoding. It means I can vary the protocol independently of my business objects and potentially support multiple protocols.
Adamski
That means you already have some encoder/decoder classes? If so, just integerate the getLength() method in those. Otherwise you probably won’t have any other choice than writing the objects into a byte array first (either via `ByteArrayOutputStream` or `ByteBuffer` as shown above).
Bombe
Thanks Bombie. This is a solution I've tried. However I also want to support java object serialization and don't want to write custom serializations for every object I write.
baskin
+1  A: 

A typical approach would be to introduce a re-useable ByteBuffer. For example:

ByteBuffer out = ...

int oldPos = out.position(); // Remember current position.
out.position(oldPos + 2); // Leave space for message length (unsigned short)

out.putInt(...); // Write out data.

// Finally prepend buffer with number of bytes.
out.putShort(oldPos, (short)(out.position() - (oldPos + 2)));

Once the buffer is populated you could then send the data over the wire using SocketChannel.write(ByteBuffer) (assuming you are using NIO).

Adamski