Consistent use of @Nullable in spring-test

This commit also removes nullability from two common spots: ResolvableType.getType() and TargetSource.getTarget(), both of which are never effectively null with any regular implementation. For such scenarios, a non-null empty type/target is the cleaner contract.

Issue: SPR-15540
This commit is contained in:
Juergen Hoeller
2017-06-08 22:52:57 +02:00
parent ee5fa2633a
commit fd53d2a51a
134 changed files with 812 additions and 777 deletions

View File

@@ -86,7 +86,7 @@ public class ResolvableType implements Serializable {
* {@code ResolvableType} returned when no value is available. {@code NONE} is used
* in preference to {@code null} so that multiple method calls can be safely chained.
*/
public static final ResolvableType NONE = new ResolvableType(null, null, null, 0);
public static final ResolvableType NONE = new ResolvableType(EmptyType.INSTANCE, null, null, 0);
private static final ResolvableType[] EMPTY_TYPES_ARRAY = new ResolvableType[0];
@@ -95,7 +95,7 @@ public class ResolvableType implements Serializable {
/**
* The underlying Java type being managed (only ever {@code null} for {@link #NONE}).
* The underlying Java type being managed.
*/
private final Type type;
@@ -146,7 +146,7 @@ public class ResolvableType implements Serializable {
* with upfront resolution and a pre-calculated hash.
* @since 4.2
*/
private ResolvableType(@Nullable Type type, @Nullable TypeProvider typeProvider,
private ResolvableType(Type type, @Nullable TypeProvider typeProvider,
@Nullable VariableResolver variableResolver, Integer hash) {
this.type = type;
@@ -188,10 +188,8 @@ public class ResolvableType implements Serializable {
/**
* Return the underling Java {@link Type} being managed. With the exception of
* the {@link #NONE} constant, this method will never return {@code null}.
* Return the underling Java {@link Type} being managed.
*/
@Nullable
public Type getType() {
return SerializableTypeWrapper.unwrap(this.type);
}
@@ -761,7 +759,10 @@ public class ResolvableType implements Serializable {
}
private Class<?> resolveClass() {
if (this.type instanceof Class || this.type == null) {
if (this.type == EmptyType.INSTANCE) {
return null;
}
if (this.type instanceof Class) {
return (Class<?>) this.type;
}
if (this.type instanceof GenericArrayType) {
@@ -903,7 +904,7 @@ public class ResolvableType implements Serializable {
* Custom serialization support for {@link #NONE}.
*/
private Object readResolve() {
return (this.type == null ? NONE : this);
return (this.type == EmptyType.INSTANCE ? NONE : this);
}
/**
@@ -1567,7 +1568,6 @@ public class ResolvableType implements Serializable {
resolveToWildcard = resolveToWildcard.resolveType();
}
WildcardType wildcardType = (WildcardType) resolveToWildcard.type;
Assert.state(wildcardType != null, "Wildcard type not resolved");
Kind boundsType = (wildcardType.getLowerBounds().length > 0 ? Kind.LOWER : Kind.UPPER);
Type[] bounds = boundsType == Kind.UPPER ? wildcardType.getUpperBounds() : wildcardType.getLowerBounds();
ResolvableType[] resolvableBounds = new ResolvableType[bounds.length];
@@ -1583,4 +1583,15 @@ public class ResolvableType implements Serializable {
enum Kind {UPPER, LOWER}
}
@SuppressWarnings("serial")
static class EmptyType implements Type, Serializable {
static final Type INSTANCE = new EmptyType();
Object readResolve() {
return INSTANCE;
}
}
}

View File

@@ -37,19 +37,19 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* Internal utility class that can be used to obtain wrapped {@link Serializable} variants
* of {@link java.lang.reflect.Type}s.
* Internal utility class that can be used to obtain wrapped {@link Serializable}
* variants of {@link java.lang.reflect.Type}s.
*
* <p>{@link #forField(Field) Fields} or {@link #forMethodParameter(MethodParameter)
* MethodParameters} can be used as the root source for a serializable type. Alternatively
* the {@link #forGenericSuperclass(Class) superclass},
* MethodParameters} can be used as the root source for a serializable type.
* Alternatively the {@link #forGenericSuperclass(Class) superclass},
* {@link #forGenericInterfaces(Class) interfaces} or {@link #forTypeParameters(Class)
* type parameters} or a regular {@link Class} can also be used as source.
*
* <p>The returned type will either be a {@link Class} or a serializable proxy of
* {@link GenericArrayType}, {@link ParameterizedType}, {@link TypeVariable} or
* {@link WildcardType}. With the exception of {@link Class} (which is final) calls to
* methods that return further {@link Type}s (for example
* {@link WildcardType}. With the exception of {@link Class} (which is final) calls
* to methods that return further {@link Type}s (for example
* {@link GenericArrayType#getGenericComponentType()}) will be automatically wrapped.
*
* @author Phillip Webb
@@ -123,13 +123,12 @@ abstract class SerializableTypeWrapper {
* @return the original non-serializable type
*/
@SuppressWarnings("unchecked")
@Nullable
public static <T extends Type> T unwrap(T type) {
Type unwrapped = type;
while (unwrapped instanceof SerializableTypeProxy) {
unwrapped = ((SerializableTypeProxy) type).getTypeProvider().getType();
}
return (T) unwrapped;
return (unwrapped != null ? (T) unwrapped : type);
}
/**

View File

@@ -423,7 +423,7 @@ public class AnnotatedElementUtils {
// Exhaustive retrieval of merged annotation attributes...
AnnotationAttributes attributes = getMergedAnnotationAttributes(element, annotationType);
return AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element);
return (attributes != null ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null);
}
/**
@@ -726,7 +726,7 @@ public class AnnotatedElementUtils {
// Exhaustive retrieval of merged annotation attributes...
AnnotationAttributes attributes = findMergedAnnotationAttributes(element, annotationType, false, false);
return AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element);
return (attributes != null ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null);
}
/**

View File

@@ -1482,8 +1482,7 @@ public abstract class AnnotationUtils {
* @param annotationType the type of annotation to synthesize
* @param annotatedElement the element that is annotated with the annotation
* corresponding to the supplied attributes; may be {@code null} if unknown
* @return the synthesized annotation, or {@code null} if the supplied attributes
* map is {@code null}
* @return the synthesized annotation
* @throws IllegalArgumentException if a required attribute is missing or if an
* attribute is not of the correct type
* @throws AnnotationConfigurationException if invalid configuration of
@@ -1495,14 +1494,11 @@ public abstract class AnnotationUtils {
* @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
*/
@SuppressWarnings("unchecked")
@Nullable
public static <A extends Annotation> A synthesizeAnnotation(@Nullable Map<String, Object> attributes,
public static <A extends Annotation> A synthesizeAnnotation(Map<String, Object> attributes,
Class<A> annotationType, @Nullable AnnotatedElement annotatedElement) {
Assert.notNull(attributes, "'attributes' must not be null");
Assert.notNull(annotationType, "'annotationType' must not be null");
if (attributes == null) {
return null;
}
MapAnnotationAttributeExtractor attributeExtractor =
new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* 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.
@@ -16,6 +16,7 @@
package org.springframework.core.style;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -77,7 +78,7 @@ public class DefaultToStringStyler implements ToStringStyler {
}
@Override
public void styleField(StringBuilder buffer, String fieldName, Object value) {
public void styleField(StringBuilder buffer, String fieldName, @Nullable Object value) {
styleFieldStart(buffer, fieldName);
styleValue(buffer, value);
styleFieldEnd(buffer, fieldName);
@@ -91,7 +92,7 @@ public class DefaultToStringStyler implements ToStringStyler {
}
@Override
public void styleValue(StringBuilder buffer, Object value) {
public void styleValue(StringBuilder buffer, @Nullable Object value) {
buffer.append(this.valueStyler.style(value));
}

View File

@@ -152,7 +152,7 @@ public class ToStringCreator {
* @param value the field value
* @return this, to support call-chaining
*/
public ToStringCreator append(String fieldName, Object value) {
public ToStringCreator append(String fieldName, @Nullable Object value) {
printFieldSeparatorIfNecessary();
this.styler.styleField(this.buffer, fieldName, value);
return this;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* 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.
@@ -16,6 +16,8 @@
package org.springframework.core.style;
import org.springframework.lang.Nullable;
/**
* A strategy interface for pretty-printing {@code toString()} methods.
* Encapsulates the print algorithms; some other object such as a builder
@@ -46,7 +48,7 @@ public interface ToStringStyler {
* @param fieldName the he name of the field
* @param value the field value
*/
void styleField(StringBuilder buffer, String fieldName, Object value);
void styleField(StringBuilder buffer, String fieldName, @Nullable Object value);
/**
* Style the given value.

View File

@@ -404,6 +404,12 @@ public abstract class CollectionUtils {
this.map = map;
}
@Override
public V getFirst(K key) {
List<V> values = this.map.get(key);
return (values != null ? values.get(0) : null);
}
@Override
public void add(K key, @Nullable V value) {
List<V> values = this.map.computeIfAbsent(key, k -> new LinkedList<>());
@@ -411,17 +417,11 @@ public abstract class CollectionUtils {
}
@Override
public void addAll(K key, List<V> values) {
public void addAll(K key, List<? extends V> values) {
List<V> currentValues = this.map.computeIfAbsent(key, k -> new LinkedList<>());
currentValues.addAll(values);
}
@Override
public V getFirst(K key) {
List<V> values = this.map.get(key);
return (values != null ? values.get(0) : null);
}
@Override
public void set(K key, V value) {
List<V> values = new LinkedList<>();

View File

@@ -75,6 +75,12 @@ public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializa
// MultiValueMap implementation
@Override
public V getFirst(K key) {
List<V> values = this.targetMap.get(key);
return (values != null ? values.get(0) : null);
}
@Override
public void add(K key, @Nullable V value) {
List<V> values = this.targetMap.computeIfAbsent(key, k -> new LinkedList<>());
@@ -82,17 +88,11 @@ public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V>, Serializa
}
@Override
public void addAll(K key, List<V> values) {
public void addAll(K key, List<? extends V> values) {
List<V> currentValues = this.targetMap.computeIfAbsent(key, k -> new LinkedList<>());
currentValues.addAll(values);
}
@Override
public V getFirst(K key) {
List<V> values = this.targetMap.get(key);
return (values != null ? values.get(0) : null);
}
@Override
public void set(K key, V value) {
List<V> values = new LinkedList<>();

View File

@@ -32,7 +32,7 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
/**
* Return the first value for the given key.
* @param key the key
* @return the first value for the specified key, or {@code null}
* @return the first value for the specified key, or {@code null} if none
*/
@Nullable
V getFirst(K key);
@@ -50,7 +50,7 @@ public interface MultiValueMap<K, V> extends Map<K, List<V>> {
* @param values the values to be added
* @since 5.0
*/
void addAll(K key, List<V> values);
void addAll(K key, List<? extends V> values);
/**
* Set the given single value under the given key.

View File

@@ -119,7 +119,7 @@ public abstract class ReflectionUtils {
* @param target the target object on which to set the field
* @param value the value to set (may be {@code null})
*/
public static void setField(Field field, Object target, @Nullable Object value) {
public static void setField(Field field, @Nullable Object target, @Nullable Object value) {
try {
field.set(target, value);
}