External Annotations not working for Dagger?

I told IntillJ to auto-generate an external annotation for Dagger's ObjectGraph.get.  However, I am still getting possible NPE warnings when I try to access the return value of the method.

final ServiceManager serviceManager = objectGraph.get(ServiceManager.class);
serviceManager.startAsync().awaitHealthy(2, TimeUnit.MINUTES); // possible NPE on serviceManager.startAsync()

If I put an assert serviceManager != null inbetween the two lines the warning goes away, validating that the problem is with IntelliJ thinking that get can return null.

My annotation file lives in <source root>/Dagger/annotation.xml (auto-generated) and looks like this:

 
<root>
  <item name='dagger.ObjectGraph.DaggerObjectGraph T get(java.lang.Class&lt;T&gt;)'>
    <annotation name='javax.annotation.Nonnull'/>
  </item>
</root>


My other external annotations (e.g., for logback and guava) are working correctly, all were auto-generated by IntelliJ in similar locations (<source root>/package/name/annotation.xml)

Here are the docs for the method I am trying to annotate: https://square.github.io/dagger/javadoc/dagger/ObjectGraph.html#get(java.lang.Class)

8 comments
Comment actions Permalink

If you navigate to this "get" method, is there an @ icon on the left gutter next to it? Does its tooltip specify it's @Nonnull? Are other annotations you mention (Guava, Logback) also @javax.annotation.Nonnull?
If you add such annotation to "inject" or "create" methods of the same class, will it be honored by the static analysis?

0
Comment actions Permalink

I fixed the issue by using the quick-fix from my code rather than navigating to get and then clicking the @ icon on the left.  Originally, I would navigate to the get method (which would take me to the third party library code) and then click the @ on the left of the message to add the annotation.  This didn't work.  However, I learned that you can do the quick fix without navigating to the method first so I did that and this time it worked.

The annotation generated when I did it from my source code looked like:

 
<item name='dagger.ObjectGraph T get(java.lang.Class&lt;T&gt;)'>
    <annotation name='javax.annotation.Nonnull'/>
</item>
0
Comment actions Permalink

Hmm... trying to reproduce the issue I can't seem to make it happen again.  I'm going to assume that I did something wrong the first time.

0
Comment actions Permalink

Is the method actually invoked in your code defined in ObjectGraph or DaggerObjectGraph? Is there any documentation available about DaggerObjectGraph?

0
Comment actions Permalink

Ah, I think I see the problem.  ObjectGraph is an abstract class. DaggerObjectGraph extends ObjectGraph.  My code calls ObjectGraph.create(...) which actually creates a DaggerObjectGraph.  IntelliJ seems to have figured that out and when I navigated to my objectGraph.get call it took me to DaggerObjectGraph.  However, in my code I am calling the abstract ObjectGraph.get, not the implementation of that method.

The takeaway here is that the annotation needs to be on the compile time type not the runtime type, even if IntelliJ is smart enough to take you to the runtime type when navigating.  For safety, it is probably best to just do the annotation from your code rather than navigating first.

0
Comment actions Permalink

How did you navigate, via Navigate | Declaration action (shortcut) or Navigate | Implementation(s)?

0
Comment actions Permalink

Hmm... I use whatever my hotkey does... which appears to be functionally the same as `Go To > Implementations`

0
Comment actions Permalink

That explains the behavior. Goto Declaration would bring you to the abstract method (which is where IDEA takes the annotations from) and the intention action would work correctly.

0

Please sign in to leave a comment.