Annotations the SpotBugs tool supports for static analysis control and null safety
—
Apply annotations by default to all members of a class or package, reducing annotation verbosity while maintaining safety. These annotations are particularly useful for establishing consistent nullability policies or other behavioral constraints across entire codebases.
Apply specified annotations to all members of a class or package by default.
/**
* Indicates that all members of the class or package should be annotated with
* the default value of the supplied annotation class.
*
* This would be used for behavior annotations such as @NonNull, @CheckForNull,
* or @CheckReturnValue.
*
* In particular, you can use @DefaultAnnotation(NonNull.class) on a class or
* package, and then use @Nullable only on those parameters, methods or fields
* that you want to allow to be null.
*/
@Documented
@Target({ ElementType.TYPE, ElementType.PACKAGE })
@Retention(RetentionPolicy.CLASS)
@interface DefaultAnnotation {
Class<? extends Annotation>[] value();
@Deprecated
Priority priority() default Priority.MEDIUM;
Confidence confidence() default Confidence.MEDIUM;
}Usage Examples:
// Apply @NonNull by default to all class members
@DefaultAnnotation(NonNull.class)
public class UserService {
// Implicitly @NonNull - no annotation needed
private UserRepository repository;
// Implicitly @NonNull parameters and return value
public String getUserName(String userId) {
return repository.findNameById(userId);
}
// Explicit @Nullable overrides the default
@Nullable
public User findUser(String userId) {
return repository.findById(userId); // May return null
}
// Implicitly @NonNull parameter
public void updateUser(User user) {
repository.save(user);
}
}
// Multiple default annotations
@DefaultAnnotation({NonNull.class, CheckReturnValue.class})
public class SecurityService {
// Both @NonNull and @CheckReturnValue applied by default
public boolean authenticate(String username, String password) {
return authProvider.validate(username, password);
}
// Override with @Nullable, but @CheckReturnValue still applies
@Nullable
public User getCurrentUser() {
return session.getUser(); // Return value should still be checked
}
}
// Package-level default annotation in package-info.java
@DefaultAnnotation(NonNull.class)
package com.example.service;
import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
import edu.umd.cs.findbugs.annotations.NonNull;Apply specified annotations to all fields in a class or package by default.
/**
* Indicates that all fields of the class or package should be annotated with
* the default value of the supplied annotation class.
*/
@Documented
@Target({ ElementType.TYPE, ElementType.PACKAGE })
@Retention(RetentionPolicy.CLASS)
@interface DefaultAnnotationForFields {
Class<? extends Annotation>[] value();
@Deprecated
Priority priority() default Priority.MEDIUM;
Confidence confidence() default Confidence.MEDIUM;
}Usage Examples:
// All fields are @NonNull by default
@DefaultAnnotationForFields(NonNull.class)
public class UserData {
// Implicitly @NonNull
private String username;
private String email;
private Date createdAt;
// Explicit @Nullable overrides default
@Nullable
private String displayName;
// Constructor can assume non-null fields
public UserData(String username, String email) {
this.username = username; // Safe - implicitly @NonNull
this.email = email; // Safe - implicitly @NonNull
this.createdAt = new Date();
}
}Apply specified annotations to all methods in a class or package by default.
/**
* Indicates that all methods of the class or package should be annotated with
* the default value of the supplied annotation class.
*/
@Documented
@Target({ ElementType.TYPE, ElementType.PACKAGE })
@Retention(RetentionPolicy.CLASS)
@interface DefaultAnnotationForMethods {
Class<? extends Annotation>[] value();
@Deprecated
Priority priority() default Priority.MEDIUM;
Confidence confidence() default Confidence.MEDIUM;
}Usage Examples:
// All methods should have their return values checked
@DefaultAnnotationForMethods(CheckReturnValue.class)
public class FileOperations {
// Return value should be checked (implicit @CheckReturnValue)
public boolean createFile(String filename) {
try {
return new File(filename).createNewFile();
} catch (IOException e) {
return false;
}
}
// Return value should be checked (implicit @CheckReturnValue)
public boolean deleteFile(String filename) {
return new File(filename).delete();
}
// Void methods not affected by @CheckReturnValue
public void logOperation(String operation) {
logger.info("File operation: " + operation);
}
}
// Multiple annotations for methods
@DefaultAnnotationForMethods({CheckReturnValue.class, NonNull.class})
public class ValidationService {
// Both @CheckReturnValue and @NonNull (for return value) applied
public ValidationResult validate(String input) {
return validator.validate(input);
}
// Override with @Nullable return value
@Nullable
public String normalize(String input) {
return input != null ? input.trim() : null;
}
}Apply specified annotations to all parameters in a class or package by default.
/**
* Indicates that all parameters of methods in the class or package should be annotated with
* the default value of the supplied annotation class.
*/
@Documented
@Target({ ElementType.TYPE, ElementType.PACKAGE })
@Retention(RetentionPolicy.CLASS)
@interface DefaultAnnotationForParameters {
Class<? extends Annotation>[] value();
@Deprecated
Priority priority() default Priority.MEDIUM;
Confidence confidence() default Confidence.MEDIUM;
}Usage Examples:
// All parameters are @NonNull by default
@DefaultAnnotationForParameters(NonNull.class)
public class StringUtils {
// Both parameters are implicitly @NonNull
public String concatenate(String first, String second) {
return first + second; // Safe - no null checks needed
}
// All parameters implicitly @NonNull
public String format(String template, Object... args) {
return MessageFormat.format(template, args);
}
// Explicit @Nullable overrides default
public String withDefault(@Nullable String input, String defaultValue) {
return input != null ? input : defaultValue;
}
}Specialized default annotation indicating that method return values are non-null by default.
/**
* This annotation can be applied to a package, class or method to indicate that
* the methods in that element have nonnull return values by default unless
* there is:
* - An explicit nullness annotation
* - The method overrides a method in a superclass (in which case the
* annotation of the corresponding parameter in the superclass applies)
* - there is a default annotation applied to a more tightly nested element.
*/
@Documented
@Nonnull
@TypeQualifierDefault(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ReturnValuesAreNonnullByDefault {
}Usage Examples:
// All method return values are non-null by default
@ReturnValuesAreNonnullByDefault
public class DataService {
// Returns non-null value (implicit @NonNull)
public List<User> getAllUsers() {
List<User> users = repository.findAll();
return users != null ? users : Collections.emptyList();
}
// Returns non-null value (implicit @NonNull)
public String getUserName(String userId) {
String name = repository.findNameById(userId);
return name != null ? name : "Unknown";
}
// Explicit @Nullable overrides the default
@Nullable
public User findUser(String userId) {
return repository.findById(userId); // May return null
}
}
// Package-level application in package-info.java
@ReturnValuesAreNonnullByDefault
package com.example.data;
import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault;Default annotations can be combined for comprehensive coverage:
// Comprehensive default annotations
@DefaultAnnotationForParameters(NonNull.class) // All parameters non-null
@DefaultAnnotationForMethods(CheckReturnValue.class) // All returns should be checked
@ReturnValuesAreNonnullByDefault // All returns are non-null
public class RobustService {
// Parameters implicitly @NonNull, return implicitly @NonNull and @CheckReturnValue
public boolean processData(String input, ProcessOptions options) {
try {
processor.process(input, options);
return true;
} catch (ProcessException e) {
logger.error("Processing failed", e);
return false;
}
}
// Override defaults as needed
public void logMessage(@Nullable String message) { // Override parameter default
if (message != null) {
logger.info(message);
}
}
}Apply default annotations to entire packages using package-info.java:
/**
* Package with comprehensive null safety defaults.
*
* All parameters and return values are non-null by default unless explicitly
* annotated otherwise. All method return values should be checked.
*/
@DefaultAnnotation({NonNull.class, CheckReturnValue.class})
@ReturnValuesAreNonnullByDefault
package com.example.secure;
import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.CheckReturnValue;
import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault;Install with Tessl CLI
npx tessl i tessl/maven-com-github-spotbugs--spotbugs-annotations