Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ByteBuffer getInt() question

We are using Java ByteBuffer for socket communication with a C++ server. We know Java is Big-endian and Socket communication is also Big-endian. So whenever the byte stream received and put into a ByteBuffer by Java, we call getInt() to get the value. No problem, no conversion.

But if somehow we specifically set the ByteBuffer byte order to Little-endian (my co-worker actually did this),

  1. will the Java automatically convert the Big-endian into the Little-endian when the data is put into the ByteBuffer?

  2. Then the getInt() of the Little-endian version will return a right value to you?

I guess the answer to above two questions are yes. But when I try to verify my guessing and try to find how the getInt() works in ByteBuffer, I found it is an abstract method. The only subclass of ByteBuffer is the MappedByteBuffer class which didn't implement the abstract getInt(). So where is the implementation of the getInt() method?

For the sending, because we are using Little-endian ByteBuffer, we need to convert them into a Big-endian bytes before we put onto the socket.

like image 264
5YrsLaterDBA Avatar asked Aug 04 '11 15:08

5YrsLaterDBA


2 Answers

ByteBuffer will automatically use the byte order you specify. (Or Big endian by default)

 ByteBuffer bb =
 // to use big endian
 bb.order(ByteOrder.BIG_ENDIAN);

 // to use little endian
 bb.order(ByteOrder.LITTLE_ENDIAN);

 // use the natural order of the system.
 bb.order(ByteOrder.nativeOrder()); 

Both direct and heap ByteBuffers will re-order bytes as you specifiy.

like image 87
Peter Lawrey Avatar answered Sep 28 '22 07:09

Peter Lawrey


So where is the implementation of the getInt() method?

ByteBuffer is indeed an abstract class. There are several way in which byte buffers can be created:

  • allocate;
  • wrap;
  • allocateDirect.

In my JDK, these create instances of internal classes HeapByteBuffer and DirectByteBuffer. Their respective getInt functions are as follows:

// HeapByteBuffer

public int getInt() {
    return Bits.getInt(this, ix(nextGetIndex(4)), bigEndian);
}

public int getInt(int i) {
    return Bits.getInt(this, ix(checkIndex(i, 4)), bigEndian);
}

and

// DirectByteBuffer

private int getInt(long a) {
    if (unaligned) {
        int x = unsafe.getInt(a);
        return (nativeByteOrder ? x : Bits.swap(x));
    }
    return Bits.getInt(a, bigEndian);
}

public int getInt() {
    return getInt(ix(nextGetIndex((1 << 2))));
}

public int getInt(int i) {
    return getInt(ix(checkIndex(i, (1 << 2))));
}

In the above, nativeByteOrder and bigEndian are two boolean members indicating respectively -- and somewhat redundantly -- whether the configured byte order: (a) matches the native byte order; (b) is big endian.

like image 29
NPE Avatar answered Sep 28 '22 06:09

NPE