Analyzing programs with declarative field injection


Modern Java frameworks allow one to declare fields that are implicitly initialized with objects created on-the-fly, normally known as beans. The specification of these objects often comes from XML files. The specification of the affected (injected) fields is typically performed through field annotation. If a static analyzer does not understand this pattern and such annotations, it will issue spurious warnings, complaining about uninitialized fields.

Julia understands the most frequently used annotations for injected fields. Moreover, it allows the user to specify newer or proprietary annotations that are used to specify which fields are injected.

Currently, Julia natively understands the following annotations that specify injected fields:

  • @javax.inject.Inject
  • @javax.annotation.Resource
  • @javax.ejb.EJB
  • @org.springframework.beans.factory.annotation.Autowired
  • @com.juliasoft.julia.extraction.Injected

Moreover, Julia understands fields of POJOs injected through Spring declarative specification in XML context files (properties).

Specification of newer or proprietary injection annotations

If the program under analysis uses another annotation @I to specify injected fields, not yet considered by Julia or proprietary, then the analyzer will erroneously assume that the field is uninitialized, with consequent spurious warnings. In that case, the user of Julia can perform the following:

  • annotate those fields with @com.juliasoft.julia.extraction.Injected, in addition to the previous @I annotation. This might be a tedious and invasive process since each single field must be annotated;
  • annotate the @I annotation itself with @com.juliasoft.julia.extraction.Injected. This will automatically assume that all fields annotated with @I are also annotated with @com.juliasoft.julia.extraction.Injected. This choice is less invasive but less fine-grained than the previous one;
  • annotate the class defining those fields with @com.juliasoft.julia.extraction.Injected. However, all fields of that class will be considered injected then;
  • if the class defining those fields is annotated with @J, then annotate @J itself with @com.juliasoft.julia.extraction.Injected. Hence all fields of all classes annotated as @J will be considered injected.

Example

Consider the following two classes A and B, that initialize fields f, g and h through proprietary injection annotations for the fields and for the class, respectively:

public class A {
  private @I D f;
  public void process() {
    f.doSomething();
  }
}

@J
public class B {
  private E g;
  private F h;
  public void process() {
    g.doSomething();
    h.doSomethingElse();
  }
}

Since annotations @I and @J are not among those natively understood by Julia, then the analyzer will incorrectly assume that fields f, g and h are never written and that their use will definitely lead to a null pointer exception. A solution might be then to annotate single fields or entire classes with @com.juliasoft.julia.extraction.Injected:

public class A {
  private @I @com.juliasoft.julia.extraction.Injected D f;
  public void process() {
    f.doSomething();
  }
}

@J @com.juliasoft.julia.extraction.Injected
public class B {
  private E g;
  private F h;
  public void process() {
    g.doSomething();
    h.doSomethingElse();
  }
}

Another solution is to annotate the annotations themselves:

@com.juliasoft.julia.extraction.Injected
public @interface I { ... }

@com.juliasoft.julia.extraction.Injected
public @interface J { ... }

public class A {
  private @I D f;
  public void process() {
    f.doSomething();
  }
}

@J
public class C {
  private E g;
  private F h;
  public void process() {
    g.doSomething();
    h.doSomethingElse();
  }
}