I am hitting a problem with Netty at class initialization. I thought static fields are always initialized before instance fields but apparently this is not the case:
- Class AbstractByteBuff contains a
static final ResourceLeakDetector<ByteBuf> leakDetector
- Class
AbstractReferenceCountedByteBuf extends AbstractByteBuff
- Class
UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf
The first time an UnpooledUnsafeDirectByteBuf is created, a Null Pointer Exception is thrown in its constructor:
protected UnpooledUnsafeDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(maxCapacity);
if (alloc == null) {
throw new NullPointerException("alloc");
}
if (initialCapacity < 0) {
throw new IllegalArgumentException("initialCapacity: " + initialCapacity);
}
if (maxCapacity < 0) {
throw new IllegalArgumentException("maxCapacity: " + maxCapacity);
}
if (initialCapacity > maxCapacity) {
throw new IllegalArgumentException(String.format(
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
}
this.alloc = alloc;
setByteBuffer(ByteBuffer.allocateDirect(initialCapacity));
leak = leakDetector.open(this);
}
The exception is thrown from the code leak = leakDetector.open(this);
. By inspecting with intellij Idea I have found out that the leakDetector
variable is null. How this is possible? It's a static variable initialized in the superclass of the superclass of the current class.
The source code is available on Github, all the classes which raise the problem are available in the following package: https://github.com/netty/netty/tree/master/buffer/src/main/java/io/netty/buffer
The three sources are the following :
https://github.com/netty/netty/blob/master/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java
This last one, AbstractByteBuff, contains the leakDetector.
Please note I am not compiling the sources but just linking to Netty 4.0.7 final. Here the stackTrace:
o.netty.handler.codec.EncoderException: java.lang.NullPointerException
at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:131)
at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:643)
at io.netty.channel.DefaultChannelHandlerContext.write(DefaultChannelHandlerContext.java:633)
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:115)
at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:643)
at io.netty.channel.DefaultChannelHandlerContext.writeAndFlush(DefaultChannelHandlerContext.java:689)
at io.netty.channel.DefaultChannelHandlerContext.writeAndFlush(DefaultChannelHandlerContext.java:713)
at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:893)
at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:239)
at com.logentries.net.NettyBasedAsyncLogger.logLine(NettyBasedAsyncLogger.java:54)
at com.logentries.logback.LogentriesAppender.append(LogentriesAppender.java:105)
at com.logentries.logback.LogentriesAppender.append(LogentriesAppender.java:15)
at ch.qos.logback.core.AppenderBase.doAppend(AppenderBase.java:85)
at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:48)
at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:280)
at ch.qos.logback.classic.Logger.callAppenders(Logger.java:267)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:449)
at ch.qos.logback.classic.Logger.filterAndLog_1(Logger.java:421)
at ch.qos.logback.classic.Logger.debug(Logger.java:514)
at io.netty.util.internal.logging.Slf4JLogger.debug(Slf4JLogger.java:76)
at io.netty.util.ResourceLeakDetector.<clinit>(ResourceLeakDetector.java:37)
at io.netty.buffer.AbstractByteBuf.<clinit>(AbstractByteBuf.java:37)
at io.netty.buffer.UnpooledByteBufAllocator.newDirectBuffer(UnpooledByteBufAllocator.java:49)
at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:132)
at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:123)
at io.netty.buffer.AbstractByteBufAllocator.ioBuffer(AbstractByteBufAllocator.java:76)
at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:107)
at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:643)
at io.netty.channel.DefaultChannelHandlerContext.write(DefaultChannelHandlerContext.java:633)
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:115)
at io.netty.channel.DefaultChannelHandlerContext.invokeWrite(DefaultChannelHandlerContext.java:643)
at io.netty.channel.DefaultChannelHandlerContext.access$2000(DefaultChannelHandlerContext.java:29)
at io.netty.channel.DefaultChannelHandlerContext$WriteTask.run(DefaultChannelHandlerContext.java:887)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:354)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:366)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NullPointerException
at io.netty.buffer.UnpooledUnsafeDirectByteBuf.<init>(UnpooledUnsafeDirectByteBuf.java:72)
at io.netty.buffer.UnpooledByteBufAllocator.newDirectBuffer(UnpooledByteBufAllocator.java:49)
at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:132)
at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:123)
at io.netty.buffer.AbstractByteBufAllocator.ioBuffer(AbstractByteBufAllocator.java:76)
at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:107)
... 36 more