CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-github-spotbugs--spotbugs-annotations

Annotations the SpotBugs tool supports for static analysis control and null safety

Pending
Overview
Eval results
Files

null-safety.mddocs/

Null Safety

Comprehensive null safety annotation system for expressing nullability constraints and enabling safer code through static analysis. These annotations integrate with SpotBugs and other tools to detect null pointer exceptions at compile time.

Capabilities

NonNull Annotation

Indicates that the annotated element must not be null.

/**
 * The annotated element must not be null.
 * 
 * Annotated Fields must only not be null after construction has completed.
 * Annotated methods must have non-null return values.
 */
@Documented
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })
@Retention(RetentionPolicy.CLASS)
@javax.annotation.Nonnull(when = When.ALWAYS)
@TypeQualifierNickname
@interface NonNull {
}

Usage Examples:

public class UserService {
    // Non-null field - must be initialized
    @NonNull
    private final UserRepository repository;
    
    public UserService(@NonNull UserRepository repository) {
        this.repository = repository; // Required - cannot be null
    }
    
    // Non-null return value
    @NonNull
    public String getUserName(@NonNull String userId) {
        // Must return non-null value
        String name = repository.findNameById(userId);
        return name != null ? name : "Unknown";
    }
    
    // Non-null parameter
    public void updateUser(@NonNull User user) {
        // Can safely use user without null check
        repository.save(user);
    }
}

Nullable Annotation

Indicates that the annotated element could be null under some circumstances.

/**
 * The annotated element could be null under some circumstances.
 *
 * In general, this means developers will have to read the documentation to
 * determine when a null value is acceptable and whether it is necessary to
 * check for a null value.
 *
 * When this annotation is applied to a method it applies to the method return value.
 */
@Documented
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })
@Retention(RetentionPolicy.CLASS)
@javax.annotation.Nonnull(when = When.UNKNOWN)
@TypeQualifierNickname
@interface Nullable {
}

Usage Examples:

public class UserService {
    // Nullable field - may be null
    @Nullable
    private String cachedData;
    
    // Nullable return value - may return null
    @Nullable
    public User findUser(@NonNull String userId) {
        return repository.findById(userId); // May return null if not found
    }
    
    // Nullable parameter - null is acceptable
    public void setDisplayName(@Nullable String displayName) {
        // Must check for null before use
        this.displayName = displayName != null ? displayName : "Anonymous";
    }
    
    // Handle nullable values safely
    public void processUser(@NonNull String userId) {
        @Nullable User user = findUser(userId);
        if (user != null) {
            // Safe to use user here
            user.updateLastAccess();
        }
    }
}

CheckForNull Annotation

Indicates that the annotated element might be null and uses of the element should check for null.

/**
 * The annotated element might be null, and uses of the element should check for
 * null.
 *
 * When this annotation is applied to a method it applies to the method return value.
 */
@Documented
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })
@Retention(RetentionPolicy.CLASS)
@javax.annotation.Nonnull(when = When.MAYBE)
@TypeQualifierNickname
@interface CheckForNull {
}

Usage Examples:

public class CacheService {
    // Check for null before using
    @CheckForNull
    public String getCachedValue(@NonNull String key) {
        String value = cache.get(key);
        return value; // Explicitly check for null before using result
    }
    
    public void processData(@NonNull String key) {
        @CheckForNull String data = getCachedValue(key);
        
        // Must check for null - static analysis will warn if you don't
        if (data != null) {
            System.out.println(data.length());
        } else {
            System.out.println("No cached data found");
        }
    }
}

UnknownNullness Annotation

Indicates that the nullness of the annotated element is unknown, or may vary in unknown ways in subclasses.

/**
 * Used to indicate that the nullness of element is unknown, or may vary in
 * unknown ways in subclasses.
 */
@Documented
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })
@Retention(RetentionPolicy.CLASS)
@javax.annotation.Nonnull(when = When.UNKNOWN)
@TypeQualifierNickname
@interface UnknownNullness {
}

Usage Examples:

public class LegacyIntegration {
    // Nullness unknown - treat with caution
    @UnknownNullness
    public Object callLegacyApi(@NonNull String request) {
        // Legacy API with unclear null handling
        return legacySystem.process(request);
    }
    
    public void handleLegacyResult(@NonNull String request) {
        @UnknownNullness Object result = callLegacyApi(request);
        
        // Defensive programming - assume it might be null
        if (result != null) {
            processResult(result);
        }
    }
}

PossiblyNull Annotation (Deprecated)

Indicates that the annotated element might be null, and uses of the element should check for null.

/**
 * The annotated element should might be null, and uses of the element should
 * check for null.
 *
 * When this annotation is applied to a method it applies to the method return
 * value.
 *
 * @deprecated - use CheckForNull instead; the name of which more clearly
 *             indicates that not only could the value be null, but that good
 *             coding practice requires that the value be checked for null.
 */
@Documented
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })
@Retention(RetentionPolicy.CLASS)
@javax.annotation.Nonnull(when = When.MAYBE)
@TypeQualifierNickname
@Deprecated
@interface PossiblyNull {
}

Usage Examples (Deprecated - Use @CheckForNull instead):

public class LegacyService {
    // Legacy usage - prefer @CheckForNull
    @PossiblyNull
    @Deprecated
    private final Logger logger;
    
    public LegacyService(boolean enableLogging) {
        this.logger = enableLogging ? LoggerFactory.getLogger(getClass()) : null;
    }
    
    // Better approach using @CheckForNull:
    @CheckForNull
    public String getDebugInfo() {
        return logger != null ? logger.getName() : null;
    }
    
    public void logMessage(@NonNull String message) {
        // Handle possibly null logger
        if (logger != null) {
            logger.info(message);
        }
    }
}

ReturnValuesAreNonnullByDefault Annotation

Indicates that methods in the annotated scope have nonnull return values 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:
 * <ul>
 * <li>An explicit nullness annotation
 * <li>The method overrides a method in a superclass (in which case the
 * annotation of the corresponding parameter in the superclass applies)
 * <li>there is a default annotation applied to a more tightly nested element.
 * </ul>
 */
@Documented
@Nonnull
@TypeQualifierDefault(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ReturnValuesAreNonnullByDefault {
}

Usage Examples:

// Applied to class - all methods return non-null by default
@ReturnValuesAreNonnullByDefault
public class UserService {
    
    // Returns non-null by default
    public String getUserName(String userId) {
        String name = repository.findNameById(userId);
        return name != null ? name : "Unknown"; // Must ensure non-null return
    }
    
    // Explicit annotation overrides default
    @Nullable
    public User findUser(String userId) {
        return repository.findById(userId); // May return null
    }
    
    // Still non-null by default
    public List<User> getAllUsers() {
        List<User> users = repository.findAll();
        return users != null ? users : Collections.emptyList();
    }
}

// Can also be applied to packages in package-info.java:
@ReturnValuesAreNonnullByDefault
package com.example.service;

Null Safety Best Practices

  1. Use @NonNull by default: Start with the assumption that references should not be null
  2. Explicit @Nullable: Only use @Nullable when null is a valid, expected value
  3. Check before use: Always check @Nullable and @CheckForNull values before dereferencing
  4. Document null handling: Use clear parameter and return value documentation
  5. Consistent application: Apply annotations consistently across your codebase
  6. Default annotations: Use @ReturnValuesAreNonnullByDefault to reduce annotation overhead

Integration with Other Tools

These annotations work with:

  • SpotBugs: Primary static analysis integration
  • NullAway: Uber's null safety checker
  • Checker Framework: Advanced static analysis
  • IDEs: IntelliJ IDEA, Eclipse null analysis
  • Error Prone: Google's static analysis tool

Install with Tessl CLI

npx tessl i tessl/maven-com-github-spotbugs--spotbugs-annotations

docs

default-annotations.md

index.md

null-safety.md

resource-management.md

return-value-checking.md

testing-annotations.md

warning-suppression.md

tile.json