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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user