byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

Annotation NPE

Open pmsgd opened this issue 2 years ago • 9 comments

Hello, I encountered NPE in byte buddy annotation parsing. We use kotlin 1.5.32, mockk library 1.12.3, byte buddy 1.10.22 and for simple mock:

val relNode = mockk<RelNode>()

I get this exception (root cause part only):

Caused by: java.lang.NullPointerException at net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation.(AnnotationDescription.java:511) at net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation.of(AnnotationDescription.java:534) at net.bytebuddy.description.annotation.AnnotationList$ForLoadedAnnotations.get(AnnotationList.java:235) at net.bytebuddy.description.annotation.AnnotationList$ForLoadedAnnotations.get(AnnotationList.java:192) at java.base/java.util.AbstractList$Itr.next(AbstractList.java:371) at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.ofTypeVariable(AnnotationAppender.java:629) at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.ofTypeVariable(AnnotationAppender.java:601) at net.bytebuddy.implementation.attribute.MethodAttributeAppender$ForInstrumentedMethod.apply(MethodAttributeAppender.java:198) at net.bytebuddy.implementation.attribute.MethodAttributeAppender$Compound.apply(MethodAttributeAppender.java:484) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyAttributes(TypeWriter.java:701) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:691) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:600) at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5751) at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:2166) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:232) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:204) at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3659) at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3897) at io.mockk.proxy.jvm.transformation.SubclassInstrumentation.doInterceptedSubclassing(SubclassInstrumentation.kt:83)

Debugged into code it crashes because typeVriable.getDeclaredAnnotations() returns array with single null element. This is caused by metadata method declaration in Apache Calcite library (version 1.30.0) in interface RelNode:

<@Nullable M extends @Nullable Metadata> M metadata(Class<M> metadataClass, RelMetadataQuery mq);

If I create extending interface with method (in Kotlin):

fun metadata(metadataClass: Class<Any?>?, mq: RelMetadataQuery?): Any?

and use it everywhere in unit tests then everything is ok.

pmsgd avatar Apr 19 '22 12:04 pmsgd

Is this also happening with a more recent version of Byte Buddy? If you only update Byte Buddy, its API should be compatible.

raphw avatar Apr 19 '22 20:04 raphw

Yes, byte buddy version 1.12.9 throws the same exception only with different line:

Caused by: java.lang.NullPointerException at net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation.(AnnotationDescription.java:657) at net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation.of(AnnotationDescription.java:692) at net.bytebuddy.description.annotation.AnnotationList$ForLoadedAnnotations.get(AnnotationList.java:240) at net.bytebuddy.description.annotation.AnnotationList$ForLoadedAnnotations.get(AnnotationList.java:197) at java.base/java.util.AbstractList$Itr.next(AbstractList.java:371) at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.ofTypeVariable(AnnotationAppender.java:645) at net.bytebuddy.implementation.attribute.AnnotationAppender$ForTypeAnnotations.ofTypeVariable(AnnotationAppender.java:617) at net.bytebuddy.implementation.attribute.MethodAttributeAppender$ForInstrumentedMethod.apply(MethodAttributeAppender.java:198) at net.bytebuddy.implementation.attribute.MethodAttributeAppender$Compound.apply(MethodAttributeAppender.java:484) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyAttributes(TypeWriter.java:712) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:702) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:611) at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5959) at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:2213) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:232) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:204) at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3668) at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3906) at io.mockk.proxy.jvm.transformation.SubclassInstrumentation.doInterceptedSubclassing(SubclassInstrumentation.kt:83)

pmsgd avatar Apr 20 '22 07:04 pmsgd

That's strange. What JVM version are you running? This is not supposed to happen.

raphw avatar Apr 20 '22 10:04 raphw

openjdk version "11.0.14" 2022-01-18 OpenJDK Runtime Environment (build 11.0.14+9-post-Debian-1deb11u1) OpenJDK 64-Bit Server VM (build 11.0.14+9-post-Debian-1deb11u1, mixed mode, sharing)

and

openjdk version "11.0.14.1" 2022-02-08 LTS OpenJDK Runtime Environment Zulu11.54+25-CA (build 11.0.14.1+1-LTS) OpenJDK 64-Bit Server VM Zulu11.54+25-CA (build 11.0.14.1+1-LTS, mixed mode)

I have NPE in both of them.

pmsgd avatar Apr 20 '22 10:04 pmsgd

Do you have a reproducer?

raphw avatar Apr 20 '22 11:04 raphw

I tried extract important part but it worked - it must be influenced by something else in our project. I can't publish it but I'll investigate it further.

pmsgd avatar Apr 20 '22 13:04 pmsgd

Finally found it. grpc libraries have checkerframework (checkerframework.org) as their dependency. After exclusion (i.e. exclude group: 'org.checkerframework') everything works without NPE again. You may want investigate it deeper but for my case the problem is solved and you can close this ticket.

pmsgd avatar May 04 '22 09:05 pmsgd

Alright, does it work with a recent version of the dependency? This error should really not happen.

raphw avatar May 04 '22 13:05 raphw

I can't replicate it with recent versions of bytebuddy and checkerframework, i.e. mocking works as it should.

pmsgd avatar May 04 '22 13:05 pmsgd