Skills for creating, testing, reviewing, migrating and guarding Spring Boot 4 projects with Java 25: project scaffolding with architecture patterns, Boot 4 test templates, code review, Boot 3 to 4 migration, and a team harness of build gates and agent hooks.
93%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Use JSpecify annotations to make nullability explicit in Spring applications and libraries. Spring Framework 7 and the Spring Boot 4 portfolio expose null-safe APIs with JSpecify; application code should align with those contracts and avoid deprecated Spring null-safety annotations.
JSpecify is OPTIONAL for application code. While Spring Boot 4 and Spring Framework 7 internally use JSpecify annotations, applications can:
org.springframework.lang annotations (acceptable during transition) - Will work but are deprecatedWhen to use JSpecify:
When Spring's annotations are acceptable:
@NullMarked in package-info.java.@Nullable at the type-use site.org.springframework.lang (@Nullable, @NonNull, @NonNullApi, @NonNullFields).JSpecify annotations are TYPE_USE, so place them directly before the type.
// field
private @Nullable String fileEncoding;
// parameter + return type
public @Nullable String buildMessage(@Nullable String message) { ... }Type-use syntax matters:
@Nullable Object[] array; // elements nullable, array non-null
Object @Nullable [] array; // elements non-null, array nullable
@Nullable Object @Nullable [] arr; // both nullableList<String> // non-null elements
List<@Nullable String> // nullable elementsType-use annotations appear after the last dot:
Cache.@Nullable ValueWrapper
jakarta.validation.@Nullable ValidatorSpring’s legacy null-safety annotations are deprecated in Spring Framework 7 in favor of JSpecify. JSpecify is type-use only, so array/varargs declarations must be updated to preserve semantics (for example, @Nullable Object[] becomes Object @Nullable []).
Place annotations next to the type instead of at the far left:
// before (legacy style)
@Nullable private String field;
@Nullable public String method();
// after (JSpecify style)
private @Nullable String field;
public @Nullable String method();If the goal is application-wide null-safety, use NullAway:
NullAway:OnlyNullMarked=true (checks only @NullMarked packages)NullAway:CustomContractAnnotations=org.springframework.lang.ContractNullAway:JSpecifyMode=true for full JSpecify semantics-XDaddTypeAnnotationsToSymbol=true if Java 25 is not possible.--release 17.