Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set findbugs NotNull as default for all classes under a package

Tags:

java

findbugs

I have the simple code below for testing the FindBugs @NonNull annotation with Maven. I execute

mvn clean install

And it correctly fails to build because print(null) violates the non-null condition.

You can set NonNull as default for all method parameters inside a class using the class annotation

@DefaultAnnotation(NonNull.class)

How can I set NonNull as default for all method parameters inside all classes under a given package (and sub-packages)?

src/main/java/test/Hello.java

package test;
import edu.umd.cs.findbugs.annotations.NonNull;
public class Hello {
    static public void print(@NonNull Object value) {
        System.out.println("value: " + value.toString());
    }

    static public void main(String[] args) {
        if (args.length > 0) {
            print(args[0]);
        } else {
            print(null);
        }
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>hello</groupId>
  <artifactId>hello</artifactId>
  <version>1.0</version>

  <dependencies>
    <dependency>
      <groupId>net.sourceforge.findbugs</groupId>
      <artifactId>annotations</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>net.sourceforge.findbugs</groupId>
      <artifactId>jsr305</artifactId>
      <version>1.3.7</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>findbugs-maven-plugin</artifactId>
        <version>2.5.2</version>
        <configuration>
          <includeTests>true</includeTests>
        </configuration>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>check</goal>
            </goals>
          </execution>
          <execution>
            <id>findbugs-test-compile</id>
            <phase>test-compile</phase>
            <goals>
              <goal>check</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>
like image 424
David Portabella Avatar asked Nov 09 '12 15:11

David Portabella


2 Answers

You can do this to parameters, fileds and method return value simultaneously by putting these lines in your package-info.java:

@DefaultAnnotation(NonNull.class)
package com.my.package;

When findbugs runs on the code in that package, all methods and fields are assumed to be non-null unless you annotate them with @CheckForNull.

I also do not know of a way to make this apply to sub-packages. I do this for each package.

like image 131
mdhirsch Avatar answered Oct 24 '22 21:10

mdhirsch


You can do this for individual packages, but I haven't found a way to have it propagate to subpackages. For method parameters use the built-in package annotation @ParametersAreNonnullByDefault. Apply the annotation to the package in its package-info.java file inside the package's directory.

Note that I'm using the javax.annotation annotations from JSR-305 which FindBugs honors.

com/example/foo/package-info.java

/**
 * Package that doesn't allow null values as method parameters.
 */
@ParametersAreNonnullByDefault
package com.example.foo;

import javax.annotation.ParametersAreNonnullByDefault;

For fields and method return values you'll need to create your own annotations. I did this by copying the source for ParametersAreNonnullByDefault and changing the ElementType enum.

com/example/util/FieldsAreNonnullByDefault.java

package com.example.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;

/**
 * Applies the {@link Nonnull} annotation to every class field unless overridden.
 */
@Documented
@Nonnull
@TypeQualifierDefault(ElementType.FIELD)  // <-- use METHOD for return values
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldsAreNonnullByDefault
{
    // nothing to add
}

I began rewriting a fairly complex system from scratch a couple months ago, and every package has these three annotations applied (fields, parameters, and return values). One benefit that's come out of the incentive to avoid null values is using the Null Object pattern where appropriate. That combined with favoring final fields as much as possible and small classes that do one thing only has really kept the code clean.

like image 26
David Harkness Avatar answered Oct 24 '22 20:10

David Harkness