-
Notifications
You must be signed in to change notification settings - Fork 1
Java and Spring Null Safety
Somkiat Puisungnoen edited this page Aug 25, 2026
·
2 revisions
@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
}
}
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;
}
}
File package-info.java
@NullMarked
package com.example.demonull;
import org.jspecify.annotations.NullMarked;