Revisit nullability annotations

This commit introduces the following changes.

1) It adds a new Spring @NonNull annotation which allows to apply
@NonNullApi semantic on a specific element, like @Nullable does.
Combined with @Nullable, it allows partial null-safety support when
package granularity is too broad.

2) @Nullable and @NonNull can apply to ElementType.TYPE_USE in order
to be used on generic type arguments (SPR-15942).

3) Annotations does not apply to ElementType.TYPE_PARAMETER anymore
since it is not supported yet (applicability for such use case is
controversial and need to be discussed).

4) @NonNullApi does not apply to ElementType.FIELD anymore since in a
lot of use cases (private, protected) it is not part for the public API
+ its usage should remain opt-in. A dedicated @NonNullFields annotation
has been added in order to set fields default to non-nullable.

5) Updated Javadoc and reference documentation.

Issue: SPR-15756
This commit is contained in:
Sebastien Deleuze
2017-09-15 13:26:41 +02:00
parent ec2218c967
commit 1bc93e3d0f
364 changed files with 1003 additions and 113 deletions

View File

@@ -3,6 +3,8 @@
* annotations with attribute overrides.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.annotation;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -4,6 +4,8 @@
* between a reactive stream of bytes and Java objects.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.codec;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* SPI to implement Converters for the type conversion system.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.convert.converter;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Type conversion system API.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.convert;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Default implementation of the type conversion system.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.convert.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* profile and hierarchical property source support.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Generic abstraction for working with byte buffer implementations.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.io.buffer;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Generic abstraction for (file-based) resources, used throughout the framework.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.io;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* Includes a ResourcePatternResolver mechanism.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.io.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* and other core helpers that are not specific to any part of the framework.
*/
@NonNullApi
@NonNullFields
package org.springframework.core;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -4,6 +4,8 @@
* Includes exceptions for serialization and deserialization failures.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.serializer;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* Includes adapters to the Converter SPI.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.serializer.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Support for styling values as Strings, with ToStringCreator as central class.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.style;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* and provides SyncTaskExecutor and SimpleAsyncTaskExecutor implementations.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.task;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* Includes an adapter for the standard ExecutorService interface.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.task.support;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Support classes for reading annotation and class-level metadata.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.type.classreading;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Core support package for type filtering (e.g. for classpath scanning).
*/
@NonNullApi
@NonNullFields
package org.springframework.core.type.filter;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Core support package for type introspection.
*/
@NonNullApi
@NonNullFields
package org.springframework.core.type;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.lang;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
/**
* A common Spring annotation to declare that annotated elements cannot be {@code null}.
* Leverages JSR 305 meta-annotations to indicate nullability in Java to common tools with
* JSR 305 support and used by Kotlin to infer nullability of Spring API.
*
* <p>Should be used at generic type argument, parameter, return value, and field level.
* Methods overrides should repeat parent {@code @NonNull} annotations unless they behave
* differently.
*
* <p>Use {@code @NonNullApi} (scope = parameters + return values) and/or {@code @NonNullFields}
* (scope = fields) to set the default behavior to non-nullable in order to avoid annotating
* your whole codebase with {@code @NonNull}. No default retricted to generic type argument
* is possible ({@code ElementType.TYPE_USE} scope is too wide) so each generic type argument
* needs to be annotated with @code @NonNull}.
*
* @author Sebastien Deleuze
* @author Juergen Hoeller
* @since 5.0
* @see NonNullApi
* @see NonNullFields
* @see Nullable
*/
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_USE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierNickname
public @interface NonNull {
}

View File

@@ -26,25 +26,30 @@ import javax.annotation.meta.TypeQualifierDefault;
/**
* A common Spring annotation to declare that parameters and return values
* are to be considered as non-nullable by default for a given package,
* along with their underlying fields.
* are to be considered as non-nullable by default for a given package.
* Leverages JSR 305 meta-annotations to indicate nullability in Java to common tools with
* JSR 305 support and used by Kotlin to infer nullability of Spring API.
*
*
* <p>Should be used at package level in association with {@link Nullable}
* annotations at parameter and return value level.
*
* <p>Leverages JSR-305 meta-annotations to indicate its semantics to
* common tools with JSR-305 support.
* <p>This annotation does not define nullability of generic type arguments, because
* {@code @TypeQualifierDefault(ElementType.TYPE_USE)} scope would be too broad.
* As a consequence, each API generic type argument should be annotated
* with {@link Nullable} or {@link NonNull} to specify their nullability.
*
* @author Sebastien Deleuze
* @author Juergen Hoeller
* @since 5.0
* @see NonNullFields
* @see Nullable
* @see javax.annotation.Nonnull
* @see NonNull
*/
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_PARAMETER, ElementType.FIELD})
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.lang;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
/**
* A common Spring annotation to declare that fields are to be considered as
* non-nullable by default for a given package. Leverages JSR 305 meta-annotations to
* indicate nullability in Java to common tools with JSR 305 support and used by Kotlin
* to infer nullability of Spring API.
*
* <p>Should be used at package level in association with {@link Nullable}
* annotations at field level.
*
* <p>This annotation does not define nullability of generic type arguments, because
* {@code @TypeQualifierDefault(ElementType.TYPE_USE)} scope would be too broad.
* As a consequence, each field generic type argument should be annotated
* with {@link Nullable} or {@link NonNull} to specify their nullability.
*
* @author Sebastien Deleuze
* @since 5.0
* @see NonNullFields
* @see Nullable
* @see NonNull
*/
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault(ElementType.FIELD)
public @interface NonNullFields {
}

View File

@@ -26,23 +26,25 @@ import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
/**
* A common Spring annotation to declare that the annotated parameter,
* return value or field could be {@code null} under some circumstances.
* A common Spring annotation to declare that annotated elements can be {@code null} under
* some circumstance. Leverages JSR 305 meta-annotations to indicate nullability in Java
* to common tools with JSR 305 support and used by Kotlin to infer nullability of Spring API.
*
* <p>Should be used at parameters, return values and optionally field level in association
* with {@link NonNullApi} package-level annotations. Methods overrides should repeat parent
* parameter or return value {@code @Nullable} annotations unless they behave differently.
* <p>Should be used at generic type argument, parameter, return value, and field level.
* Methods overrides should repeat parent {@code @Nullable} annotations unless they behave
* differently.
*
* <p>Leverages JSR-305 meta-annotations to indicate its semantics to
* common tools with JSR-305 support.
* <p>Can be used in association with {@code NonNullApi} or {@code @NonNullFields} to
* override the default non-nullable semantic to nullable.
*
* @author Sebastien Deleuze
* @author Juergen Hoeller
* @since 5.0
* @see NonNullApi
* @see javax.annotation.Nullable
* @see NonNullFields
* @see NonNull
*/
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_PARAMETER, ElementType.FIELD})
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_USE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull(when = When.MAYBE)

View File

@@ -3,5 +3,6 @@
* Used descriptively within the framework codebase; validated by Animal Sniffer at build time.
*/
@NonNullApi
@NonNullFields
package org.springframework.lang;

View File

@@ -2,6 +2,8 @@
* A generic back-off abstraction.
*/
@NonNullApi
@NonNullFields
package org.springframework.util.backoff;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* such as an invertible comparator and a compound comparator.
*/
@NonNullApi
@NonNullFields
package org.springframework.util.comparator;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -2,6 +2,8 @@
* Useful generic {@code java.util.concurrent.Future} extension.
*/
@NonNullApi
@NonNullFields
package org.springframework.util.concurrent;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* a Log4J configurer, and a state holder for paged lists of objects.
*/
@NonNullApi
@NonNullFields
package org.springframework.util;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -3,6 +3,8 @@
* such as error handlers that log warnings via Commons Logging.
*/
@NonNullApi
@NonNullFields
package org.springframework.util.xml;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;