3

its my first post so go easy on me :). I'm working on refactoring some connectivity code to use non-blocking IO and am running into a null point exception when calling byteButter.put(byte[]) or byteBuffer.put(byte[],index,length). The exception is occurring on this line

localBuffer.put(sendLengthBuffer,0,sendLengthBuffer.length);

The strange thing is the null pointer only occurs on the first time I call the method, all subsequent attempts to write are functioning as intended.

Code:

public void write(SocketChannel sc,PayloadLength pl,ArrayBlockingQueue<byte[]> queue) throws IOException{
        while(!queue.isEmpty()){
            byte[] message = queue.poll();
            if(message != null && message.length > 0){
                if(bufferHasRemaining()){
                    SystemLogger.getLogger().logMe(LoggerLevel.INFO, this.getClass().getSimpleName(), "writer compacting");
                    localBuffer.compact();
                }else{
                    SystemLogger.getLogger().logMe(LoggerLevel.INFO, this.getClass().getSimpleName(), "writer compacting");
                    localBuffer.clear();
                }
                //calculate the message length
                byte[] sendLengthBuffer = new byte[pl.getLengthSize()];
                pl.parseWriteLength(sendLengthBuffer, message.length);
                localBuffer.put(sendLengthBuffer,0,sendLengthBuffer.length);
                localBuffer.put(message,0,message.length);
                localBuffer.flip();

//              //write until buffer is empty
//              //TODO: potential infinite loop here
//              while(localBuffer.hasRemaining()){
//                  sc.write(localBuffer);
//              }
                sc.write(localBuffer);
                if(bufferHasRemaining()){
                    //could not write all bytes to channel, most likely the sockets write buffer is full
                    break;
                }

            }
        }

And here is the stack trace:

EXCEPTION: null - null
STACK TRACE:
java.nio.HeapByteBuffer.put(HeapByteBuffer.java:189)
com.discover.paymentservices.commons.net.nio.NIOWriteHandler.write(NIOWriteHandler.java:57)
com.discover.paymentservices.tibco.channel.nio.BaseNIOConnectionHandler.run(BaseNIOConnectionHandler.java:603)

****EDIT***** Turns out the null pointer was a result of calling byteBuffer.compact() immediately after allocating the byteBuffer. Still not certain why the null pointer gets thrown on the put() in this scenario but I seem to have found a solution. Thanks for the comments!

JoeN
  • 51
  • 1
  • 7
  • 1
    Possible duplicate of [What is a Null Pointer Exception, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-null-pointer-exception-and-how-do-i-fix-it) – ΦXocę 웃 Пepeúpa ツ Jan 20 '16 at 14:48
  • Upvote because the question shows code and isnt a trivial affair: localBuffer and sendLengthBuffer seem to be non-null. Now please show the offending line(s) in HeapByteBuffer. – Markus Kull Jan 20 '16 at 14:54
  • It isn't actually happening on that line: it is happening inside the `HeapByteBuffer` class on line 189. – Andy Turner Jan 20 '16 at 14:54
  • Please show the code where the HeapByteBuffer is instantiated – Henk De Boer Jan 20 '16 at 14:57
  • @HenkDeBoer - this is created in the constructor public NIOWriteHandler(){ localBuffer = ByteBuffer.allocate(1024); } – JoeN Jan 20 '16 at 15:24
  • @AndyTurner - This has been a problem. I an running java 1.8. All of the source code I've been able to dig up shows a comment or an empty line at line number 189 of the HeapByteBuffer class. – JoeN Jan 20 '16 at 15:28
  • @HenkDeBoer my understanding is that allocate(int) returns a HeapedByteBuffer whereas allocateDirect(int) returns a direct byte buffer. The ByteBuffer class is abstract – JoeN Jan 20 '16 at 15:31
  • Of course, silly of me. Thanks for the clarification. – Henk De Boer Jan 20 '16 at 15:31

1 Answers1

0

It appears that the local buffer is being created in another thread, however the fields of the local buffer are not thread safe so you don't see them immediately.

I suggest using use a ThreadLocal direct byte buffer. A direct byte buffer is more efficient than a heap buffer as it doesn't require an additional copy to native memory.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • You're assumption that the local buffer is being created in another thread is correct, however I'm not sure why this would cause a null pointer. The ByteBuffer gets allocated when I create a new instance of BaseNIOConnectionHandler. This object is also a thread, which is the only thread interacting with the ByteBuffer. In Short..Thread 1 creates BaseNIOConnectionHandler (also creating the ByteBuffers in the constructor), Thread 1 starts BaseNIOConnectionHandler which interacts with the ByteBuffers – JoeN Jan 20 '16 at 16:29
  • @JoeN If you create an object in one thread and it's field are not final, there is no thread safety guarantees and if you pass it to another thread without using a memory barrier any of it's fields could have an old value, like `null` for the underlying `byte[]` however, when you access it a little later, the byte[] field is visible and it works. – Peter Lawrey Jan 20 '16 at 17:45
  • I moved the creation and manipulation and still the issue persists...I did find a resolution, see the edit to my post for more details – JoeN Jan 21 '16 at 17:32