12
\$\begingroup\$

I have a couple of fields which I am trying to put together into a single ByteBuffer before storing it in a Cassandra database.

That byte array which I will be writing into Cassandra is made up of three byte arrays as described below:

short employeeId = 32767;
long lastModifiedDate = "1379811105109L";
byte[] attributeValue = os.toByteArray();

Now, I will write employeeId, lastModifiedDate and attributeValue together into a single byte array and that resulting byte array will be written into Cassandra. I will then have my C++ program retrieve that byte array data from Cassandra and then deserialize it to extract employeeId, lastModifiedDate and attributeValue from it.

To do this, I am using ByyteBuffer with BigEndian byte order format.

I have put up this code together:

public static void main(String[] args) throws Exception {

        String text = "Byte Buffer Test";
        byte[] attributeValue = text.getBytes();

        long lastModifiedDate = 1289811105109L;
        short employeeId = 32767;

        int size = 2 + 8 + 4 + attributeValue.length; // short is 2 bytes, long 8 and int 4

        ByteBuffer bbuf = ByteBuffer.allocate(size); 

        bbuf.order(ByteOrder.BIG_ENDIAN);
        bbuf.putShort(employeeId);
        bbuf.putLong(lastModifiedDate);
        bbuf.putInt(attributeValue.length);
        bbuf.put(attributeValue);

        bbuf.rewind();

        // best approach is copy the internal buffer
        byte[] bytesToStore = new byte[size];
        bbuf.get(bytesToStore);

        // write bytesToStore in Cassandra...

        // Now retrieve the Byte Array data from Cassandra and deserialize it...
        byte[] allWrittenBytesTest = bytesToStore;//magicFunctionToRetrieveDataFromCassandra();

        ByteBuffer bb = ByteBuffer.wrap(allWrittenBytesTest);

        bb.order(ByteOrder.BIG_ENDIAN);
        bb.rewind();

        short extractEmployeeId = bb.getShort();
        long extractLastModifiedDate = bb.getLong();
        int extractAttributeValueLength = bb.getInt();
        byte[] extractAttributeValue = new byte[extractAttributeValueLength];

        bb.get(extractAttributeValue); // read attributeValue from the remaining buffer

        System.out.println(extractEmployeeId);
        System.out.println(extractLastModifiedDate);
        System.out.println(new String(extractAttributeValue));

}
  1. Is there any better way of doing this?
  2. Are there some minor improvements that can be made here?
  3. Can anyone take a look and let me know whether this is the right way to use ByteBuffer? This is my first time using it, so I'm having a bit of a problem.
\$\endgroup\$
7
\$\begingroup\$

I cannot see anything wrong with the way you are using it. The example is a little contrived (given that you are not actually using cassandra), and the only things I can see that look odd are a direct result of that.

Bottom line is that it appears to be a fine piece of code (which is perhaps why there have been no reviews so far).

As for some nit-picky things:

I don't like that you are hard-coding the size of the buffer (on the write-side): int size = 2 + 8 + 4 + attributeValue.length is 'ugly'.

I tend to do th 'overkill' approach and use a buffer that is always too big. I find memory is cheap for the occasional buffer (even up to a couple of megs of memory...). I then make the buffer a thread-local so that I am not always creating new buffers. In your example it is trivial because it is all in the main method.... but for a 'real' program you may want to reconsider. If you know your data will always be less than, say 4K, I would instead do the following on the write side:

// a 'smaprt' implementation will make the buffer a ThreadLocal,
// and will also make it grow, if needed.
ByteBuffer bbuf = ByteBuffer.allocate(4096);
bbuf.order(ByteOrder.BIG_ENDIAN);

Then, your code should reset the buffer before using it:

bbuf.clear(); // position to 0, limit to capacity
bbuf.putShort(employeeId);
bbuf.putLong(lastModifiedDate);
bbuf.putInt(attributeValue.length);
bbuf.put(attributeValue);

Now, instead of doing a rewind(), do a flip()

bbuf.flip(); // limit to position, position to 0
byte[] bytesToStore = new byte[bbuf.limit()];
bbuf.get(bytesToStore);

The advantage of the above is that you do not need to manually track the size of your data, and you do not need to keep allocating new ByteBuffers each time,

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.