Fix Checkstyle configuration for nullability annotations
While assessing #35195, I noticed the following issues with our Checkstyle configuration regarding nullability annotations. - "^(?!org\.jspecify|\.annotations).*(NonNull|Nullable)$" contains a "|". - "^(?!org\.jspecify|\.annotations).*(NonNull|Nullable)$" matches against NonNull but not against Nonnull, and therefore incorrectly permits usage of javax.annotation.Nonnull. - Some of the Checkstyle suppressions no longer apply. This commit addresses all of the above issues and updates several tests to use example annotations other than javax.annotation.Nonnull where feasible. See gh-35195 Closes gh-35205
This commit is contained in:
parent
aac61b86c8
commit
4fdf40e39e
|
@ -31,8 +31,10 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.RegEx;
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.Syntax;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
import javax.annotation.meta.TypeQualifierNickname;
|
||||||
import javax.annotation.meta.When;
|
import javax.annotation.meta.When;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -46,6 +48,7 @@ import org.springframework.core.annotation.AnnotationUtilsTests.WebController;
|
||||||
import org.springframework.core.annotation.AnnotationUtilsTests.WebMapping;
|
import org.springframework.core.annotation.AnnotationUtilsTests.WebMapping;
|
||||||
import org.springframework.core.testfixture.stereotype.Component;
|
import org.springframework.core.testfixture.stereotype.Component;
|
||||||
import org.springframework.core.testfixture.stereotype.Indexed;
|
import org.springframework.core.testfixture.stereotype.Indexed;
|
||||||
|
import org.springframework.lang.Contract;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
@ -237,9 +240,8 @@ class AnnotatedElementUtilsTests {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
void isAnnotatedForPlainTypes() {
|
void isAnnotatedForPlainTypes() {
|
||||||
assertThat(isAnnotated(Order.class, Documented.class)).isTrue();
|
assertThat(isAnnotated(Order.class, Documented.class)).isTrue();
|
||||||
assertThat(isAnnotated(org.springframework.lang.NonNullApi.class, Documented.class)).isTrue();
|
assertThat(isAnnotated(Inherited.class, Documented.class)).isTrue();
|
||||||
assertThat(isAnnotated(org.springframework.lang.NonNullApi.class, Nonnull.class)).isTrue();
|
assertThat(isAnnotated(Contract.class, Documented.class)).isTrue();
|
||||||
assertThat(isAnnotated(ParametersAreNonnullByDefault.class, Nonnull.class)).isTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -278,9 +280,8 @@ class AnnotatedElementUtilsTests {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
void hasAnnotationForPlainTypes() {
|
void hasAnnotationForPlainTypes() {
|
||||||
assertThat(hasAnnotation(Order.class, Documented.class)).isTrue();
|
assertThat(hasAnnotation(Order.class, Documented.class)).isTrue();
|
||||||
assertThat(hasAnnotation(org.springframework.lang.NonNullApi.class, Documented.class)).isTrue();
|
assertThat(hasAnnotation(Inherited.class, Documented.class)).isTrue();
|
||||||
assertThat(hasAnnotation(org.springframework.lang.NonNullApi.class, Nonnull.class)).isTrue();
|
assertThat(hasAnnotation(Contract.class, Documented.class)).isTrue();
|
||||||
assertThat(hasAnnotation(ParametersAreNonnullByDefault.class, Nonnull.class)).isTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -346,17 +347,16 @@ class AnnotatedElementUtilsTests {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
void getAllAnnotationAttributesOnLangType() {
|
void getAllAnnotationAttributesOnLangType() {
|
||||||
MultiValueMap<String, Object> attributes = getAllAnnotationAttributes(
|
MultiValueMap<String, Object> attributes = getAllAnnotationAttributes(
|
||||||
org.springframework.lang.NonNullApi.class, Nonnull.class.getName());
|
org.springframework.lang.NonNullApi.class, javax.annotation.Nonnull.class.getName());
|
||||||
assertThat(attributes).as("Annotation attributes map for @Nonnull on NonNullApi").isNotNull();
|
assertThat(attributes).as("Annotation attributes map for @Nonnull on @NonNullApi").isNotNull();
|
||||||
assertThat(attributes.get("when")).as("value for NonNullApi").isEqualTo(List.of(When.ALWAYS));
|
assertThat(attributes.get("when")).as("value for @NonNullApi").isEqualTo(List.of(When.ALWAYS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getAllAnnotationAttributesOnJavaxType() {
|
void getAllAnnotationAttributesOnJavaxType() {
|
||||||
MultiValueMap<String, Object> attributes = getAllAnnotationAttributes(
|
MultiValueMap<String, Object> attributes = getAllAnnotationAttributes(RegEx.class, Syntax.class.getName());
|
||||||
ParametersAreNonnullByDefault.class, Nonnull.class.getName());
|
assertThat(attributes).as("Annotation attributes map for @Syntax on @RegEx").isNotNull();
|
||||||
assertThat(attributes).as("Annotation attributes map for @Nonnull on NonNullApi").isNotNull();
|
assertThat(attributes.get("when")).as("value for @RegEx").isEqualTo(List.of(When.ALWAYS));
|
||||||
assertThat(attributes.get("when")).as("value for NonNullApi").isEqualTo(List.of(When.ALWAYS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -855,8 +855,10 @@ class AnnotatedElementUtilsTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void javaxMetaAnnotationTypeViaFindMergedAnnotation() {
|
void javaxMetaAnnotationTypeViaFindMergedAnnotation() {
|
||||||
assertThat(findMergedAnnotation(ParametersAreNonnullByDefault.class, Nonnull.class)).isEqualTo(ParametersAreNonnullByDefault.class.getAnnotation(Nonnull.class));
|
assertThat(findMergedAnnotation(ThreadSafe.class, Documented.class))
|
||||||
assertThat(findMergedAnnotation(ResourceHolder.class, Nonnull.class)).isEqualTo(ParametersAreNonnullByDefault.class.getAnnotation(Nonnull.class));
|
.isEqualTo(ThreadSafe.class.getAnnotation(Documented.class));
|
||||||
|
assertThat(findMergedAnnotation(ResourceHolder.class, TypeQualifierNickname.class))
|
||||||
|
.isEqualTo(RegEx.class.getAnnotation(TypeQualifierNickname.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1536,7 +1538,7 @@ class AnnotatedElementUtilsTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Resource(name = "x")
|
@Resource(name = "x")
|
||||||
@ParametersAreNonnullByDefault
|
@RegEx
|
||||||
static class ResourceHolder {
|
static class ResourceHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,8 @@ package org.springframework.core.annotation;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.lang.Contract;
|
import org.springframework.lang.Contract;
|
||||||
|
@ -86,12 +85,13 @@ class AnnotationFilterTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void javaWhenJavaxAnnotationReturnsTrue() {
|
void javaWhenJavaxAnnotationReturnsTrue() {
|
||||||
assertThat(AnnotationFilter.JAVA.matches(Nonnull.class)).isTrue();
|
assertThat(AnnotationFilter.JAVA.matches(ThreadSafe.class)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
void javaWhenSpringLangAnnotationReturnsFalse() {
|
void javaWhenSpringLangAnnotationReturnsFalse() {
|
||||||
assertThat(AnnotationFilter.JAVA.matches(Nullable.class)).isFalse();
|
assertThat(AnnotationFilter.JAVA.matches(org.springframework.lang.Nullable.class)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -103,7 +103,7 @@ class AnnotationFilterTests {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
void noneReturnsFalse() {
|
void noneReturnsFalse() {
|
||||||
assertThat(AnnotationFilter.NONE.matches(Retention.class)).isFalse();
|
assertThat(AnnotationFilter.NONE.matches(Retention.class)).isFalse();
|
||||||
assertThat(AnnotationFilter.NONE.matches(Nullable.class)).isFalse();
|
assertThat(AnnotationFilter.NONE.matches(org.springframework.lang.Nullable.class)).isFalse();
|
||||||
assertThat(AnnotationFilter.NONE.matches(TestAnnotation.class)).isFalse();
|
assertThat(AnnotationFilter.NONE.matches(TestAnnotation.class)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.core.annotation.AnnotationTypeMapping.MirrorSets;
|
import org.springframework.core.annotation.AnnotationTypeMapping.MirrorSets;
|
||||||
|
@ -442,7 +440,7 @@ class AnnotationTypeMappingsTests {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Method getAliasMapping(AnnotationTypeMapping mapping, int attributeIndex) {
|
private Method getAliasMapping(AnnotationTypeMapping mapping, int attributeIndex) {
|
||||||
int mapped = mapping.getAliasMapping(attributeIndex);
|
int mapped = mapping.getAliasMapping(attributeIndex);
|
||||||
return mapped != -1 ? mapping.getRoot().getAttributes().get(mapped) : null;
|
return mapped != -1 ? mapping.getRoot().getAttributes().get(mapped) : null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,9 @@ import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.RegEx;
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.Syntax;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -428,8 +429,8 @@ class AnnotationUtilsTests {
|
||||||
@Test
|
@Test
|
||||||
void isAnnotationMetaPresentForPlainType() {
|
void isAnnotationMetaPresentForPlainType() {
|
||||||
assertThat(isAnnotationMetaPresent(Order.class, Documented.class)).isTrue();
|
assertThat(isAnnotationMetaPresent(Order.class, Documented.class)).isTrue();
|
||||||
assertThat(isAnnotationMetaPresent(ParametersAreNonnullByDefault.class, Documented.class)).isTrue();
|
assertThat(isAnnotationMetaPresent(ThreadSafe.class, Documented.class)).isTrue();
|
||||||
assertThat(isAnnotationMetaPresent(ParametersAreNonnullByDefault.class, Nonnull.class)).isTrue();
|
assertThat(isAnnotationMetaPresent(RegEx.class, Syntax.class)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
<!-- Framework docs -->
|
<!-- Framework docs -->
|
||||||
<suppress files="org[\\/]springframework[\\/]docs[\\/].+" checks="IllegalImport" id="bannedJUnitJupiterImports" />
|
<suppress files="org[\\/]springframework[\\/]docs[\\/].+" checks="IllegalImport" id="bannedJUnitJupiterImports" />
|
||||||
|
|
||||||
<!-- spring-aop -->
|
|
||||||
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]aopalliance[\\/]" checks="IllegalImport" id="bannedImports" message="javax"/>
|
|
||||||
|
|
||||||
<!-- spring-beans -->
|
<!-- spring-beans -->
|
||||||
<suppress files="TypeMismatchException" checks="MutableException"/>
|
<suppress files="TypeMismatchException" checks="MutableException"/>
|
||||||
<suppress files="BeanCreationException" checks="MutableException"/>
|
<suppress files="BeanCreationException" checks="MutableException"/>
|
||||||
|
@ -40,9 +37,7 @@
|
||||||
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/](asm|cglib|objenesis|javapoet)[\\/]" checks=".*"/>
|
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/](asm|cglib|objenesis|javapoet)[\\/]" checks=".*"/>
|
||||||
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/]aot[\\/]nativex[\\/]feature[\\/]" checks="RegexpSinglelineJava" id="systemOutErrPrint"/>
|
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/]aot[\\/]nativex[\\/]feature[\\/]" checks="RegexpSinglelineJava" id="systemOutErrPrint"/>
|
||||||
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/](core|util)[\\/](SpringProperties|SystemPropertyUtils)" checks="RegexpSinglelineJava" id="systemOutErrPrint"/>
|
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/](core|util)[\\/](SpringProperties|SystemPropertyUtils)" checks="RegexpSinglelineJava" id="systemOutErrPrint"/>
|
||||||
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/]lang[\\/]" checks="IllegalImport" id="bannedImports" message="javax"/>
|
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/]lang[\\/]NonNull.+" checks="IllegalImport" id="bannedNullabilityImports"/>
|
||||||
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]org[\\/]springframework[\\/]core[\\/]annotation[\\/]" checks="IllegalImport" id="bannedImports" message="javax"/>
|
|
||||||
<suppress files="[\\/]src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]core[\\/]annotation[\\/]" checks="IllegalImport" id="bannedImports" message="javax"/>
|
|
||||||
<suppress files="ByteArrayEncoder" checks="SpringLambda"/>
|
<suppress files="ByteArrayEncoder" checks="SpringLambda"/>
|
||||||
<suppress files="SocketUtils" checks="HideUtilityClassConstructor"/>
|
<suppress files="SocketUtils" checks="HideUtilityClassConstructor"/>
|
||||||
<suppress files="ResolvableType" checks="FinalClass"/>
|
<suppress files="ResolvableType" checks="FinalClass"/>
|
||||||
|
|
|
@ -104,10 +104,20 @@
|
||||||
<property name="sortStaticImportsAlphabetically" value="true"/>
|
<property name="sortStaticImportsAlphabetically" value="true"/>
|
||||||
</module>
|
</module>
|
||||||
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
||||||
<property name="id" value="bannedImports"/>
|
<property name="id" value="bannedReactorImports"/>
|
||||||
<property name="regexp" value="true"/>
|
<property name="regexp" value="true"/>
|
||||||
<property name="illegalClasses"
|
<property name="illegalClasses" value="^reactor\.core\.support\.Assert"/>
|
||||||
value="^reactor\.core\.support\.Assert,^org\.slf4j\.LoggerFactory,^(?!org\.jspecify|\.annotations).*(NonNull|Nullable)$"/>
|
</module>
|
||||||
|
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
||||||
|
<property name="id" value="bannedSlf4jImports"/>
|
||||||
|
<property name="regexp" value="true"/>
|
||||||
|
<property name="illegalClasses" value="^org\.slf4j\.LoggerFactory"/>
|
||||||
|
</module>
|
||||||
|
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
||||||
|
<property name="id" value="bannedNullabilityImports"/>
|
||||||
|
<property name="regexp" value="true"/>
|
||||||
|
<!-- Rejects all NonNull, Nonnull, and Nullable types that are NOT in the org.jspecify.annotations package. -->
|
||||||
|
<property name="illegalClasses" value="^(?!org\.jspecify\.annotations).*(Non[Nn]ull|Nullable)$"/>
|
||||||
</module>
|
</module>
|
||||||
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
||||||
<property name="id" value="bannedJUnit3Imports"/>
|
<property name="id" value="bannedJUnit3Imports"/>
|
||||||
|
|
Loading…
Reference in New Issue