Consistent use of @Nullable across the codebase (even for internals)

Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments.

Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit.

Issue: SPR-15540
This commit is contained in:
Juergen Hoeller
2017-06-07 14:17:48 +02:00
parent ffc3f6d87d
commit f813712f5b
1493 changed files with 10670 additions and 9172 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -57,9 +57,10 @@ public abstract class BridgeMethodResolver {
* if no more specific one could be found)
*/
public static Method findBridgedMethod(Method bridgeMethod) {
if (bridgeMethod == null || !bridgeMethod.isBridge()) {
if (!bridgeMethod.isBridge()) {
return bridgeMethod;
}
// Gather all methods with matching name and parameter size.
List<Method> candidateMethods = new ArrayList<>();
Method[] methods = ReflectionUtils.getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
@@ -68,10 +69,12 @@ public abstract class BridgeMethodResolver {
candidateMethods.add(candidateMethod);
}
}
// Now perform simple quick check.
if (candidateMethods.size() == 1) {
return candidateMethods.get(0);
}
// Search for candidate match.
Method bridgedMethod = searchCandidates(candidateMethods, bridgeMethod);
if (bridgedMethod != null) {
@@ -104,7 +107,7 @@ public abstract class BridgeMethodResolver {
* @return the bridged method, or {@code null} if none found
*/
@Nullable
private static Method searchCandidates(@Nullable List<Method> candidateMethods, Method bridgeMethod) {
private static Method searchCandidates(List<Method> candidateMethods, Method bridgeMethod) {
if (candidateMethods.isEmpty()) {
return null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -91,7 +91,7 @@ public abstract class CollectionFactory {
* @param collectionType the collection type to check
* @return {@code true} if the type is <em>approximable</em>
*/
public static boolean isApproximableCollectionType(Class<?> collectionType) {
public static boolean isApproximableCollectionType(@Nullable Class<?> collectionType) {
return (collectionType != null && approximableCollectionTypes.contains(collectionType));
}
@@ -216,7 +216,7 @@ public abstract class CollectionFactory {
* @param mapType the map type to check
* @return {@code true} if the type is <em>approximable</em>
*/
public static boolean isApproximableMapType(Class<?> mapType) {
public static boolean isApproximableMapType(@Nullable Class<?> mapType) {
return (mapType != null && approximableMapTypes.contains(mapType));
}
@@ -334,6 +334,7 @@ public abstract class CollectionFactory {
public static Properties createStringAdaptingProperties() {
return new Properties() {
@Override
@Nullable
public String getProperty(String key) {
Object value = get(key);
return (value != null ? value.toString() : null);

View File

@@ -46,7 +46,7 @@ public class ConfigurableObjectInputStream extends ObjectInputStream {
* @param classLoader the ClassLoader to use for loading local classes
* @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream)
*/
public ConfigurableObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
public ConfigurableObjectInputStream(InputStream in, @Nullable ClassLoader classLoader) throws IOException {
this(in, classLoader, true);
}
@@ -59,7 +59,7 @@ public class ConfigurableObjectInputStream extends ObjectInputStream {
* @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream)
*/
public ConfigurableObjectInputStream(
InputStream in, ClassLoader classLoader, boolean acceptProxyClasses) throws IOException {
InputStream in, @Nullable ClassLoader classLoader, boolean acceptProxyClasses) throws IOException {
super(in);
this.classLoader = classLoader;

View File

@@ -181,12 +181,10 @@ public abstract class Conventions {
* method, taking the generic collection type, if any, into account, falling
* back on the given return value if the method declaration is not specific
* enough, e.g. {@code Object} return type or untyped collection.
*
* <p>As of 5.0 this method supports reactive types:<br>
* {@code Mono<com.myapp.Product>} becomes {@code "productMono"}<br>
* {@code Flux<com.myapp.MyProduct>} becomes {@code "myProductFlux"}<br>
* {@code Observable<com.myapp.MyProduct>} becomes {@code "myProductObservable"}<br>
*
* @param method the method to generate a variable name for
* @param resolvedType the resolved return type of the method
* @param value the return value (may be {@code null} if not available)
@@ -230,12 +228,11 @@ public abstract class Conventions {
}
else {
valueClass = resolvedType;
if (reactiveAdapterRegistry.hasAdapters()) {
ReactiveAdapter adapter = reactiveAdapterRegistry.getAdapter(valueClass);
if (adapter != null && !adapter.getDescriptor().isNoValue()) {
reactiveSuffix = ClassUtils.getShortName(valueClass);
valueClass = ResolvableType.forMethodReturnType(method).getGeneric(0).resolve();
valueClass = ResolvableType.forMethodReturnType(method).getGeneric().resolve(Object.class);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -53,7 +54,7 @@ public abstract class DecoratingClassLoader extends ClassLoader {
* Create a new DecoratingClassLoader using the given parent ClassLoader
* for delegation.
*/
public DecoratingClassLoader(ClassLoader parent) {
public DecoratingClassLoader(@Nullable ClassLoader parent) {
super(parent);
}

View File

@@ -111,6 +111,7 @@ public abstract class GenericTypeResolver {
return getSingleGeneric(resolvableType);
}
@Nullable
private static Class<?> getSingleGeneric(ResolvableType resolvableType) {
Assert.isTrue(resolvableType.getGenerics().length == 1,
() -> "Expected 1 type argument on generic interface [" + resolvableType +
@@ -146,14 +147,16 @@ public abstract class GenericTypeResolver {
* @return the resolved type (possibly the given generic type as-is)
* @since 5.0
*/
@Nullable
public static Type resolveType(Type genericType, Class<?> contextClass) {
public static Type resolveType(Type genericType, @Nullable Class<?> contextClass) {
if (contextClass != null) {
if (genericType instanceof TypeVariable) {
ResolvableType resolvedTypeVariable = resolveVariable(
(TypeVariable<?>) genericType, ResolvableType.forClass(contextClass));
if (resolvedTypeVariable != ResolvableType.NONE) {
return resolvedTypeVariable.resolve();
Class<?> resolved = resolvedTypeVariable.resolve();
if (resolved != null) {
return resolved;
}
}
}
else if (genericType instanceof ParameterizedType) {
@@ -178,7 +181,10 @@ public abstract class GenericTypeResolver {
generics[i] = ResolvableType.forType(typeArgument).resolve();
}
}
return ResolvableType.forClassWithGenerics(resolvedType.getRawClass(), generics).getType();
Class<?> rawClass = resolvedType.getRawClass();
if (rawClass != null) {
return ResolvableType.forClassWithGenerics(rawClass, generics).getType();
}
}
}
}
@@ -242,8 +248,9 @@ public abstract class GenericTypeResolver {
@SuppressWarnings("rawtypes")
private static void buildTypeVariableMap(ResolvableType type, Map<TypeVariable, Type> typeVariableMap) {
if (type != ResolvableType.NONE) {
if (type.getType() instanceof ParameterizedType) {
TypeVariable<?>[] variables = type.resolve().getTypeParameters();
Class<?> resolved = type.resolve();
if (resolved != null && type.getType() instanceof ParameterizedType) {
TypeVariable<?>[] variables = resolved.getTypeParameters();
for (int i = 0; i < variables.length; i++) {
ResolvableType generic = type.getGeneric(i);
while (generic.getType() instanceof TypeVariable<?>) {
@@ -258,8 +265,8 @@ public abstract class GenericTypeResolver {
for (ResolvableType interfaceType : type.getInterfaces()) {
buildTypeVariableMap(interfaceType, typeVariableMap);
}
if (type.resolve().isMemberClass()) {
buildTypeVariableMap(ResolvableType.forClass(type.resolve().getEnclosingClass()), typeVariableMap);
if (resolved != null && resolved.isMemberClass()) {
buildTypeVariableMap(ResolvableType.forClass(resolved.getEnclosingClass()), typeVariableMap);
}
}
}

View File

@@ -35,6 +35,7 @@ import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.SpringAsmInfo;
import org.springframework.asm.Type;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@@ -157,6 +158,7 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
}
@Override
@Nullable
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
// exclude synthetic + bridged && static class initialization
if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -76,7 +76,7 @@ public final class MethodClassKey implements Comparable<MethodClassKey> {
int result = this.method.getName().compareTo(other.method.getName());
if (result == 0) {
result = this.method.toString().compareTo(other.method.toString());
if (result == 0 && this.targetClass != null) {
if (result == 0 && this.targetClass != null && other.targetClass != null) {
result = this.targetClass.getName().compareTo(other.targetClass.getName());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -52,7 +52,7 @@ public abstract class MethodIntrospector {
* @return the selected methods associated with their metadata (in the order of retrieval),
* or an empty map in case of no match
*/
public static <T> Map<Method, T> selectMethods(Class<?> targetType, @Nullable final MetadataLookup<T> metadataLookup) {
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<>();
Set<Class<?>> handlerTypes = new LinkedHashSet<>();
Class<?> specificHandlerType = null;
@@ -66,16 +66,13 @@ public abstract class MethodIntrospector {
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
ReflectionUtils.doWithMethods(currentHandlerType, method -> {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
@@ -93,12 +90,8 @@ public abstract class MethodIntrospector {
* @return the selected methods, or an empty set in case of no match
*/
public static Set<Method> selectMethods(Class<?> targetType, final ReflectionUtils.MethodFilter methodFilter) {
return selectMethods(targetType, new MetadataLookup<Boolean>() {
@Override
public Boolean inspect(Method method) {
return (methodFilter.matches(method) ? Boolean.TRUE : null);
}
}).keySet();
return selectMethods(targetType,
(MetadataLookup<Boolean>) method -> (methodFilter.matches(method) ? Boolean.TRUE : null)).keySet();
}
/**

View File

@@ -378,7 +378,7 @@ public class MethodParameter {
/**
* Set a resolved (generic) parameter type.
*/
void setParameterType(Class<?> parameterType) {
void setParameterType(@Nullable Class<?> parameterType) {
this.parameterType = parameterType;
}
@@ -408,7 +408,7 @@ public class MethodParameter {
public Type getGenericParameterType() {
if (this.genericParameterType == null) {
if (this.parameterIndex < 0) {
this.genericParameterType = (this.method != null ? this.method.getGenericReturnType() : null);
this.genericParameterType = (this.method != null ? this.method.getGenericReturnType() : void.class);
}
else {
this.genericParameterType = (this.method != null ?
@@ -489,7 +489,8 @@ public class MethodParameter {
*/
@Nullable
public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
return adaptAnnotation(getAnnotatedElement().getAnnotation(annotationType));
A annotation = getAnnotatedElement().getAnnotation(annotationType);
return (annotation != null ? adaptAnnotation(annotation) : null);
}
/**
@@ -560,7 +561,7 @@ public class MethodParameter {
* this point; it just allows discovery to happen when the application calls
* {@link #getParameterName()} (if ever).
*/
public void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer) {
public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
@@ -720,22 +721,28 @@ public class MethodParameter {
*/
public static boolean isNullable(MethodParameter param) {
if (param.getContainingClass().isAnnotationPresent(Metadata.class)) {
int parameterIndex = param.getParameterIndex();
if (parameterIndex == -1) {
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(param.getMethod());
Method method = param.getMethod();
Constructor<?> ctor = param.getConstructor();
int index = param.getParameterIndex();
if (method != null && index == -1) {
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
return (function != null && function.getReturnType().isMarkedNullable());
}
else {
KFunction<?> function = (param.getMethod() != null ?
ReflectJvmMapping.getKotlinFunction(param.getMethod()) :
ReflectJvmMapping.getKotlinFunction(param.getConstructor()));
KFunction<?> function = null;
if (method != null) {
function = ReflectJvmMapping.getKotlinFunction(method);
}
else if (ctor != null) {
function = ReflectJvmMapping.getKotlinFunction(ctor);
}
if (function != null) {
List<KParameter> parameters = function.getParameters();
return parameters
.stream()
.filter(p -> KParameter.Kind.VALUE.equals(p.getKind()))
.collect(Collectors.toList())
.get(parameterIndex)
.get(index)
.getType()
.isMarkedNullable();
}

View File

@@ -62,7 +62,7 @@ public abstract class NestedCheckedException extends Exception {
* @param msg the detail message
* @param cause the nested exception
*/
public NestedCheckedException(String msg, Throwable cause) {
public NestedCheckedException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}
@@ -72,6 +72,7 @@ public abstract class NestedCheckedException extends Exception {
* if there is one.
*/
@Override
@Nullable
public String getMessage() {
return NestedExceptionUtils.buildMessage(super.getMessage(), getCause());
}
@@ -106,7 +107,7 @@ public abstract class NestedCheckedException extends Exception {
* @param exType the exception type to look for
* @return whether there is a nested exception of the specified type
*/
public boolean contains(Class<?> exType) {
public boolean contains(@Nullable Class<?> exType) {
if (exType == null) {
return false;
}

View File

@@ -40,7 +40,8 @@ public abstract class NestedExceptionUtils {
* @param cause the root cause
* @return the full exception message
*/
public static String buildMessage(String message, Throwable cause) {
@Nullable
public static String buildMessage(@Nullable String message, @Nullable Throwable cause) {
if (cause == null) {
return message;
}
@@ -59,7 +60,7 @@ public abstract class NestedExceptionUtils {
* @since 4.3.9
*/
@Nullable
public static Throwable getRootCause(Throwable original) {
public static Throwable getRootCause(@Nullable Throwable original) {
if (original == null) {
return null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 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.
@@ -18,6 +18,8 @@ package org.springframework.core;
import java.io.IOException;
import org.springframework.lang.Nullable;
/**
* Subclass of {@link IOException} that properly handles a root cause,
* exposing the root cause just like NestedChecked/RuntimeException does.
@@ -59,7 +61,7 @@ public class NestedIOException extends IOException {
* @param msg the detail message
* @param cause the nested exception
*/
public NestedIOException(String msg, Throwable cause) {
public NestedIOException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}
@@ -69,6 +71,7 @@ public class NestedIOException extends IOException {
* if there is one.
*/
@Override
@Nullable
public String getMessage() {
return NestedExceptionUtils.buildMessage(super.getMessage(), getCause());
}

View File

@@ -62,7 +62,7 @@ public abstract class NestedRuntimeException extends RuntimeException {
* @param msg the detail message
* @param cause the nested exception
*/
public NestedRuntimeException(String msg, Throwable cause) {
public NestedRuntimeException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}
@@ -72,6 +72,7 @@ public abstract class NestedRuntimeException extends RuntimeException {
* if there is one.
*/
@Override
@Nullable
public String getMessage() {
return NestedExceptionUtils.buildMessage(super.getMessage(), getCause());
}
@@ -107,7 +108,7 @@ public abstract class NestedRuntimeException extends RuntimeException {
* @param exType the exception type to look for
* @return whether there is a nested exception of the specified type
*/
public boolean contains(Class<?> exType) {
public boolean contains(@Nullable Class<?> exType) {
if (exType == null) {
return false;
}

View File

@@ -61,12 +61,7 @@ public class OrderComparator implements Comparator<Object> {
* @since 4.1
*/
public Comparator<Object> withSourceProvider(final OrderSourceProvider sourceProvider) {
return new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return doCompare(o1, o2, sourceProvider);
}
};
return (o1, o2) -> doCompare(o1, o2, sourceProvider);
}
@Override
@@ -97,21 +92,23 @@ public class OrderComparator implements Comparator<Object> {
* @param obj the object to check
* @return the order value, or {@code Ordered.LOWEST_PRECEDENCE} as fallback
*/
private int getOrder(Object obj, OrderSourceProvider sourceProvider) {
private int getOrder(Object obj, @Nullable OrderSourceProvider sourceProvider) {
Integer order = null;
if (sourceProvider != null) {
Object orderSource = sourceProvider.getOrderSource(obj);
if (orderSource != null && orderSource.getClass().isArray()) {
Object[] sources = ObjectUtils.toObjectArray(orderSource);
for (Object source : sources) {
order = findOrder(source);
if (order != null) {
break;
if (orderSource != null) {
if (orderSource.getClass().isArray()) {
Object[] sources = ObjectUtils.toObjectArray(orderSource);
for (Object source : sources) {
order = findOrder(source);
if (order != null) {
break;
}
}
}
}
else {
order = findOrder(orderSource);
else {
order = findOrder(orderSource);
}
}
}
return (order != null ? order : getOrder(obj));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -54,7 +54,7 @@ public class OverridingClassLoader extends DecoratingClassLoader {
* Create a new OverridingClassLoader for the given ClassLoader.
* @param parent the ClassLoader to build an overriding ClassLoader for
*/
public OverridingClassLoader(ClassLoader parent) {
public OverridingClassLoader(@Nullable ClassLoader parent) {
this(parent, null);
}
@@ -64,7 +64,7 @@ public class OverridingClassLoader extends DecoratingClassLoader {
* @param overrideDelegate the ClassLoader to delegate to for overriding
* @since 4.3
*/
public OverridingClassLoader(ClassLoader parent, ClassLoader overrideDelegate) {
public OverridingClassLoader(@Nullable ClassLoader parent, @Nullable ClassLoader overrideDelegate) {
super(parent);
this.overrideDelegate = overrideDelegate;
for (String packageName : DEFAULT_EXCLUDED_PACKAGES) {
@@ -160,6 +160,7 @@ public class OverridingClassLoader extends DecoratingClassLoader {
* @param name the name of the class
* @return the InputStream containing the byte code for the specified class
*/
@Nullable
protected InputStream openStreamForClass(String name) {
String internalName = name.replace('.', '/') + CLASS_FILE_SUFFIX;
return getParent().getResourceAsStream(internalName);

View File

@@ -20,6 +20,7 @@ import java.util.function.Function;
import org.reactivestreams.Publisher;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -104,7 +105,7 @@ public class ReactiveAdapter {
* @return the Publisher representing the adaptation
*/
@SuppressWarnings("unchecked")
public <T> Publisher<T> toPublisher(Object source) {
public <T> Publisher<T> toPublisher(@Nullable Object source) {
if (source == null) {
source = getDescriptor().getEmptyValue();
}
@@ -117,7 +118,7 @@ public class ReactiveAdapter {
* @return the reactive type instance representing the adapted publisher
*/
public Object fromPublisher(Publisher<?> publisher) {
return (publisher != null ? this.fromPublisherFunction.apply(publisher) : null);
return this.fromPublisherFunction.apply(publisher);
}
}

View File

@@ -109,7 +109,8 @@ public class ReactiveAdapterRegistry {
/**
* Get the adapter for the given reactive type.
*/
public ReactiveAdapter getAdapter(@Nullable Class<?> reactiveType) {
@Nullable
public ReactiveAdapter getAdapter(Class<?> reactiveType) {
return getAdapter(reactiveType, null);
}
@@ -123,7 +124,6 @@ public class ReactiveAdapterRegistry {
*/
@Nullable
public ReactiveAdapter getAdapter(@Nullable Class<?> reactiveType, @Nullable Object source) {
Object sourceToUse = (source instanceof Optional ? ((Optional<?>) source).orElse(null) : source);
Class<?> clazz = (sourceToUse != null ? sourceToUse.getClass() : reactiveType);
if (clazz == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core;
import java.util.function.Supplier;
@@ -99,7 +100,7 @@ public class ReactiveTypeDescriptor {
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}

View File

@@ -132,7 +132,7 @@ public class ResolvableType implements Serializable {
* Private constructor used to create a new {@link ResolvableType} for cache key purposes,
* with no upfront resolution.
*/
private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) {
private ResolvableType(Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
this.type = type;
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
@@ -146,7 +146,9 @@ public class ResolvableType implements Serializable {
* with upfront resolution and a pre-calculated hash.
* @since 4.2
*/
private ResolvableType(@Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver, Integer hash) {
private ResolvableType(@Nullable Type type, @Nullable TypeProvider typeProvider,
@Nullable VariableResolver variableResolver, Integer hash) {
this.type = type;
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
@@ -159,8 +161,8 @@ public class ResolvableType implements Serializable {
* Private constructor used to create a new {@link ResolvableType} for uncached purposes,
* with upfront resolution but lazily calculated hash.
*/
private ResolvableType(
Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver, ResolvableType componentType) {
private ResolvableType(Type type, @Nullable TypeProvider typeProvider,
@Nullable VariableResolver variableResolver, @Nullable ResolvableType componentType) {
this.type = type;
this.typeProvider = typeProvider;
@@ -175,7 +177,7 @@ public class ResolvableType implements Serializable {
* Avoids all {@code instanceof} checks in order to create a straight {@link Class} wrapper.
* @since 4.2
*/
private ResolvableType(Class<?> clazz) {
private ResolvableType(@Nullable Class<?> clazz) {
this.resolved = (clazz != null ? clazz : Object.class);
this.type = this.resolved;
this.typeProvider = null;
@@ -189,6 +191,7 @@ 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}.
*/
@Nullable
public Type getType() {
return SerializableTypeWrapper.unwrap(this.type);
}
@@ -227,7 +230,7 @@ public class ResolvableType implements Serializable {
* @since 4.2
* @see #isAssignableFrom(Class)
*/
public boolean isInstance(Object obj) {
public boolean isInstance(@Nullable Object obj) {
return (obj != null && isAssignableFrom(obj.getClass()));
}
@@ -625,7 +628,7 @@ public class ResolvableType implements Serializable {
* @see #resolveGeneric(int...)
* @see #resolveGenerics()
*/
public ResolvableType getGeneric(int... indexes) {
public ResolvableType getGeneric(@Nullable int... indexes) {
ResolvableType[] generics = getGenerics();
if (indexes == null || indexes.length == 0) {
return (generics.length == 0 ? NONE : generics[0]);
@@ -687,20 +690,24 @@ public class ResolvableType implements Serializable {
* @see #resolve()
*/
public Class<?>[] resolveGenerics() {
return resolveGenerics(null);
ResolvableType[] generics = getGenerics();
Class<?>[] resolvedGenerics = new Class<?>[generics.length];
for (int i = 0; i < generics.length; i++) {
resolvedGenerics[i] = generics[i].resolve();
}
return resolvedGenerics;
}
/**
* Convenience method that will {@link #getGenerics() get} and {@link #resolve()
* resolve} generic parameters, using the specified {@code fallback} if any type
* cannot be resolved.
* @param fallback the fallback class to use if resolution fails (may be {@code null})
* @return an array of resolved generic parameters (the resulting array will never be
* {@code null}, but it may contain {@code null} elements})
* @param fallback the fallback class to use if resolution fails
* @return an array of resolved generic parameters
* @see #getGenerics()
* @see #resolve()
*/
public Class<?>[] resolveGenerics(@Nullable Class<?> fallback) {
public Class<?>[] resolveGenerics(Class<?> fallback) {
ResolvableType[] generics = getGenerics();
Class<?>[] resolvedGenerics = new Class<?>[generics.length];
for (int i = 0; i < generics.length; i++) {
@@ -735,7 +742,7 @@ public class ResolvableType implements Serializable {
*/
@Nullable
public Class<?> resolve() {
return resolve(null);
return (this.resolved != null ? this.resolved : null);
}
/**
@@ -743,13 +750,13 @@ public class ResolvableType implements Serializable {
* {@code fallback} if the type cannot be resolved. This method will consider bounds
* of {@link TypeVariable}s and {@link WildcardType}s if direct resolution fails;
* however, bounds of {@code Object.class} will be ignored.
* @param fallback the fallback class to use if resolution fails (may be {@code null})
* @param fallback the fallback class to use if resolution fails
* @return the resolved {@link Class} or the {@code fallback}
* @see #resolve()
* @see #resolveGeneric(int...)
* @see #resolveGenerics()
*/
public Class<?> resolve(@Nullable Class<?> fallback) {
public Class<?> resolve(Class<?> fallback) {
return (this.resolved != null ? this.resolved : fallback);
}
@@ -810,15 +817,20 @@ public class ResolvableType implements Serializable {
}
if (this.type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) this.type;
TypeVariable<?>[] variables = resolve().getTypeParameters();
Class<?> resolved = resolve();
if (resolved == null) {
return null;
}
TypeVariable<?>[] variables = resolved.getTypeParameters();
for (int i = 0; i < variables.length; i++) {
if (ObjectUtils.nullSafeEquals(variables[i].getName(), variable.getName())) {
Type actualType = parameterizedType.getActualTypeArguments()[i];
return forType(actualType, this.variableResolver);
}
}
if (parameterizedType.getOwnerType() != null) {
return forType(parameterizedType.getOwnerType(), this.variableResolver).resolveVariable(variable);
Type ownerType = parameterizedType.getOwnerType();
if (ownerType != null) {
return forType(ownerType, this.variableResolver).resolveVariable(variable);
}
}
if (this.variableResolver != null) {
@@ -960,12 +972,12 @@ public class ResolvableType implements Serializable {
}
@Override
public boolean isAssignableFrom(Class<?> other) {
return ClassUtils.isAssignable(getRawClass(), other);
return (clazz == null || ClassUtils.isAssignable(clazz, other));
}
@Override
public boolean isAssignableFrom(ResolvableType other) {
Class<?> otherClass = other.getRawClass();
return (otherClass != null && ClassUtils.isAssignable(getRawClass(), otherClass));
return (otherClass != null && (clazz == null || ClassUtils.isAssignable(clazz, otherClass)));
}
};
}
@@ -1086,7 +1098,7 @@ public class ResolvableType implements Serializable {
* @return a {@link ResolvableType} for the specified field
* @see #forField(Field)
*/
public static ResolvableType forField(Field field, ResolvableType implementationType) {
public static ResolvableType forField(Field field, @Nullable ResolvableType implementationType) {
Assert.notNull(field, "Field must not be null");
ResolvableType owner = (implementationType != null ? implementationType : NONE);
owner = owner.as(field.getDeclaringClass());
@@ -1233,7 +1245,9 @@ public class ResolvableType implements Serializable {
* @return a {@link ResolvableType} for the specified method parameter
* @see #forMethodParameter(MethodParameter)
*/
public static ResolvableType forMethodParameter(MethodParameter methodParameter, ResolvableType implementationType) {
public static ResolvableType forMethodParameter(MethodParameter methodParameter,
@Nullable ResolvableType implementationType) {
Assert.notNull(methodParameter, "MethodParameter must not be null");
implementationType = (implementationType != null ? implementationType :
forType(methodParameter.getContainingClass()));
@@ -1250,7 +1264,7 @@ public class ResolvableType implements Serializable {
* @return a {@link ResolvableType} for the specified method parameter
* @see #forMethodParameter(Method, int)
*/
public static ResolvableType forMethodParameter(MethodParameter methodParameter, Type targetType) {
public static ResolvableType forMethodParameter(MethodParameter methodParameter, @Nullable Type targetType) {
Assert.notNull(methodParameter, "MethodParameter must not be null");
ResolvableType owner = forType(methodParameter.getContainingClass()).as(methodParameter.getDeclaringClass());
return forType(targetType, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()).
@@ -1281,7 +1295,7 @@ public class ResolvableType implements Serializable {
return new ResolvableType(arrayClass, null, null, componentType);
}
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) {
private static ResolvableType[] forTypes(Type[] types, @Nullable VariableResolver owner) {
ResolvableType[] result = new ResolvableType[types.length];
for (int i = 0; i < types.length; i++) {
result[i] = forType(types[i], owner);
@@ -1292,7 +1306,7 @@ public class ResolvableType implements Serializable {
/**
* Return a {@link ResolvableType} for the specified {@link Type}.
* Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
* @param type the source type or {@code null}
* @param type the source type (potentially {@code null})
* @return a {@link ResolvableType} for the specified {@link Type}
* @see #forType(Type, ResolvableType)
*/
@@ -1308,7 +1322,7 @@ public class ResolvableType implements Serializable {
* @return a {@link ResolvableType} for the specified {@link Type} and owner
* @see #forType(Type)
*/
public static ResolvableType forType(@Nullable Type type, ResolvableType owner) {
public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableType owner) {
VariableResolver variableResolver = null;
if (owner != null) {
variableResolver = owner.asVariableResolver();
@@ -1422,7 +1436,7 @@ public class ResolvableType implements Serializable {
@Override
public ResolvableType resolveVariable(TypeVariable<?> variable) {
for (int i = 0; i < this.variables.length; i++) {
if (SerializableTypeWrapper.unwrap(this.variables[i]).equals(
if (ObjectUtils.nullSafeEquals(SerializableTypeWrapper.unwrap(this.variables[i]),
SerializableTypeWrapper.unwrap(variable))) {
return this.generics[i];
}
@@ -1553,6 +1567,7 @@ 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];

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -26,7 +26,7 @@ import org.springframework.lang.Nullable;
*
* <p>Users of this interface should be careful in complex hierarchy scenarios, especially
* when the generic type signature of the class changes in sub-classes. It is always
* possible to return {@code null} to fallback on a default behaviour.
* possible to return {@code null} to fallback on a default behavior.
*
* @author Stephane Nicoll
* @since 4.2

View File

@@ -33,6 +33,7 @@ import java.lang.reflect.WildcardType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -66,6 +67,7 @@ abstract class SerializableTypeWrapper {
/**
* Return a {@link Serializable} variant of {@link Field#getGenericType()}.
*/
@Nullable
public static Type forField(Field field) {
Assert.notNull(field, "Field must not be null");
return forTypeProvider(new FieldTypeProvider(field));
@@ -75,6 +77,7 @@ abstract class SerializableTypeWrapper {
* Return a {@link Serializable} variant of
* {@link MethodParameter#getGenericParameterType()}.
*/
@Nullable
public static Type forMethodParameter(MethodParameter methodParameter) {
return forTypeProvider(new MethodParameterTypeProvider(methodParameter));
}
@@ -83,6 +86,7 @@ abstract class SerializableTypeWrapper {
* Return a {@link Serializable} variant of {@link Class#getGenericSuperclass()}.
*/
@SuppressWarnings("serial")
@Nullable
public static Type forGenericSuperclass(final Class<?> type) {
return forTypeProvider(type::getGenericSuperclass);
}
@@ -119,6 +123,7 @@ 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) {
@@ -130,26 +135,31 @@ abstract class SerializableTypeWrapper {
/**
* Return a {@link Serializable} {@link Type} backed by a {@link TypeProvider} .
*/
@Nullable
static Type forTypeProvider(final TypeProvider provider) {
Assert.notNull(provider, "Provider must not be null");
if (provider.getType() instanceof Serializable || provider.getType() == null) {
return provider.getType();
Type providedType = provider.getType();
if (providedType == null) {
return null;
}
Type cached = cache.get(provider.getType());
if (providedType instanceof Serializable) {
return providedType;
}
Type cached = cache.get(providedType);
if (cached != null) {
return cached;
}
for (Class<?> type : SUPPORTED_SERIALIZABLE_TYPES) {
if (type.isAssignableFrom(provider.getType().getClass())) {
if (type.isAssignableFrom(providedType.getClass())) {
ClassLoader classLoader = provider.getClass().getClassLoader();
Class<?>[] interfaces = new Class<?>[] {type, SerializableTypeProxy.class, Serializable.class};
InvocationHandler handler = new TypeProxyInvocationHandler(provider);
cached = (Type) Proxy.newProxyInstance(classLoader, interfaces, handler);
cache.put(provider.getType(), cached);
cache.put(providedType, cached);
return cached;
}
}
throw new IllegalArgumentException("Unsupported Type class: " + provider.getType().getClass().getName());
throw new IllegalArgumentException("Unsupported Type class: " + providedType.getClass().getName());
}
@@ -174,6 +184,7 @@ abstract class SerializableTypeWrapper {
/**
* Return the (possibly non {@link Serializable}) {@link Type}.
*/
@Nullable
Type getType();
/**
@@ -202,17 +213,18 @@ abstract class SerializableTypeWrapper {
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("equals")) {
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
if (method.getName().equals("equals") && args != null) {
Object other = args[0];
// Unwrap proxies for speed
if (other instanceof Type) {
other = unwrap((Type) other);
}
return this.provider.getType().equals(other);
return ObjectUtils.nullSafeEquals(this.provider.getType(), other);
}
else if (method.getName().equals("hashCode")) {
return this.provider.getType().hashCode();
return ObjectUtils.nullSafeHashCode(this.provider.getType());
}
else if (method.getName().equals("getTypeProvider")) {
return this.provider;
@@ -222,7 +234,7 @@ abstract class SerializableTypeWrapper {
return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1));
}
else if (Type[].class == method.getReturnType() && args == null) {
Type[] result = new Type[((Type[]) method.invoke(this.provider.getType(), args)).length];
Type[] result = new Type[((Type[]) method.invoke(this.provider.getType())).length];
for (int i = 0; i < result.length; i++) {
result[i] = forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, i));
}
@@ -296,20 +308,13 @@ abstract class SerializableTypeWrapper {
private transient MethodParameter methodParameter;
public MethodParameterTypeProvider(MethodParameter methodParameter) {
if (methodParameter.getMethod() != null) {
this.methodName = methodParameter.getMethod().getName();
this.parameterTypes = methodParameter.getMethod().getParameterTypes();
}
else {
this.methodName = null;
this.parameterTypes = methodParameter.getConstructor().getParameterTypes();
}
this.methodName = (methodParameter.getMethod() != null ? methodParameter.getMethod().getName() : null);
this.parameterTypes = methodParameter.getExecutable().getParameterTypes();
this.declaringClass = methodParameter.getDeclaringClass();
this.parameterIndex = methodParameter.getParameterIndex();
this.methodParameter = methodParameter;
}
@Override
public Type getType() {
return this.methodParameter.getGenericParameterType();
@@ -385,6 +390,9 @@ abstract class SerializableTypeWrapper {
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
inputStream.defaultReadObject();
this.method = ReflectionUtils.findMethod(this.declaringClass, this.methodName);
if (this.method == null) {
throw new IllegalStateException("Cannot find method on deserialization: " + this.methodName);
}
if (this.method.getReturnType() != Type.class && this.method.getReturnType() != Type[].class) {
throw new IllegalStateException(
"Invalid return type on deserialized method - needs to be Type or Type[]: " + this.method);

View File

@@ -121,6 +121,7 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor<S> implements Anno
* {@linkplain #getSource source} that corresponds to the supplied
* attribute method.
*/
@Nullable
protected abstract Object getRawAttributeValue(Method attributeMethod);
/**
@@ -128,6 +129,7 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor<S> implements Anno
* {@linkplain #getSource source} that corresponds to the supplied
* attribute name.
*/
@Nullable
protected abstract Object getRawAttributeValue(String attributeName);
}

View File

@@ -21,6 +21,7 @@ import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
@@ -117,6 +118,7 @@ public class AnnotatedElementUtils {
return new AnnotatedElement() {
@Override
@SuppressWarnings("unchecked")
@Nullable
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
for (Annotation ann : annotations) {
if (ann.annotationType() == annotationClass) {
@@ -168,11 +170,10 @@ public class AnnotatedElementUtils {
* @param annotationName the fully qualified class name of the annotation
* type on which to find meta-annotations
* @return the names of all meta-annotations present on the annotation,
* or {@code null} if not found
* or an empty set if none found
* @see #getMetaAnnotationTypes(AnnotatedElement, Class)
* @see #hasMetaAnnotationTypes
*/
@Nullable
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationName) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.hasLength(annotationName, "'annotationName' must not be null or empty");
@@ -180,9 +181,9 @@ public class AnnotatedElementUtils {
return getMetaAnnotationTypes(element, AnnotationUtils.getAnnotation(element, annotationName));
}
private static Set<String> getMetaAnnotationTypes(AnnotatedElement element, Annotation composed) {
private static Set<String> getMetaAnnotationTypes(AnnotatedElement element, @Nullable Annotation composed) {
if (composed == null) {
return null;
return Collections.emptySet();
}
try {
@@ -195,7 +196,7 @@ public class AnnotatedElementUtils {
return CONTINUE;
}
}, new HashSet<>(), 1);
return (!types.isEmpty() ? types : null);
return types;
}
catch (Throwable ex) {
AnnotationUtils.rethrowAnnotationConfigurationException(ex);
@@ -844,7 +845,8 @@ public class AnnotatedElementUtils {
* @return the result of the processor, potentially {@code null}
*/
@Nullable
private static <T> T searchWithGetSemantics(AnnotatedElement element, @Nullable Class<? extends Annotation> annotationType,
private static <T> T searchWithGetSemantics(AnnotatedElement element,
@Nullable Class<? extends Annotation> annotationType,
@Nullable String annotationName, Processor<T> processor) {
return searchWithGetSemantics(element, annotationType, annotationName, null, processor);
@@ -865,8 +867,9 @@ public class AnnotatedElementUtils {
* @since 4.3
*/
@Nullable
private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
@Nullable String annotationName, @Nullable Class<? extends Annotation> containerType, Processor<T> processor) {
private static <T> T searchWithGetSemantics(AnnotatedElement element,
@Nullable Class<? extends Annotation> annotationType, @Nullable String annotationName,
@Nullable Class<? extends Annotation> containerType, Processor<T> processor) {
try {
return searchWithGetSemantics(element, annotationType, annotationName, containerType, processor,
@@ -896,8 +899,9 @@ public class AnnotatedElementUtils {
* @return the result of the processor, potentially {@code null}
*/
@Nullable
private static <T> T searchWithGetSemantics(AnnotatedElement element, @Nullable Class<? extends Annotation> annotationType,
@Nullable String annotationName, @Nullable Class<? extends Annotation> containerType, Processor<T> processor,
private static <T> T searchWithGetSemantics(AnnotatedElement element,
@Nullable Class<? extends Annotation> annotationType, @Nullable String annotationName,
@Nullable Class<? extends Annotation> containerType, Processor<T> processor,
Set<AnnotatedElement> visited, int metaDepth) {
Assert.notNull(element, "AnnotatedElement must not be null");
@@ -960,9 +964,9 @@ public class AnnotatedElementUtils {
*/
@Nullable
private static <T> T searchWithGetSemanticsInAnnotations(@Nullable AnnotatedElement element,
List<Annotation> annotations, Class<? extends Annotation> annotationType, String annotationName,
@Nullable Class<? extends Annotation> containerType, Processor<T> processor, Set<AnnotatedElement> visited,
int metaDepth) {
List<Annotation> annotations, @Nullable Class<? extends Annotation> annotationType,
@Nullable String annotationName, @Nullable Class<? extends Annotation> containerType,
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
// Search in annotations
for (Annotation annotation : annotations) {
@@ -1029,7 +1033,8 @@ public class AnnotatedElementUtils {
* @since 4.2
*/
@Nullable
private static <T> T searchWithFindSemantics(AnnotatedElement element, @Nullable Class<? extends Annotation> annotationType,
private static <T> T searchWithFindSemantics(AnnotatedElement element,
@Nullable Class<? extends Annotation> annotationType,
@Nullable String annotationName, Processor<T> processor) {
return searchWithFindSemantics(element, annotationType, annotationName, null, processor);
@@ -1050,8 +1055,9 @@ public class AnnotatedElementUtils {
* @since 4.3
*/
@Nullable
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
@Nullable String annotationName, @Nullable Class<? extends Annotation> containerType, Processor<T> processor) {
private static <T> T searchWithFindSemantics(AnnotatedElement element,
@Nullable Class<? extends Annotation> annotationType, @Nullable String annotationName,
@Nullable Class<? extends Annotation> containerType, Processor<T> processor) {
if (containerType != null && !processor.aggregates()) {
throw new IllegalArgumentException(
@@ -1087,8 +1093,9 @@ public class AnnotatedElementUtils {
* @since 4.2
*/
@Nullable
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
String annotationName, @Nullable Class<? extends Annotation> containerType, Processor<T> processor,
private static <T> T searchWithFindSemantics(AnnotatedElement element,
@Nullable Class<? extends Annotation> annotationType, @Nullable String annotationName,
@Nullable Class<? extends Annotation> containerType, Processor<T> processor,
Set<AnnotatedElement> visited, int metaDepth) {
Assert.notNull(element, "AnnotatedElement must not be null");
@@ -1260,11 +1267,14 @@ public class AnnotatedElementUtils {
* @since 4.3
*/
@SuppressWarnings("unchecked")
private static <A extends Annotation> A[] getRawAnnotationsFromContainer(AnnotatedElement element,
Annotation container) {
private static <A extends Annotation> A[] getRawAnnotationsFromContainer(
@Nullable AnnotatedElement element, Annotation container) {
try {
return (A[]) AnnotationUtils.getValue(container);
A[] value = (A[]) AnnotationUtils.getValue(container);
if (value != null) {
return value;
}
}
catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(element, ex);
@@ -1597,7 +1607,7 @@ public class AnnotatedElementUtils {
}
}
private void overrideAttributes(AnnotatedElement element, Annotation annotation,
private void overrideAttributes(@Nullable AnnotatedElement element, Annotation annotation,
AnnotationAttributes attributes, String sourceAttributeName, List<String> targetAttributeNames) {
Object adaptedValue = getAdaptedValue(element, annotation, sourceAttributeName);
@@ -1607,13 +1617,16 @@ public class AnnotatedElementUtils {
}
}
private void overrideAttribute(AnnotatedElement element, Annotation annotation, AnnotationAttributes attributes,
String sourceAttributeName, String targetAttributeName) {
private void overrideAttribute(@Nullable AnnotatedElement element, Annotation annotation,
AnnotationAttributes attributes, String sourceAttributeName, String targetAttributeName) {
attributes.put(targetAttributeName, getAdaptedValue(element, annotation, sourceAttributeName));
}
private Object getAdaptedValue(AnnotatedElement element, Annotation annotation, String sourceAttributeName) {
@Nullable
private Object getAdaptedValue(
@Nullable AnnotatedElement element, Annotation annotation, String sourceAttributeName) {
Object value = AnnotationUtils.getValue(annotation, sourceAttributeName);
return AnnotationUtils.adaptValue(element, value, this.classValuesAsString, this.nestedAnnotationsAsMap);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -60,6 +60,7 @@ interface AnnotationAttributeExtractor<S> {
* supported by this extractor
* @return the value of the annotation attribute
*/
@Nullable
Object getAttributeValue(Method attributeMethod);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -50,7 +50,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
private final Class<? extends Annotation> annotationType;
private final String displayName;
final String displayName;
boolean validated = false;
@@ -128,7 +128,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
}
@SuppressWarnings("unchecked")
private static Class<? extends Annotation> getAnnotationType(String annotationType, ClassLoader classLoader) {
@Nullable
private static Class<? extends Annotation> getAnnotationType(String annotationType, @Nullable ClassLoader classLoader) {
if (classLoader != null) {
try {
return (Class<? extends Annotation>) classLoader.loadClass(annotationType);
@@ -142,8 +143,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
/**
* Get the type of annotation represented by this
* {@code AnnotationAttributes} instance.
* Get the type of annotation represented by this {@code AnnotationAttributes}.
* @return the annotation type, or {@code null} if unknown
* @since 4.2
*/
@@ -153,10 +153,9 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
}
/**
* Get the value stored under the specified {@code attributeName} as a
* string.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* Get the value stored under the specified {@code attributeName} as a string.
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -171,8 +170,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* <p>If the value stored under the specified {@code attributeName} is
* a string, it will be wrapped in a single-element array before
* returning it.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -182,10 +181,9 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
}
/**
* Get the value stored under the specified {@code attributeName} as a
* boolean.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* Get the value stored under the specified {@code attributeName} as a boolean.
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -195,10 +193,9 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
}
/**
* Get the value stored under the specified {@code attributeName} as a
* number.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* Get the value stored under the specified {@code attributeName} as a number.
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -209,10 +206,9 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
}
/**
* Get the value stored under the specified {@code attributeName} as an
* enum.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* Get the value stored under the specified {@code attributeName} as an enum.
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -223,10 +219,9 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
}
/**
* Get the value stored under the specified {@code attributeName} as a
* class.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* Get the value stored under the specified {@code attributeName} as a class.
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -239,11 +234,10 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
/**
* Get the value stored under the specified {@code attributeName} as an
* array of classes.
* <p>If the value stored under the specified {@code attributeName} is
* a class, it will be wrapped in a single-element array before
* returning it.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* <p>If the value stored under the specified {@code attributeName} is a class,
* it will be wrapped in a single-element array before returning it.
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -257,8 +251,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* {@code attributeName}.
* <p>Note: if you expect an actual annotation, invoke
* {@link #getAnnotation(String, Class)} instead.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the {@code AnnotationAttributes}
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -270,8 +264,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
/**
* Get the annotation of type {@code annotationType} stored under the
* specified {@code attributeName}.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @param annotationType the expected annotation type; never {@code null}
* @return the annotation
* @throws IllegalArgumentException if the attribute does not exist or
@@ -290,8 +284,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* a single-element array before returning it.
* <p>Note: if you expect an actual array of annotations, invoke
* {@link #getAnnotationArray(String, Class)} instead.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @return the array of {@code AnnotationAttributes}
* @throws IllegalArgumentException if the attribute does not exist or
* if it is not of the expected type
@@ -306,8 +300,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* <p>If the value stored under the specified {@code attributeName} is
* an {@code Annotation}, it will be wrapped in a single-element array
* before returning it.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @param annotationType the expected annotation type; never {@code null}
* @return the annotation array
* @throws IllegalArgumentException if the attribute does not exist or
@@ -328,8 +322,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* component type of the expected array type, the single element will be
* wrapped in a single-element array of the appropriate type before
* returning it.
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param attributeName the name of the attribute to get;
* never {@code null} or empty
* @param expectedType the expected type; never {@code null}
* @return the value
* @throws IllegalArgumentException if the attribute does not exist or
@@ -428,7 +422,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* to the {@link #AnnotationAttributes(Map)} constructor.
* @param map original source of annotation attribute <em>key-value</em> pairs
*/
public static AnnotationAttributes fromMap(Map<String, Object> map) {
@Nullable
public static AnnotationAttributes fromMap(@Nullable Map<String, Object> map) {
if (map == null) {
return null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -81,7 +81,7 @@ public class AnnotationAwareOrderComparator extends OrderComparator {
return ann.value();
}
}
else if (obj != null) {
else {
order = OrderUtils.getOrder(obj.getClass());
if (order == null && obj instanceof DecoratingProxy) {
order = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
@@ -98,15 +98,12 @@ public class AnnotationAwareOrderComparator extends OrderComparator {
* multiple matches but only one object to be returned.
*/
public Integer getPriority(Object obj) {
Integer priority = null;
if (obj instanceof Class) {
priority = OrderUtils.getPriority((Class<?>) obj);
return OrderUtils.getPriority((Class<?>) obj);
}
else if (obj != null) {
priority = OrderUtils.getPriority(obj.getClass());
if (priority == null && obj instanceof DecoratingProxy) {
priority = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
}
Integer priority = OrderUtils.getPriority(obj.getClass());
if (priority == null && obj instanceof DecoratingProxy) {
priority = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
}
return priority;
}

View File

@@ -191,7 +191,7 @@ public abstract class AnnotationUtils {
}
}
}
return synthesizeAnnotation(annotation, annotatedElement);
return (annotation != null ? synthesizeAnnotation(annotation, annotatedElement) : null);
}
catch (Throwable ex) {
handleIntrospectionFailure(annotatedElement, ex);
@@ -231,7 +231,7 @@ public abstract class AnnotationUtils {
* @see AnnotatedElement#getAnnotations()
*/
@Nullable
public static Annotation[] getAnnotations(@Nullable AnnotatedElement annotatedElement) {
public static Annotation[] getAnnotations(AnnotatedElement annotatedElement) {
try {
return synthesizeAnnotationArray(annotatedElement.getAnnotations(), annotatedElement);
}
@@ -473,14 +473,11 @@ public abstract class AnnotationUtils {
@Nullable
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
Assert.notNull(annotatedElement, "AnnotatedElement must not be null");
if (annotationType == null) {
return null;
}
// Do NOT store result in the findAnnotationCache since doing so could break
// findAnnotation(Class, Class) and findAnnotation(Method, Class).
A ann = findAnnotation(annotatedElement, annotationType, new HashSet<>());
return synthesizeAnnotation(ann, annotatedElement);
return (ann != null ? synthesizeAnnotation(ann, annotatedElement) : null);
}
/**
@@ -536,9 +533,6 @@ public abstract class AnnotationUtils {
@Nullable
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
Assert.notNull(method, "Method must not be null");
if (annotationType == null) {
return null;
}
AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
A result = (A) findAnnotationCache.get(cacheKey);
@@ -579,6 +573,7 @@ public abstract class AnnotationUtils {
return result;
}
@Nullable
private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class<?>... ifcs) {
A annotation = null;
for (Class<?> iface : ifcs) {
@@ -660,10 +655,6 @@ public abstract class AnnotationUtils {
@Nullable
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, boolean synthesize) {
Assert.notNull(clazz, "Class must not be null");
if (annotationType == null) {
return null;
}
AnnotationCacheKey cacheKey = new AnnotationCacheKey(clazz, annotationType);
A result = (A) findAnnotationCache.get(cacheKey);
if (result == null) {
@@ -857,7 +848,7 @@ public abstract class AnnotationUtils {
* @since 4.2.1
*/
public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annotationType,
Class<? extends Annotation> metaAnnotationType) {
@Nullable Class<? extends Annotation> metaAnnotationType) {
Assert.notNull(annotationType, "Annotation type must not be null");
if (metaAnnotationType == null) {
@@ -883,7 +874,7 @@ public abstract class AnnotationUtils {
* @param annotation the annotation to check
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
*/
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
public static boolean isInJavaLangAnnotationPackage(@Nullable Annotation annotation) {
return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType()));
}
@@ -894,7 +885,7 @@ public abstract class AnnotationUtils {
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
* @since 4.3.8
*/
static boolean isInJavaLangAnnotationPackage(Class<? extends Annotation> annotationType) {
static boolean isInJavaLangAnnotationPackage(@Nullable Class<? extends Annotation> annotationType) {
return (annotationType != null && isInJavaLangAnnotationPackage(annotationType.getName()));
}
@@ -905,7 +896,7 @@ public abstract class AnnotationUtils {
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
* @since 4.2
*/
public static boolean isInJavaLangAnnotationPackage(String annotationType) {
public static boolean isInJavaLangAnnotationPackage(@Nullable String annotationType) {
return (annotationType != null && annotationType.startsWith("java.lang.annotation"));
}
@@ -1010,7 +1001,7 @@ public abstract class AnnotationUtils {
(Object) annotatedElement, annotation, classValuesAsString, nestedAnnotationsAsMap);
}
private static AnnotationAttributes getAnnotationAttributes(Object annotatedElement,
private static AnnotationAttributes getAnnotationAttributes(@Nullable Object annotatedElement,
Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
AnnotationAttributes attributes =
@@ -1091,8 +1082,9 @@ public abstract class AnnotationUtils {
* {@code Annotation} instances
* @return the adapted value, or the original value if no adaptation is needed
*/
static Object adaptValue(@Nullable Object annotatedElement, Object value, boolean classValuesAsString,
boolean nestedAnnotationsAsMap) {
@Nullable
static Object adaptValue(@Nullable Object annotatedElement, @Nullable Object value,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
if (classValuesAsString) {
if (value instanceof Class) {
@@ -1215,9 +1207,8 @@ public abstract class AnnotationUtils {
* @see #getDefaultValue(Class, String)
*/
static void postProcessAnnotationAttributes(@Nullable Object annotatedElement,
AnnotationAttributes attributes, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
@Nullable AnnotationAttributes attributes, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
// Abort?
if (attributes == null) {
return;
}
@@ -1256,7 +1247,7 @@ public abstract class AnnotationUtils {
throw new AnnotationConfigurationException(String.format(
"In AnnotationAttributes for annotation [%s] declared on %s, " +
"attribute '%s' and its alias '%s' are declared with values of [%s] and [%s], " +
"but only one is permitted.", annotationType.getName(), elementAsString,
"but only one is permitted.", attributes.displayName, elementAsString,
attributeName, aliasedAttributeName, ObjectUtils.nullSafeToString(value),
ObjectUtils.nullSafeToString(aliasedValue)));
}
@@ -1319,7 +1310,7 @@ public abstract class AnnotationUtils {
*/
@Nullable
public static Object getValue(Annotation annotation, String attributeName) {
if (annotation == null || !StringUtils.hasText(attributeName)) {
if (!StringUtils.hasText(attributeName)) {
return null;
}
try {
@@ -1359,9 +1350,6 @@ public abstract class AnnotationUtils {
*/
@Nullable
public static Object getDefaultValue(Annotation annotation, String attributeName) {
if (annotation == null) {
return null;
}
return getDefaultValue(annotation.annotationType(), attributeName);
}
@@ -1387,7 +1375,7 @@ public abstract class AnnotationUtils {
*/
@Nullable
public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {
if (annotationType == null || !StringUtils.hasText(attributeName)) {
if (!StringUtils.hasText(attributeName)) {
return null;
}
try {
@@ -1413,8 +1401,7 @@ public abstract class AnnotationUtils {
* @since 4.2
* @see #synthesizeAnnotation(Annotation, AnnotatedElement)
*/
@Nullable
static <A extends Annotation> A synthesizeAnnotation(@Nullable A annotation) {
static <A extends Annotation> A synthesizeAnnotation(A annotation) {
return synthesizeAnnotation(annotation, null);
}
@@ -1435,16 +1422,14 @@ public abstract class AnnotationUtils {
* @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
* @see #synthesizeAnnotation(Class)
*/
@Nullable
public static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable AnnotatedElement annotatedElement) {
public static <A extends Annotation> A synthesizeAnnotation(
A annotation, @Nullable AnnotatedElement annotatedElement) {
return synthesizeAnnotation(annotation, (Object) annotatedElement);
}
@SuppressWarnings("unchecked")
static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) {
if (annotation == null) {
return null;
}
if (annotation instanceof SynthesizedAnnotation) {
return annotation;
}
@@ -1496,7 +1481,7 @@ public abstract class AnnotationUtils {
*/
@SuppressWarnings("unchecked")
@Nullable
public static <A extends Annotation> A synthesizeAnnotation(Map<String, Object> attributes,
public static <A extends Annotation> A synthesizeAnnotation(@Nullable Map<String, Object> attributes,
Class<A> annotationType, @Nullable AnnotatedElement annotatedElement) {
Assert.notNull(annotationType, "'annotationType' must not be null");
@@ -1548,10 +1533,8 @@ public abstract class AnnotationUtils {
* @see #synthesizeAnnotation(Annotation, AnnotatedElement)
* @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
*/
static Annotation[] synthesizeAnnotationArray(Annotation[] annotations, @Nullable Object annotatedElement) {
if (annotations == null) {
return null;
}
static Annotation[] synthesizeAnnotationArray(
Annotation[] annotations, @Nullable Object annotatedElement) {
Annotation[] synthesized = (Annotation[]) Array.newInstance(
annotations.getClass().getComponentType(), annotations.length);
@@ -1612,7 +1595,7 @@ public abstract class AnnotationUtils {
* @return a map containing attribute aliases (never {@code null})
* @since 4.2
*/
static Map<String, List<String>> getAttributeAliasMap(Class<? extends Annotation> annotationType) {
static Map<String, List<String>> getAttributeAliasMap(@Nullable Class<? extends Annotation> annotationType) {
if (annotationType == null) {
return Collections.emptyMap();
}
@@ -1796,7 +1779,7 @@ public abstract class AnnotationUtils {
* @return {@code true} if the method is an attribute method
* @since 4.2
*/
static boolean isAttributeMethod(Method method) {
static boolean isAttributeMethod(@Nullable Method method) {
return (method != null && method.getParameterCount() == 0 && method.getReturnType() != void.class);
}
@@ -1806,7 +1789,7 @@ public abstract class AnnotationUtils {
* @see Annotation#annotationType()
* @since 4.2
*/
static boolean isAnnotationTypeMethod(Method method) {
static boolean isAnnotationTypeMethod(@Nullable Method method) {
return (method != null && method.getName().equals("annotationType") && method.getParameterCount() == 0);
}
@@ -1852,7 +1835,7 @@ public abstract class AnnotationUtils {
* @param ex the exception that we encountered
* @see #rethrowAnnotationConfigurationException
*/
static void handleIntrospectionFailure(AnnotatedElement element, Throwable ex) {
static void handleIntrospectionFailure(@Nullable AnnotatedElement element, Throwable ex) {
rethrowAnnotationConfigurationException(ex);
Log loggerToUse = logger;
@@ -1934,7 +1917,9 @@ public abstract class AnnotationUtils {
private final Set<A> result = new LinkedHashSet<>();
AnnotationCollector(Class<A> annotationType, Class<? extends Annotation> containerAnnotationType, boolean declaredMode) {
AnnotationCollector(Class<A> annotationType,
@Nullable Class<? extends Annotation> containerAnnotationType, boolean declaredMode) {
this.annotationType = annotationType;
this.containerAnnotationType = (containerAnnotationType != null ? containerAnnotationType :
resolveContainerAnnotationType(annotationType));
@@ -1974,8 +1959,11 @@ public abstract class AnnotationUtils {
private List<A> getValue(AnnotatedElement element, Annotation annotation) {
try {
List<A> synthesizedAnnotations = new ArrayList<>();
for (A anno : (A[]) AnnotationUtils.getValue(annotation)) {
synthesizedAnnotations.add(synthesizeAnnotation(anno, element));
A[] value = (A[]) AnnotationUtils.getValue(annotation);
if (value != null) {
for (A anno : value) {
synthesizedAnnotations.add(synthesizeAnnotation(anno, element));
}
}
return synthesizedAnnotations;
}
@@ -2251,7 +2239,6 @@ public abstract class AnnotationUtils {
* @throws AnnotationConfigurationException if invalid configuration of
* {@code @AliasFor} is detected
*/
@Nullable
private String getAliasedAttributeName(AliasFor aliasFor, Method attribute) {
String attributeName = aliasFor.attribute();
String value = aliasFor.value();

View File

@@ -56,7 +56,7 @@ class DefaultAnnotationAttributeExtractor extends AbstractAliasAwareAnnotationAt
@Override
protected Object getRawAttributeValue(String attributeName) {
Method attributeMethod = ReflectionUtils.findMethod(getAnnotationType(), attributeName);
return getRawAttributeValue(attributeMethod);
return (attributeMethod != null ? getRawAttributeValue(attributeMethod) : null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -48,15 +48,17 @@ public abstract class OrderUtils {
/**
* Return the order on the specified {@code type}.
* Return the order on the specified {@code type}, or the specified
* default value if none can be found.
* <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}.
* @param type the type to handle
* @return the order value, or {@code null} if none can be found
* @return the priority value, or the specified default order if none can be found
* @since 5.0
* @see #getPriority(Class)
*/
@Nullable
public static Integer getOrder(Class<?> type) {
return getOrder(type, null);
public static int getOrder(Class<?> type, int defaultOrder) {
Integer order = getOrder(type);
return (order != null ? order : defaultOrder);
}
/**
@@ -67,7 +69,21 @@ public abstract class OrderUtils {
* @return the priority value, or the specified default order if none can be found
* @see #getPriority(Class)
*/
public static Integer getOrder(Class<?> type, Integer defaultOrder) {
@Nullable
public static Integer getOrder(Class<?> type, @Nullable Integer defaultOrder) {
Integer order = getOrder(type);
return (order != null ? order : defaultOrder);
}
/**
* Return the order on the specified {@code type}.
* <p>Takes care of {@link Order @Order} and {@code @javax.annotation.Priority}.
* @param type the type to handle
* @return the order value, or {@code null} if none can be found
* @see #getPriority(Class)
*/
@Nullable
public static Integer getOrder(Class<?> type) {
Order order = AnnotationUtils.findAnnotation(type, Order.class);
if (order != null) {
return order.value();
@@ -76,7 +92,7 @@ public abstract class OrderUtils {
if (priorityOrder != null) {
return priorityOrder;
}
return defaultOrder;
return null;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -61,6 +61,6 @@ public abstract class AbstractSingleValueEncoder<T> extends AbstractEncoder<T> {
* @return the output stream
*/
protected abstract Flux<DataBuffer> encode(T t, DataBufferFactory dataBufferFactory,
ResolvableType type, MimeType mimeType, Map<String, Object> hints);
ResolvableType type, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -48,7 +48,7 @@ public class ByteArrayDecoder extends AbstractDecoder<byte[]> {
}
@Override
public Flux<byte[]> decode(Publisher<DataBuffer> inputStream,@Nullable ResolvableType elementType,
public Flux<byte[]> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return Flux.from(inputStream).map((dataBuffer) -> {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -46,11 +46,11 @@ public class ByteBufferDecoder extends AbstractDecoder<ByteBuffer> {
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
Class<?> clazz = elementType.getRawClass();
return (super.canDecode(elementType, mimeType) && ByteBuffer.class.isAssignableFrom(clazz));
return (super.canDecode(elementType, mimeType) && clazz != null && ByteBuffer.class.isAssignableFrom(clazz));
}
@Override
public Flux<ByteBuffer> decode(Publisher<DataBuffer> inputStream, @Nullable ResolvableType elementType,
public Flux<ByteBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return Flux.from(inputStream).map((dataBuffer) -> {

View File

@@ -46,12 +46,13 @@ public class DataBufferDecoder extends AbstractDecoder<DataBuffer> {
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
Class<?> clazz = elementType.getRawClass();
return (super.canDecode(elementType, mimeType) && DataBuffer.class.isAssignableFrom(clazz));
return (super.canDecode(elementType, mimeType) && clazz != null && DataBuffer.class.isAssignableFrom(clazz));
}
@Override
public Flux<DataBuffer> decode(Publisher<DataBuffer> inputStream, @Nullable ResolvableType elementType,
public Flux<DataBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return Flux.from(inputStream);
}

View File

@@ -43,7 +43,8 @@ public interface Decoder<T> {
* Whether the decoder supports the given target element type and the MIME
* type of the source stream.
* @param elementType the target element type for the output stream
* @param mimeType the mime type associated with the stream to decode, can be {@code null} if not specified.
* @param mimeType the mime type associated with the stream to decode
* (can be {@code null} if not specified)
* @return {@code true} if supported, {@code false} otherwise
*/
boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType);
@@ -54,11 +55,11 @@ public interface Decoder<T> {
* @param elementType the expected type of elements in the output stream;
* this type must have been previously passed to the {@link #canDecode}
* method and it must have returned {@code true}.
* @param mimeType the MIME type associated with the input stream, optional
* @param mimeType the MIME type associated with the input stream (optional)
* @param hints additional information about how to do encode
* @return the output stream with decoded elements
*/
Flux<T> decode(Publisher<DataBuffer> inputStream, @Nullable ResolvableType elementType,
Flux<T> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints);
/**
@@ -67,7 +68,7 @@ public interface Decoder<T> {
* @param elementType the expected type of elements in the output stream;
* this type must have been previously passed to the {@link #canDecode}
* method and it must have returned {@code true}.
* @param mimeType the MIME type associated with the input stream, optional
* @param mimeType the MIME type associated with the input stream (optional)
* @param hints additional information about how to do encode
* @return the output stream with the decoded element
*/

View File

@@ -44,7 +44,8 @@ public interface Encoder<T> {
* Whether the encoder supports the given source element type and the MIME
* type for the output stream.
* @param elementType the type of elements in the source stream
* @param mimeType the MIME type for the output stream, can be {@code null} if not specified.
* @param mimeType the MIME type for the output stream
* (can be {@code null} if not specified)
* @return {@code true} if supported, {@code false} otherwise
*/
boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType);
@@ -59,7 +60,7 @@ public interface Encoder<T> {
* @param elementType the expected type of elements in the input stream;
* this type must have been previously passed to the {@link #canEncode}
* method and it must have returned {@code true}.
* @param mimeType the MIME type for the output stream
* @param mimeType the MIME type for the output stream (optional)
* @param hints additional information about how to do encode
* @return the output stream
*/

View File

@@ -30,6 +30,7 @@ import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
@@ -49,13 +50,13 @@ public class ResourceDecoder extends AbstractDecoder<Resource> {
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
Class<?> clazz = elementType.getRawClass();
return (InputStreamResource.class.equals(clazz) ||
clazz.isAssignableFrom(ByteArrayResource.class)) &&
super.canDecode(elementType, mimeType);
return (clazz != null &&
(InputStreamResource.class == clazz || clazz.isAssignableFrom(ByteArrayResource.class)) &&
super.canDecode(elementType, mimeType));
}
@Override
public Flux<Resource> decode(Publisher<DataBuffer> inputStream, @Nullable ResolvableType elementType,
public Flux<Resource> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
return Flux.from(decodeToMono(inputStream, elementType, mimeType, hints));
@@ -66,6 +67,7 @@ public class ResourceDecoder extends AbstractDecoder<Resource> {
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
Class<?> clazz = elementType.getRawClass();
Assert.state(clazz != null, "No resource class");
Mono<byte[]> byteArray = Flux.from(inputStream).
reduce(DataBuffer::write).
@@ -77,7 +79,7 @@ public class ResourceDecoder extends AbstractDecoder<Resource> {
});
if (InputStreamResource.class.equals(clazz)) {
if (InputStreamResource.class == clazz) {
return Mono.from(byteArray.map(ByteArrayInputStream::new).map(InputStreamResource::new));
}
else if (clazz.isAssignableFrom(ByteArrayResource.class)) {

View File

@@ -68,7 +68,7 @@ public class ResourceEncoder extends AbstractSingleValueEncoder<Resource> {
@Override
protected Flux<DataBuffer> encode(Resource resource, DataBufferFactory dataBufferFactory,
ResolvableType type, MimeType mimeType, Map<String, Object> hints) {
ResolvableType type, MimeType mimeType, @Nullable Map<String, Object> hints) {
try {
if (resource.isFile()) {

View File

@@ -77,7 +77,8 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
@Override
@SuppressWarnings("unchecked")
public Flux<DataBuffer> encode(Publisher<? extends ResourceRegion> inputStream,
DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType,
@Nullable Map<String, Object> hints) {
Assert.notNull(inputStream, "'inputStream' must not be null");
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
@@ -93,7 +94,8 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
final String boundaryString = (String) hints.get(BOUNDARY_STRING_HINT);
byte[] startBoundary = getAsciiBytes("\r\n--" + boundaryString + "\r\n");
byte[] contentType = getAsciiBytes("Content-Type: " + mimeType.toString() + "\r\n");
byte[] contentType =
(mimeType != null ? getAsciiBytes("Content-Type: " + mimeType + "\r\n") : new byte[0]);
Flux<DataBuffer> regions = Flux.from(inputStream).
concatMap(region ->

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -77,7 +77,7 @@ public class StringDecoder extends AbstractDecoder<String> {
}
@Override
public Flux<String> decode(Publisher<DataBuffer> inputStream, @Nullable ResolvableType elementType,
public Flux<String> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
Flux<DataBuffer> inputFlux = Flux.from(inputStream);
@@ -113,14 +113,14 @@ public class StringDecoder extends AbstractDecoder<String> {
return Flux.fromIterable(results);
}
private String decodeDataBuffer(DataBuffer dataBuffer, MimeType mimeType) {
private String decodeDataBuffer(DataBuffer dataBuffer, @Nullable MimeType mimeType) {
Charset charset = getCharset(mimeType);
CharBuffer charBuffer = charset.decode(dataBuffer.asByteBuffer());
DataBufferUtils.release(dataBuffer);
return charBuffer.toString();
}
private Charset getCharset(MimeType mimeType) {
private Charset getCharset(@Nullable MimeType mimeType) {
if (mimeType != null && mimeType.getCharset() != null) {
return mimeType.getCharset();
}

View File

@@ -43,7 +43,9 @@ public class ConversionFailedException extends ConversionException {
* @param value the value we tried to convert
* @param cause the cause of the conversion failure
*/
public ConversionFailedException(TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object value, Throwable cause) {
public ConversionFailedException(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType,
@Nullable Object value, Throwable cause) {
super("Failed to convert from type [" + sourceType + "] to type [" + targetType +
"] for value '" + ObjectUtils.nullSafeToString(value) + "'", cause);
this.sourceType = sourceType;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -72,6 +72,7 @@ public interface ConversionService {
* @throws ConversionException if a conversion exception occurred
* @throws IllegalArgumentException if targetType is {@code null}
*/
@Nullable
<T> T convert(@Nullable Object source, Class<T> targetType);
/**
@@ -87,6 +88,7 @@ public interface ConversionService {
* @throws IllegalArgumentException if targetType is {@code null},
* or {@code sourceType} is {@code null} but source is not {@code null}
*/
@Nullable
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.convert;
import org.springframework.lang.Nullable;
/**
* Exception to be thrown when a suitable converter could not be found
* in a given conversion service.
@@ -37,7 +39,7 @@ public class ConverterNotFoundException extends ConversionException {
* @param sourceType the source type requested to convert from
* @param targetType the target type requested to convert to
*/
public ConverterNotFoundException(TypeDescriptor sourceType, TypeDescriptor targetType) {
public ConverterNotFoundException(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
super("No converter found capable of converting from type [" + sourceType + "] to type [" + targetType + "]");
this.sourceType = sourceType;
this.targetType = targetType;
@@ -47,6 +49,7 @@ public class ConverterNotFoundException extends ConversionException {
/**
* Return the source type that was requested to convert from.
*/
@Nullable
public TypeDescriptor getSourceType() {
return this.sourceType;
}

View File

@@ -67,7 +67,9 @@ public final class Property {
this(objectType, readMethod, writeMethod, null);
}
public Property(Class<?> objectType, Method readMethod, Method writeMethod, String name) {
public Property(
Class<?> objectType, @Nullable Method readMethod, @Nullable Method writeMethod, @Nullable String name) {
this.objectType = objectType;
this.readMethod = readMethod;
this.writeMethod = writeMethod;
@@ -100,6 +102,7 @@ public final class Property {
/**
* The property getter method: e.g. {@code getFoo()}
*/
@Nullable
public Method getReadMethod() {
return this.readMethod;
}
@@ -107,6 +110,7 @@ public final class Property {
/**
* The property setter method: e.g. {@code setFoo(String)}
*/
@Nullable
public Method getWriteMethod() {
return this.writeMethod;
}
@@ -208,8 +212,8 @@ public final class Property {
}
private void addAnnotationsToMap(
Map<Class<? extends Annotation>, Annotation> annotationMap,
AnnotatedElement object) {
Map<Class<? extends Annotation>, Annotation> annotationMap, @Nullable AnnotatedElement object) {
if (object != null) {
for (Annotation annotation : object.getAnnotations()) {
annotationMap.put(annotation.annotationType(), annotation);
@@ -223,27 +227,34 @@ public final class Property {
if (!StringUtils.hasLength(name)) {
return null;
}
Field field = null;
Class<?> declaringClass = declaringClass();
Field field = ReflectionUtils.findField(declaringClass, name);
if (field == null) {
// Same lenient fallback checking as in CachedIntrospectionResults...
field = ReflectionUtils.findField(declaringClass,
name.substring(0, 1).toLowerCase() + name.substring(1));
if (declaringClass != null) {
field = ReflectionUtils.findField(declaringClass, name);
if (field == null) {
// Same lenient fallback checking as in CachedIntrospectionResults...
field = ReflectionUtils.findField(declaringClass,
name.substring(0, 1).toUpperCase() + name.substring(1));
name.substring(0, 1).toLowerCase() + name.substring(1));
if (field == null) {
field = ReflectionUtils.findField(declaringClass,
name.substring(0, 1).toUpperCase() + name.substring(1));
}
}
}
return field;
}
@Nullable
private Class<?> declaringClass() {
if (getReadMethod() != null) {
return getReadMethod().getDeclaringClass();
}
else {
else if (getWriteMethod() != null) {
return getWriteMethod().getDeclaringClass();
}
else {
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -163,7 +163,7 @@ public class TypeDescriptor implements Serializable {
* @since 4.0
*/
public Object getSource() {
return (this.resolvableType != null ? this.resolvableType.getSource() : null);
return this.resolvableType.getSource();
}
/**
@@ -282,7 +282,7 @@ public class TypeDescriptor implements Serializable {
return false;
}
if (isArray() && typeDescriptor.isArray()) {
return getElementTypeDescriptor().isAssignableTo(typeDescriptor.getElementTypeDescriptor());
return isNestedAssignable(getElementTypeDescriptor(), typeDescriptor.getElementTypeDescriptor());
}
else if (isCollection() && typeDescriptor.isCollection()) {
return isNestedAssignable(getElementTypeDescriptor(), typeDescriptor.getElementTypeDescriptor());
@@ -296,11 +296,11 @@ public class TypeDescriptor implements Serializable {
}
}
private boolean isNestedAssignable(TypeDescriptor nestedTypeDescriptor, TypeDescriptor otherNestedTypeDescriptor) {
if (nestedTypeDescriptor == null || otherNestedTypeDescriptor == null) {
return true;
}
return nestedTypeDescriptor.isAssignableTo(otherNestedTypeDescriptor);
private boolean isNestedAssignable(@Nullable TypeDescriptor nestedTypeDescriptor,
@Nullable TypeDescriptor otherNestedTypeDescriptor) {
return (nestedTypeDescriptor == null || otherNestedTypeDescriptor == null ||
nestedTypeDescriptor.isAssignableTo(otherNestedTypeDescriptor));
}
/**
@@ -355,6 +355,7 @@ public class TypeDescriptor implements Serializable {
* or array type
* @see #narrow(Object)
*/
@Nullable
public TypeDescriptor elementTypeDescriptor(Object element) {
return narrow(element, getElementTypeDescriptor());
}
@@ -397,6 +398,7 @@ public class TypeDescriptor implements Serializable {
* @throws IllegalStateException if this type is not a {@code java.util.Map}
* @see #narrow(Object)
*/
@Nullable
public TypeDescriptor getMapKeyTypeDescriptor(Object mapKey) {
return narrow(mapKey, getMapKeyTypeDescriptor());
}
@@ -433,12 +435,13 @@ public class TypeDescriptor implements Serializable {
* @throws IllegalStateException if this type is not a {@code java.util.Map}
* @see #narrow(Object)
*/
@Nullable
public TypeDescriptor getMapValueTypeDescriptor(Object mapValue) {
return narrow(mapValue, getMapValueTypeDescriptor());
}
@Nullable
private TypeDescriptor narrow(Object value, TypeDescriptor typeDescriptor) {
private TypeDescriptor narrow(@Nullable Object value, @Nullable TypeDescriptor typeDescriptor) {
if (typeDescriptor != null) {
return typeDescriptor.narrow(value);
}
@@ -559,7 +562,7 @@ public class TypeDescriptor implements Serializable {
* used to convert collection elements
* @return the collection type descriptor
*/
public static TypeDescriptor collection(Class<?> collectionType, TypeDescriptor elementTypeDescriptor) {
public static TypeDescriptor collection(Class<?> collectionType, @Nullable TypeDescriptor elementTypeDescriptor) {
Assert.notNull(collectionType, "Collection type must not be null");
if (!Collection.class.isAssignableFrom(collectionType)) {
throw new IllegalArgumentException("Collection type must be a [java.util.Collection]");
@@ -582,7 +585,9 @@ public class TypeDescriptor implements Serializable {
* @param valueTypeDescriptor the map's value type, used to convert map values
* @return the map type descriptor
*/
public static TypeDescriptor map(Class<?> mapType, TypeDescriptor keyTypeDescriptor, TypeDescriptor valueTypeDescriptor) {
public static TypeDescriptor map(Class<?> mapType, @Nullable TypeDescriptor keyTypeDescriptor,
@Nullable TypeDescriptor valueTypeDescriptor) {
Assert.notNull(mapType, "Map type must not be null");
if (!Map.class.isAssignableFrom(mapType)) {
throw new IllegalArgumentException("Map type must be a [java.util.Map]");
@@ -730,7 +735,7 @@ public class TypeDescriptor implements Serializable {
private final Annotation[] annotations;
public AnnotatedElementAdapter(Annotation[] annotations) {
public AnnotatedElementAdapter(@Nullable Annotation[] annotations) {
this.annotations = annotations;
}
@@ -745,6 +750,7 @@ public class TypeDescriptor implements Serializable {
}
@Override
@Nullable
@SuppressWarnings("unchecked")
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
for (Annotation annotation : getAnnotations()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -97,7 +97,7 @@ public interface GenericConverter {
}
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 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.
@@ -61,10 +61,13 @@ final class ArrayToArrayConverter implements ConditionalGenericConverter {
@Override
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (this.conversionService instanceof GenericConversionService &&
((GenericConversionService) this.conversionService).canBypassConvert(
sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor())) {
return source;
if (this.conversionService instanceof GenericConversionService) {
TypeDescriptor targetElement = targetType.getElementTypeDescriptor();
if (targetElement != null &&
((GenericConversionService) this.conversionService).canBypassConvert(
sourceType.getElementTypeDescriptor(), targetElement)) {
return source;
}
}
List<Object> sourceList = Arrays.asList(ObjectUtils.toObjectArray(source));
return this.helperConverter.convert(sourceList, sourceType, targetType);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -100,6 +100,7 @@ final class ByteBufferConverter implements ConditionalGenericConverter {
throw new IllegalStateException("Unexpected source/target types");
}
@Nullable
private Object convertFromByteBuffer(ByteBuffer source, TypeDescriptor targetType) {
byte[] bytes = new byte[source.remaining()];
source.get(bytes);
@@ -110,10 +111,14 @@ final class ByteBufferConverter implements ConditionalGenericConverter {
return this.conversionService.convert(bytes, BYTE_ARRAY_TYPE, targetType);
}
private Object convertToByteBuffer(Object source, TypeDescriptor sourceType) {
private Object convertToByteBuffer(@Nullable Object source, TypeDescriptor sourceType) {
byte[] bytes = (byte[]) (source instanceof byte[] ? source :
this.conversionService.convert(source, sourceType, BYTE_ARRAY_TYPE));
if (bytes == null) {
return ByteBuffer.wrap(new byte[0]);
}
ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
byteBuffer.put(bytes);

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.
@@ -25,6 +25,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Converts a Collection to an array.
@@ -35,16 +36,19 @@ import org.springframework.lang.Nullable;
* array's component type if necessary.
*
* @author Keith Donald
* @author Juergen Hoeller
* @since 3.0
*/
final class CollectionToArrayConverter implements ConditionalGenericConverter {
private final ConversionService conversionService;
public CollectionToArrayConverter(ConversionService conversionService) {
this.conversionService = conversionService;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(Collection.class, Object[].class));
@@ -52,7 +56,8 @@ final class CollectionToArrayConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return ConversionUtils.canConvertElements(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService);
return ConversionUtils.canConvertElements(sourceType.getElementTypeDescriptor(),
targetType.getElementTypeDescriptor(), this.conversionService);
}
@Override
@@ -62,10 +67,13 @@ final class CollectionToArrayConverter implements ConditionalGenericConverter {
return null;
}
Collection<?> sourceCollection = (Collection<?>) source;
Object array = Array.newInstance(targetType.getElementTypeDescriptor().getType(), sourceCollection.size());
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
Assert.state(targetElementType != null, "No target element type");
Object array = Array.newInstance(targetElementType.getType(), sourceCollection.size());
int i = 0;
for (Object sourceElement : sourceCollection) {
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor());
Object targetElement = this.conversionService.convert(sourceElement,
sourceType.elementTypeDescriptor(sourceElement), targetElementType);
Array.set(array, i++, targetElement);
}
return array;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 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.
@@ -22,6 +22,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.lang.Nullable;
/**
* A factory for common {@link org.springframework.core.convert.ConversionService}
@@ -40,7 +41,7 @@ public abstract class ConversionServiceFactory {
* {@link ConverterFactory}, or {@link GenericConverter}
* @param registry the target registry
*/
public static void registerConverters(Set<?> converters, ConverterRegistry registry) {
public static void registerConverters(@Nullable Set<?> converters, ConverterRegistry registry) {
if (converters != null) {
for (Object converter : converters) {
if (converter instanceof GenericConverter) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -20,6 +20,7 @@ import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -31,8 +32,9 @@ import org.springframework.util.Assert;
*/
abstract class ConversionUtils {
public static Object invokeConverter(GenericConverter converter, Object source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
@Nullable
public static Object invokeConverter(GenericConverter converter, @Nullable Object source,
TypeDescriptor sourceType, TypeDescriptor targetType) {
try {
return converter.convert(source, sourceType, targetType);
@@ -45,8 +47,8 @@ abstract class ConversionUtils {
}
}
public static boolean canConvertElements(TypeDescriptor sourceElementType, TypeDescriptor targetElementType,
ConversionService conversionService) {
public static boolean canConvertElements(@Nullable TypeDescriptor sourceElementType,
@Nullable TypeDescriptor targetElementType, ConversionService conversionService) {
if (targetElementType == null) {
// yes

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 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.
@@ -20,6 +20,7 @@ import java.beans.PropertyEditorSupport;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -60,6 +61,7 @@ public class ConvertingPropertyEditorAdapter extends PropertyEditorSupport {
}
@Override
@Nullable
public String getAsText() {
if (this.canConvertToString) {
return (String) this.conversionService.convert(getValue(), this.targetDescriptor, TypeDescriptor.valueOf(String.class));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -46,7 +46,6 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -118,7 +117,7 @@ public class GenericConversionService implements ConfigurableConversionService {
"ConverterFactory [" + factory.getClass().getName() + "]; does the class parameterize those types?");
}
addConverter(new ConverterFactoryAdapter(factory,
new ConvertiblePair(typeInfo[0].resolve(), typeInfo[1].resolve())));
new ConvertiblePair(typeInfo[0].resolve(Object.class), typeInfo[1].resolve(Object.class))));
}
@Override
@@ -306,25 +305,29 @@ public class GenericConversionService implements ConfigurableConversionService {
}
@Nullable
private Object handleConverterNotFound(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
private Object handleConverterNotFound(
@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
return null;
}
if (sourceType.isAssignableTo(targetType) && targetType.getObjectType().isInstance(source)) {
if ((sourceType == null || sourceType.isAssignableTo(targetType)) &&
targetType.getObjectType().isInstance(source)) {
return source;
}
throw new ConverterNotFoundException(sourceType, targetType);
}
private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, Object result) {
@Nullable
private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
if (result == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
}
return result;
}
private void assertNotPrimitiveTargetType(TypeDescriptor sourceType, TypeDescriptor targetType) {
private void assertNotPrimitiveTargetType(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType.isPrimitive()) {
throw new ConversionFailedException(sourceType, targetType, null,
new IllegalArgumentException("A null value cannot be assigned to a primitive type"));
@@ -460,14 +463,13 @@ public class GenericConversionService implements ConfigurableConversionService {
return false;
}
ConverterCacheKey otherKey = (ConverterCacheKey) other;
return (ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType) &&
ObjectUtils.nullSafeEquals(this.targetType, otherKey.targetType));
return (this.sourceType.equals(otherKey.sourceType)) &&
this.targetType.equals(otherKey.targetType);
}
@Override
public int hashCode() {
return (ObjectUtils.nullSafeHashCode(this.sourceType) * 29 +
ObjectUtils.nullSafeHashCode(this.targetType));
return (this.sourceType.hashCode() * 29 + this.targetType.hashCode());
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 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.
@@ -25,6 +25,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -68,6 +69,7 @@ final class IdToEntityConverter implements ConditionalGenericConverter {
return null;
}
Method finder = getFinder(targetType.getType());
Assert.state(finder != null, "No finder method");
Object id = this.conversionService.convert(
source, sourceType, TypeDescriptor.valueOf(finder.getParameterTypes()[0]));
return ReflectionUtils.invokeMethod(finder, source, id);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -113,14 +113,16 @@ final class MapToMapConverter implements ConditionalGenericConverter {
targetType.getMapValueTypeDescriptor(), this.conversionService);
}
private Object convertKey(Object sourceKey, TypeDescriptor sourceType, TypeDescriptor targetType) {
@Nullable
private Object convertKey(Object sourceKey, TypeDescriptor sourceType, @Nullable TypeDescriptor targetType) {
if (targetType == null) {
return sourceKey;
}
return this.conversionService.convert(sourceKey, sourceType.getMapKeyTypeDescriptor(sourceKey), targetType);
}
private Object convertValue(Object sourceValue, TypeDescriptor sourceType, TypeDescriptor targetType) {
@Nullable
private Object convertValue(Object sourceValue, TypeDescriptor sourceType, @Nullable TypeDescriptor targetType) {
if (targetType == null) {
return sourceValue;
}
@@ -134,7 +136,7 @@ final class MapToMapConverter implements ConditionalGenericConverter {
private final Object value;
public MapEntry(Object key, Object value) {
public MapEntry(@Nullable Object key, @Nullable Object value) {
this.key = key;
this.value = value;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 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.
@@ -24,12 +24,14 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Converts an Object to a single-element array containing the Object.
* Will convert the Object to the target array's component type if necessary.
*
* @author Keith Donald
* @author Juergen Hoeller
* @since 3.0
*/
final class ObjectToArrayConverter implements ConditionalGenericConverter {
@@ -49,7 +51,8 @@ final class ObjectToArrayConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return ConversionUtils.canConvertElements(sourceType, targetType.getElementTypeDescriptor(), this.conversionService);
return ConversionUtils.canConvertElements(sourceType, targetType.getElementTypeDescriptor(),
this.conversionService);
}
@Override
@@ -58,8 +61,10 @@ final class ObjectToArrayConverter implements ConditionalGenericConverter {
if (source == null) {
return null;
}
Object target = Array.newInstance(targetType.getElementTypeDescriptor().getType(), 1);
Object targetElement = this.conversionService.convert(source, sourceType, targetType.getElementTypeDescriptor());
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
Assert.state(targetElementType != null, "No target element type");
Object target = Array.newInstance(targetElementType.getType(), 1);
Object targetElement = this.conversionService.convert(source, sourceType, targetElementType);
Array.set(target, 0, targetElement);
return target;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -193,6 +193,7 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
return method;
}
@Nullable
private static Constructor<?> determineFactoryConstructor(Class<?> targetClass, Class<?> sourceClass) {
return ClassUtils.getConstructorIfAvailable(targetClass, sourceClass);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -51,7 +51,7 @@ final class ObjectToOptionalConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType.getResolvableType() != null) {
if (targetType.getResolvableType().hasGenerics()) {
return this.conversionService.canConvert(sourceType, new GenericTypeDescriptor(targetType));
}
else {
@@ -68,7 +68,7 @@ final class ObjectToOptionalConverter implements ConditionalGenericConverter {
else if (source instanceof Optional) {
return source;
}
else if (targetType.getResolvableType() != null) {
else if (targetType.getResolvableType().hasGenerics()) {
Object target = this.conversionService.convert(source, sourceType, new GenericTypeDescriptor(targetType));
return Optional.ofNullable(target);
}
@@ -82,7 +82,7 @@ final class ObjectToOptionalConverter implements ConditionalGenericConverter {
private static class GenericTypeDescriptor extends TypeDescriptor {
public GenericTypeDescriptor(TypeDescriptor typeDescriptor) {
super(typeDescriptor.getResolvableType().getGeneric(0), null, typeDescriptor.getAnnotations());
super(typeDescriptor.getResolvableType().getGeneric(), null, typeDescriptor.getAnnotations());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -17,6 +17,7 @@
package org.springframework.core.convert.support;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -71,7 +72,7 @@ class StreamConverter implements ConditionalGenericConverter {
* @param elementType the type of the stream elements
* @param targetType the type to convert to
*/
public boolean matchesFromStream(TypeDescriptor elementType, TypeDescriptor targetType) {
public boolean matchesFromStream(@Nullable TypeDescriptor elementType, TypeDescriptor targetType) {
TypeDescriptor collectionOfElement = TypeDescriptor.collection(Collection.class, elementType);
return this.conversionService.canConvert(collectionOfElement, targetType);
}
@@ -82,7 +83,7 @@ class StreamConverter implements ConditionalGenericConverter {
* @param elementType the type of the stream elements
* @param sourceType the type to convert from
*/
public boolean matchesToStream(TypeDescriptor elementType, TypeDescriptor sourceType) {
public boolean matchesToStream(@Nullable TypeDescriptor elementType, TypeDescriptor sourceType) {
TypeDescriptor collectionOfElement = TypeDescriptor.collection(Collection.class, elementType);
return this.conversionService.canConvert(sourceType, collectionOfElement);
}
@@ -100,15 +101,19 @@ class StreamConverter implements ConditionalGenericConverter {
throw new IllegalStateException("Unexpected source/target types");
}
private Object convertFromStream(Stream<?> source, TypeDescriptor streamType, TypeDescriptor targetType) {
List<Object> content = source.collect(Collectors.<Object>toList());
@Nullable
private Object convertFromStream(@Nullable Stream<?> source, TypeDescriptor streamType, TypeDescriptor targetType) {
List<Object> content = (source != null ? source.collect(Collectors.<Object>toList()) : Collections.emptyList());
TypeDescriptor listType = TypeDescriptor.collection(List.class, streamType.getElementTypeDescriptor());
return this.conversionService.convert(content, listType, targetType);
}
private Object convertToStream(Object source, TypeDescriptor sourceType, TypeDescriptor streamType) {
private Object convertToStream(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor streamType) {
TypeDescriptor targetCollection = TypeDescriptor.collection(List.class, streamType.getElementTypeDescriptor());
List<?> target = (List<?>) this.conversionService.convert(source, sourceType, targetCollection);
if (target == null) {
target = Collections.emptyList();
}
return target.stream();
}

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.
@@ -24,6 +24,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -31,16 +32,19 @@ import org.springframework.util.StringUtils;
* Only matches if String.class can be converted to the target array element type.
*
* @author Keith Donald
* @author Juergen Hoeller
* @since 3.0
*/
final class StringToArrayConverter implements ConditionalGenericConverter {
private final ConversionService conversionService;
public StringToArrayConverter(ConversionService conversionService) {
this.conversionService = conversionService;
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, Object[].class));
@@ -48,7 +52,8 @@ final class StringToArrayConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
return ConversionUtils.canConvertElements(sourceType, targetType.getElementTypeDescriptor(),
this.conversionService);
}
@Override
@@ -59,10 +64,12 @@ final class StringToArrayConverter implements ConditionalGenericConverter {
}
String string = (String) source;
String[] fields = StringUtils.commaDelimitedListToStringArray(string);
Object target = Array.newInstance(targetType.getElementTypeDescriptor().getType(), fields.length);
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
Assert.state(targetElementType != null, "No target element type");
Object target = Array.newInstance(targetElementType.getType(), fields.length);
for (int i = 0; i < fields.length; i++) {
String sourceElement = fields[i];
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetElementType);
Array.set(target, i, targetElement);
}
return target;

View File

@@ -27,7 +27,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.SpringProperties;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -52,7 +51,6 @@ import org.springframework.util.StringUtils;
* @see ConfigurableEnvironment
* @see StandardEnvironment
*/
@NonNullApi
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -39,7 +38,6 @@ import org.springframework.util.SystemPropertyUtils;
* @author Juergen Hoeller
* @since 3.1
*/
@NonNullApi
public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {
protected final Log logger = LogFactory.getLog(getClass());
@@ -131,10 +129,8 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
@Override
public void setRequiredProperties(String... requiredProperties) {
if (requiredProperties != null) {
for (String key : requiredProperties) {
this.requiredProperties.add(key);
}
for (String key : requiredProperties) {
this.requiredProperties.add(key);
}
}
@@ -247,7 +243,8 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
* @since 4.3.5
*/
@SuppressWarnings("unchecked")
protected <T> T convertValueIfNecessary(Object value, Class<T> targetType) {
@Nullable
protected <T> T convertValueIfNecessary(Object value, @Nullable Class<T> targetType) {
if (targetType == null) {
return (T) value;
}

View File

@@ -23,7 +23,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
/**
@@ -34,7 +33,6 @@ import org.springframework.lang.Nullable;
* @since 3.1
* @see SimpleCommandLineArgsParser
*/
@NonNullApi
class CommandLineArgs {
private final Map<String, List<String>> optionArgs = new HashMap<>();

View File

@@ -19,7 +19,6 @@ package org.springframework.core.env;
import java.util.Collection;
import java.util.List;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
@@ -205,7 +204,6 @@ import org.springframework.util.StringUtils;
* @see SimpleCommandLinePropertySource
* @see JOptCommandLinePropertySource
*/
@NonNullApi
public abstract class CommandLinePropertySource<T> extends EnumerablePropertySource<T> {
/** The default name given to {@link CommandLinePropertySource} instances: {@value} */

View File

@@ -23,7 +23,6 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.lang.NonNullApi;
import org.springframework.util.StringUtils;
/**
@@ -40,7 +39,6 @@ import org.springframework.util.StringUtils;
* @author Phillip Webb
* @since 3.1.1
*/
@NonNullApi
public class CompositePropertySource extends EnumerablePropertySource<Object> {
private final Set<PropertySource<?>> propertySources = new LinkedHashSet<>();

View File

@@ -18,8 +18,6 @@ package org.springframework.core.env;
import java.util.Map;
import org.springframework.lang.NonNullApi;
/**
* Configuration interface to be implemented by most if not all {@link Environment} types.
* Provides facilities for setting active and default profiles and manipulating underlying
@@ -71,7 +69,6 @@ import org.springframework.lang.NonNullApi;
* @see StandardEnvironment
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment
*/
@NonNullApi
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
/**

View File

@@ -17,7 +17,6 @@
package org.springframework.core.env;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
/**
@@ -29,7 +28,6 @@ import org.springframework.lang.Nullable;
* @author Chris Beams
* @since 3.1
*/
@NonNullApi
public interface ConfigurablePropertyResolver extends PropertyResolver {
/**

View File

@@ -16,7 +16,6 @@
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
import org.springframework.util.ObjectUtils;
/**
@@ -42,7 +41,6 @@ import org.springframework.util.ObjectUtils;
* @author Juergen Hoeller
* @since 3.1
*/
@NonNullApi
public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
public EnumerablePropertySource(String name, T source) {

View File

@@ -16,8 +16,6 @@
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
/**
* Interface representing the environment in which the current application is running.
* Models two key aspects of the application environment: <em>profiles</em> and
@@ -70,7 +68,6 @@ import org.springframework.lang.NonNullApi;
* @see org.springframework.context.ConfigurableApplicationContext#setEnvironment
* @see org.springframework.context.support.AbstractApplicationContext#createEnvironment
*/
@NonNullApi
public interface Environment extends PropertyResolver {
/**

View File

@@ -41,8 +41,7 @@ package org.springframework.core.env;
public interface EnvironmentCapable {
/**
* Return the {@link Environment} associated with this component
* (may be {@code null} or a default environment).
* Return the {@link Environment} associated with this component.
*/
Environment getEnvironment();

View File

@@ -23,8 +23,6 @@ import java.util.List;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
import org.springframework.lang.NonNullApi;
/**
* {@link CommandLinePropertySource} implementation backed by a JOpt {@link OptionSet}.
*
@@ -56,7 +54,6 @@ import org.springframework.lang.NonNullApi;
* @see joptsimple.OptionParser
* @see joptsimple.OptionSet
*/
@NonNullApi
public class JOptCommandLinePropertySource extends CommandLinePropertySource<OptionSet> {
/**

View File

@@ -18,7 +18,6 @@ package org.springframework.core.env;
import java.util.Map;
import org.springframework.lang.NonNullApi;
import org.springframework.util.StringUtils;
/**
@@ -29,7 +28,6 @@ import org.springframework.util.StringUtils;
* @since 3.1
* @see PropertiesPropertySource
*/
@NonNullApi
public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {
public MapPropertySource(String name, Map<String, Object> source) {

View File

@@ -19,8 +19,6 @@ package org.springframework.core.env;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.lang.NonNullApi;
/**
* Exception thrown when required properties are not found.
*
@@ -31,7 +29,6 @@ import org.springframework.lang.NonNullApi;
* @see org.springframework.context.support.AbstractApplicationContext#prepareRefresh()
*/
@SuppressWarnings("serial")
@NonNullApi
public class MissingRequiredPropertiesException extends IllegalStateException {
private final Set<String> missingRequiredProperties = new LinkedHashSet<>();

View File

@@ -23,7 +23,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
@@ -41,7 +40,6 @@ import org.springframework.util.StringUtils;
* @since 3.1
* @see PropertySourcesPropertyResolver
*/
@NonNullApi
public class MutablePropertySources implements PropertySources {
private final Log logger;

View File

@@ -19,8 +19,6 @@ package org.springframework.core.env;
import java.util.Map;
import java.util.Properties;
import org.springframework.lang.NonNullApi;
/**
* {@link PropertySource} implementation that extracts properties from a
* {@link java.util.Properties} object.
@@ -35,7 +33,6 @@ import org.springframework.lang.NonNullApi;
* @author Juergen Hoeller
* @since 3.1
*/
@NonNullApi
public class PropertiesPropertySource extends MapPropertySource {
@SuppressWarnings({"unchecked", "rawtypes"})

View File

@@ -16,7 +16,6 @@
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
/**
@@ -28,7 +27,6 @@ import org.springframework.lang.Nullable;
* @see Environment
* @see PropertySourcesPropertyResolver
*/
@NonNullApi
public interface PropertyResolver {
/**

View File

@@ -19,7 +19,6 @@ package org.springframework.core.env;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -57,7 +56,6 @@ import org.springframework.util.ObjectUtils;
* @see MutablePropertySources
* @see org.springframework.context.annotation.PropertySource
*/
@NonNullApi
public abstract class PropertySource<T> {
protected final Log logger = LogFactory.getLog(getClass());

View File

@@ -16,7 +16,6 @@
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
/**
@@ -25,7 +24,6 @@ import org.springframework.lang.Nullable;
* @author Chris Beams
* @since 3.1
*/
@NonNullApi
public interface PropertySources extends Iterable<PropertySource<?>> {
/**

View File

@@ -16,7 +16,6 @@
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
/**
@@ -30,7 +29,6 @@ import org.springframework.lang.Nullable;
* @see PropertySources
* @see AbstractEnvironment
*/
@NonNullApi
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
private final PropertySources propertySources;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -21,7 +21,7 @@ import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
/**
* Read-only {@code Map<String, String>} implementation that is backed by system
@@ -37,7 +37,6 @@ import org.springframework.lang.NonNullApi;
* @author Chris Beams
* @since 3.0
*/
@NonNullApi
abstract class ReadOnlySystemAttributesMap implements Map<String, String> {
@Override
@@ -50,13 +49,13 @@ abstract class ReadOnlySystemAttributesMap implements Map<String, String> {
* @throws IllegalArgumentException if given key is non-String
*/
@Override
@Nullable
public String get(Object key) {
if (!(key instanceof String)) {
throw new IllegalArgumentException(
"Type of key [" + (key != null ? key.getClass().getName() : "null") +
"] must be java.lang.String.");
"Type of key [" + key.getClass().getName() + "] must be java.lang.String");
}
return this.getSystemAttribute((String) key);
return getSystemAttribute((String) key);
}
@Override
@@ -68,6 +67,7 @@ abstract class ReadOnlySystemAttributesMap implements Map<String, String> {
* Template method that returns the underlying system attribute.
* <p>Implementations typically call {@link System#getProperty(String)} or {@link System#getenv(String)} here.
*/
@Nullable
protected abstract String getSystemAttribute(String attributeName);

View File

@@ -16,8 +16,6 @@
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
/**
* Parses a {@code String[]} of command line arguments in order to populate a
* {@link CommandLineArgs} object.
@@ -51,7 +49,6 @@ import org.springframework.lang.NonNullApi;
* @author Chris Beams
* @since 3.1
*/
@NonNullApi
class SimpleCommandLineArgsParser {
/**

View File

@@ -18,8 +18,6 @@ package org.springframework.core.env;
import java.util.List;
import org.springframework.lang.NonNullApi;
/**
* {@link CommandLinePropertySource} implementation backed by a simple String array.
*
@@ -77,7 +75,6 @@ import org.springframework.lang.NonNullApi;
* @see CommandLinePropertySource
* @see JOptCommandLinePropertySource
*/
@NonNullApi
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {
/**

View File

@@ -16,8 +16,6 @@
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;
/**
* {@link Environment} implementation suitable for use in 'standard' (i.e. non-web)
* applications.
@@ -53,7 +51,6 @@ import org.springframework.lang.NonNullApi;
* @see SystemEnvironmentPropertySource
* @see org.springframework.web.context.support.StandardServletEnvironment
*/
@NonNullApi
public class StandardEnvironment extends AbstractEnvironment {
/** System environment property source name: {@value} */

View File

@@ -18,7 +18,6 @@ package org.springframework.core.env;
import java.util.Map;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -64,7 +63,6 @@ import org.springframework.util.Assert;
* @see AbstractEnvironment#getSystemEnvironment()
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
*/
@NonNullApi
public class SystemEnvironmentPropertySource extends MapPropertySource {
/**

View File

@@ -2,4 +2,7 @@
* Spring's environment abstraction consisting of bean definition
* profile and hierarchical property source support.
*/
@NonNullApi
package org.springframework.core.env;
import org.springframework.lang.NonNullApi;

View File

@@ -144,7 +144,6 @@ public abstract class AbstractResource implements Resource {
@Override
public long contentLength() throws IOException {
InputStream is = getInputStream();
Assert.state(is != null, "Resource InputStream must not be null");
try {
long size = 0;
byte[] buf = new byte[255];

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 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.
@@ -21,6 +21,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link Resource} implementation for a given byte array.
* <p>Creates a {@link ByteArrayInputStream} for the given byte array.
@@ -57,10 +60,8 @@ public class ByteArrayResource extends AbstractResource {
* @param byteArray the byte array to wrap
* @param description where the byte array comes from
*/
public ByteArrayResource(byte[] byteArray, String description) {
if (byteArray == null) {
throw new IllegalArgumentException("Byte array must not be null");
}
public ByteArrayResource(byte[] byteArray, @Nullable String description) {
Assert.notNull(byteArray, "Byte array must not be null");
this.byteArray = byteArray;
this.description = (description != null ? description : "");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -189,7 +189,7 @@ public class DefaultResourceLoader implements ResourceLoader {
*/
protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {
public ClassPathContextResource(String path, ClassLoader classLoader) {
public ClassPathContextResource(String path, @Nullable ClassLoader classLoader) {
super(path, classLoader);
}

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.
@@ -20,6 +20,8 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.lang.Nullable;
/**
* Simple {@link Resource} implementation that holds a resource description
* but does not point to an actually readable resource.
@@ -39,7 +41,7 @@ public class DescriptiveResource extends AbstractResource {
* Create a new DescriptiveResource.
* @param description the resource description
*/
public DescriptiveResource(String description) {
public DescriptiveResource(@Nullable String description) {
this.description = (description != null ? description : "");
}

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.
@@ -48,7 +48,7 @@ public class FileSystemResourceLoader extends DefaultResourceLoader {
*/
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
if (path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemContextResource(path);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -19,6 +19,7 @@ package org.springframework.core.io;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -63,7 +64,7 @@ public class InputStreamResource extends AbstractResource {
* @param inputStream the InputStream to use
* @param description where the InputStream comes from
*/
public InputStreamResource(InputStream inputStream, String description) {
public InputStreamResource(InputStream inputStream, @Nullable String description) {
Assert.notNull(inputStream, "InputStream must not be null");
this.inputStream = inputStream;
this.description = (description != null ? description : "");

View File

@@ -70,7 +70,7 @@ public class ResourceEditor extends PropertyEditorSupport {
* @param resourceLoader the {@code ResourceLoader} to use
* @param propertyResolver the {@code PropertyResolver} to use
*/
public ResourceEditor(ResourceLoader resourceLoader, PropertyResolver propertyResolver) {
public ResourceEditor(ResourceLoader resourceLoader, @Nullable PropertyResolver propertyResolver) {
this(resourceLoader, propertyResolver, true);
}
@@ -82,7 +82,7 @@ public class ResourceEditor extends PropertyEditorSupport {
* @param ignoreUnresolvablePlaceholders whether to ignore unresolvable placeholders
* if no corresponding property could be found in the given {@code propertyResolver}
*/
public ResourceEditor(ResourceLoader resourceLoader, PropertyResolver propertyResolver,
public ResourceEditor(ResourceLoader resourceLoader, @Nullable PropertyResolver propertyResolver,
boolean ignoreUnresolvablePlaceholders) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -71,8 +71,7 @@ public interface ResourceLoader {
* <p>Clients which need to access the ClassLoader directly can do so
* in a uniform manner with the ResourceLoader, rather than relying
* on the thread context ClassLoader.
* @return the ClassLoader (only {@code null} if even the system
* ClassLoader isn't accessible)
* @return the ClassLoader
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
*/
@Nullable

View File

@@ -26,6 +26,7 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
@@ -121,7 +122,7 @@ public class UrlResource extends AbstractFileResolvingResource {
* @throws MalformedURLException if the given URL specification is not valid
* @see java.net.URI#URI(String, String, String)
*/
public UrlResource(String protocol, String location, String fragment) throws MalformedURLException {
public UrlResource(String protocol, String location, @Nullable String fragment) throws MalformedURLException {
try {
this.uri = new URI(protocol, location, fragment);
this.url = this.uri.toURL();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 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.
@@ -183,10 +183,12 @@ public abstract class VfsUtils {
return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url);
}
protected static Object doGetVisitorAttribute() {
@Nullable
protected static Object doGetVisitorAttributes() {
return ReflectionUtils.getField(VISITOR_ATTRIBUTES_FIELD_RECURSE, null);
}
@Nullable
protected static String doGetPath(Object resource) {
return (String) ReflectionUtils.invokeMethod(VIRTUAL_FILE_METHOD_GET_PATH_NAME, resource);
}

View File

@@ -32,6 +32,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;
import reactor.core.publisher.SynchronousSink;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -122,7 +123,7 @@ public abstract class DataBufferUtils {
});
}
private static void closeChannel(Channel channel) {
private static void closeChannel(@Nullable Channel channel) {
try {
if (channel != null) {
channel.close();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -19,6 +19,7 @@ package org.springframework.core.io.support;
import java.io.IOException;
import org.springframework.core.env.PropertySource;
import org.springframework.lang.Nullable;
/**
* The default implementation for {@link PropertySourceFactory},
@@ -32,7 +33,7 @@ import org.springframework.core.env.PropertySource;
public class DefaultPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
return (name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 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.
@@ -66,7 +66,7 @@ public class EncodedResource implements InputStreamSource {
* @param resource the {@code Resource} to hold (never {@code null})
* @param encoding the encoding to use for reading from the resource
*/
public EncodedResource(Resource resource, String encoding) {
public EncodedResource(Resource resource, @Nullable String encoding) {
this(resource, encoding, null);
}
@@ -76,11 +76,11 @@ public class EncodedResource implements InputStreamSource {
* @param resource the {@code Resource} to hold (never {@code null})
* @param charset the {@code Charset} to use for reading from the resource
*/
public EncodedResource(Resource resource, Charset charset) {
public EncodedResource(Resource resource, @Nullable Charset charset) {
this(resource, null, charset);
}
private EncodedResource(Resource resource, String encoding, Charset charset) {
private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
super();
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;

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.
@@ -63,7 +63,7 @@ public class LocalizedResourceHelper {
* Set the separator to use inbetween file name parts.
* Default is an underscore ("_").
*/
public void setSeparator(String separator) {
public void setSeparator(@Nullable String separator) {
this.separator = (separator != null ? separator : DEFAULT_SEPARATOR);
}

View File

@@ -363,7 +363,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
* @param result the set of resources to add jar roots to
* @since 4.1.1
*/
protected void addAllClassLoaderJarRoots(ClassLoader classLoader, Set<Resource> result) {
protected void addAllClassLoaderJarRoots(@Nullable ClassLoader classLoader, Set<Resource> result) {
if (classLoader instanceof URLClassLoader) {
try {
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
@@ -462,18 +462,21 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
Set<Resource> result = new LinkedHashSet<>(16);
for (Resource rootDirResource : rootDirResources) {
rootDirResource = resolveRootDirResource(rootDirResource);
URL rootDirURL = rootDirResource.getURL();
URL rootDirUrl = rootDirResource.getURL();
if (equinoxResolveMethod != null) {
if (rootDirURL.getProtocol().startsWith("bundle")) {
rootDirURL = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirURL);
rootDirResource = new UrlResource(rootDirURL);
if (rootDirUrl.getProtocol().startsWith("bundle")) {
URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
if (resolvedUrl != null) {
rootDirUrl = resolvedUrl;
}
rootDirResource = new UrlResource(rootDirUrl);
}
}
if (rootDirURL.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirURL, subPattern, getPathMatcher()));
if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
}
else if (ResourceUtils.isJarURL(rootDirURL) || isJarResource(rootDirResource)) {
result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirURL, subPattern));
else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
}
else {
result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
@@ -851,8 +854,9 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
}
}
@Nullable
public Object getAttributes() {
return VfsPatternUtils.getVisitorAttribute();
return VfsPatternUtils.getVisitorAttributes();
}
public Set<Resource> getResources() {

Some files were not shown because too many files have changed in this diff Show More