Skip to content

Java and Spring Null Safety

Somkiat Puisungnoen edited this page Aug 25, 2026 · 2 revisions

Java and Spring Null Safety

1. Old version

@Service
public class UserService {
    
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // Danger: Input can be null. Output can be null. Compiler is silent.
    public User updateUserStatus(Long id, String status) {
        if (id == null) {
            throw new IllegalArgumentException("Id must not be null");
        }
        
        User user = userRepository.findById(id);
        
        // Defensive check required because repository might return null
        if (user != null) {
            // Danger: status could be null, causing NPE inside setStatus
            user.setStatus(status.toUpperCase()); 
            return userRepository.save(user);
        }
        
        return null; // Returning null forces the caller to also write if-statements
    }
}

2. Modern Spring Service (Compile-Time Null Safety)

import org.jspecify.annotations.NullMarked;

@NullMarked
@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // Compiler Guarantee: 'id' and 'status' cannot be null. 
    // If a caller passes null, the build fails.
    public Optional<User> updateUserStatus(Long id, String status) {
        
        // Cleaner flow: Repository returns an Optional, eliminating null checks
        return userRepository.findById(id)
            .map(user -> {
                user.setStatus(status.toUpperCase()); // Guaranteed safe
                return userRepository.save(user);
            });
    }

    // Explicit Exception: This method is allowed to return null safely
    public @Nullable User findGuestUser() {
        // ... implementation that might return null
        return null; 
    }
}

Config package-level

File package-info.java

@NullMarked
package com.example.demonull;

import org.jspecify.annotations.NullMarked;

Clone this wiki locally