diff options
author | Emmanuel Bourg <ebourg@apache.org> | 2018-04-08 23:27:38 +0200 |
---|---|---|
committer | Emmanuel Bourg <ebourg@apache.org> | 2018-04-08 23:27:38 +0200 |
commit | e9dafb5ce16aa2faa4fee1019417cc0a7456af57 (patch) | |
tree | c38471d22f5c367a45673724d3a6571d5daf591b /spring-core/src | |
parent | 6dc3d6835b664af0d21e774a5342b90d4417f628 (diff) |
New upstream version 4.3.15
Diffstat (limited to 'spring-core/src')
47 files changed, 762 insertions, 608 deletions
diff --git a/spring-core/src/main/java/org/springframework/asm/ClassWriter.java b/spring-core/src/main/java/org/springframework/asm/ClassWriter.java index a024937d..513b2e5d 100644 --- a/spring-core/src/main/java/org/springframework/asm/ClassWriter.java +++ b/spring-core/src/main/java/org/springframework/asm/ClassWriter.java @@ -1699,7 +1699,7 @@ public class ClassWriter extends ClassVisitor { */ private Item addType(final Item item) { ++typeCount; - Item result = new Item(typeCount, key); + Item result = new Item(typeCount, item); put(result); if (typeTable == null) { typeTable = new Item[16]; diff --git a/spring-core/src/main/java/org/springframework/core/AttributeAccessorSupport.java b/spring-core/src/main/java/org/springframework/core/AttributeAccessorSupport.java index dbbe1aff..ba321bf7 100644 --- a/spring-core/src/main/java/org/springframework/core/AttributeAccessorSupport.java +++ b/spring-core/src/main/java/org/springframework/core/AttributeAccessorSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2018 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,7 @@ import java.util.LinkedHashMap; import java.util.Map; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Support class for {@link AttributeAccessor AttributeAccessors}, providing @@ -70,7 +71,7 @@ public abstract class AttributeAccessorSupport implements AttributeAccessor, Ser @Override public String[] attributeNames() { - return this.attributes.keySet().toArray(new String[this.attributes.size()]); + return StringUtils.toStringArray(this.attributes.keySet()); } diff --git a/spring-core/src/main/java/org/springframework/core/MethodParameter.java b/spring-core/src/main/java/org/springframework/core/MethodParameter.java index 5bc50d97..7267704e 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,7 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.HashMap; @@ -47,6 +48,8 @@ import org.springframework.util.ClassUtils; */ public class MethodParameter { + private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; + private static final Class<?> javaUtilOptionalClass; static { @@ -482,17 +485,27 @@ public class MethodParameter { * Return the annotations associated with the specific method/constructor parameter. */ public Annotation[] getParameterAnnotations() { - if (this.parameterAnnotations == null) { + Annotation[] paramAnns = this.parameterAnnotations; + if (paramAnns == null) { Annotation[][] annotationArray = (this.method != null ? this.method.getParameterAnnotations() : this.constructor.getParameterAnnotations()); - if (this.parameterIndex >= 0 && this.parameterIndex < annotationArray.length) { - this.parameterAnnotations = adaptAnnotationArray(annotationArray[this.parameterIndex]); + int index = this.parameterIndex; + if (this.constructor != null && this.constructor.getDeclaringClass().isMemberClass() && + !Modifier.isStatic(this.constructor.getDeclaringClass().getModifiers()) && + annotationArray.length == this.constructor.getParameterTypes().length - 1) { + // Bug in javac in JDK <9: annotation array excludes enclosing instance parameter + // for inner classes, so access it with the actual parameter index lowered by 1 + index = this.parameterIndex - 1; + } + if (index >= 0 && index < annotationArray.length) { + paramAnns = adaptAnnotationArray(annotationArray[index]); } else { - this.parameterAnnotations = new Annotation[0]; + paramAnns = EMPTY_ANNOTATION_ARRAY; } + this.parameterAnnotations = paramAnns; } - return this.parameterAnnotations; + return paramAnns; } /** diff --git a/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java b/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java index 7f6d807f..5ed2e1ad 100644 --- a/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java +++ b/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,14 +24,14 @@ import org.springframework.util.Assert; /** * The purpose of this class is to enable capturing and passing a generic * {@link Type}. In order to capture the generic type and retain it at runtime, - * you need to create a subclass as follows: + * you need to create a subclass (ideally as anonymous inline class) as follows: * * <pre class="code"> * ParameterizedTypeReference<List<String>> typeRef = new ParameterizedTypeReference<List<String>>() {}; * </pre> * - * <p>The resulting {@code typeReference} instance can then be used to obtain a - * {@link Type} instance that carries parameterized type information. + * <p>The resulting {@code typeRef} instance can then be used to obtain a {@link Type} + * instance that carries the captured parameterized type information at runtime. * For more information on "super type tokens" see the link to Neal Gafter's blog post. * * @author Arjen Poutsma @@ -49,8 +49,9 @@ public abstract class ParameterizedTypeReference<T> { Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass(); Assert.isInstanceOf(ParameterizedType.class, type, "Type must be a parameterized type"); ParameterizedType parameterizedType = (ParameterizedType) type; - Assert.isTrue(parameterizedType.getActualTypeArguments().length == 1, "Number of type arguments must be 1"); - this.type = parameterizedType.getActualTypeArguments()[0]; + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + Assert.isTrue(actualTypeArguments.length == 1, "Number of type arguments must be 1"); + this.type = actualTypeArguments[0]; } private ParameterizedTypeReference(Type type) { diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java index 35e6da4d..155236d5 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -34,6 +34,7 @@ import java.util.Map; import org.springframework.core.SerializableTypeWrapper.FieldTypeProvider; import org.springframework.core.SerializableTypeWrapper.MethodParameterTypeProvider; import org.springframework.core.SerializableTypeWrapper.TypeProvider; +import org.springframework.lang.UsesJava8; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; @@ -355,7 +356,7 @@ public class ResolvableType implements Serializable { if (this == NONE) { return false; } - return (((this.type instanceof Class && ((Class<?>) this.type).isArray())) || + return ((this.type instanceof Class && ((Class<?>) this.type).isArray()) || this.type instanceof GenericArrayType || resolveType().isArray()); } @@ -1427,8 +1428,9 @@ 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( - SerializableTypeWrapper.unwrap(variable))) { + TypeVariable<?> v1 = SerializableTypeWrapper.unwrap(this.variables[i]); + TypeVariable<?> v2 = SerializableTypeWrapper.unwrap(variable); + if (ObjectUtils.nullSafeEquals(v1, v2)) { return this.generics[i]; } } @@ -1453,6 +1455,23 @@ public class ResolvableType implements Serializable { this.typeArguments = typeArguments; } + @Override // on Java 8 + @UsesJava8 + public String getTypeName() { + StringBuilder result = new StringBuilder(this.rawType.getTypeName()); + if (this.typeArguments.length > 0) { + result.append('<'); + for (int i = 0; i < this.typeArguments.length; i++) { + if (i > 0) { + result.append(", "); + } + result.append(this.typeArguments[i].getTypeName()); + } + result.append('>'); + } + return result.toString(); + } + @Override public Type getOwnerType() { return null; diff --git a/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java b/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java index 16c73b5f..fcfbd0f6 100644 --- a/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java +++ b/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -45,23 +45,25 @@ public class SimpleAliasRegistry implements AliasRegistry { public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); - if (alias.equals(name)) { - this.aliasMap.remove(alias); - } - else { - String registeredName = this.aliasMap.get(alias); - if (registeredName != null) { - if (registeredName.equals(name)) { - // An existing alias - no need to re-register - return; - } - if (!allowAliasOverriding()) { - throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + - name + "': It is already registered for name '" + registeredName + "'."); + synchronized (this.aliasMap) { + if (alias.equals(name)) { + this.aliasMap.remove(alias); + } + else { + String registeredName = this.aliasMap.get(alias); + if (registeredName != null) { + if (registeredName.equals(name)) { + // An existing alias - no need to re-register + return; + } + if (!allowAliasOverriding()) { + throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + + name + "': It is already registered for name '" + registeredName + "'."); + } } + checkForAliasCircle(name, alias); + this.aliasMap.put(alias, name); } - checkForAliasCircle(name, alias); - this.aliasMap.put(alias, name); } } @@ -92,9 +94,11 @@ public class SimpleAliasRegistry implements AliasRegistry { @Override public void removeAlias(String alias) { - String name = this.aliasMap.remove(alias); - if (name == null) { - throw new IllegalStateException("No alias '" + alias + "' registered"); + synchronized (this.aliasMap) { + String name = this.aliasMap.remove(alias); + if (name == null) { + throw new IllegalStateException("No alias '" + alias + "' registered"); + } } } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java index d83747fe..75f42f02 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -29,6 +29,7 @@ import java.util.Set; import org.springframework.core.BridgeMethodResolver; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -59,10 +60,9 @@ import org.springframework.util.MultiValueMap; * individual method for details on which search algorithm is used. * * <p><strong>Get semantics</strong> are limited to searching for annotations - * that are either <em>present</em> on an {@code AnnotatedElement} (i.e., - * declared locally or {@linkplain java.lang.annotation.Inherited inherited}) - * or declared within the annotation hierarchy <em>above</em> the - * {@code AnnotatedElement}. + * that are either <em>present</em> on an {@code AnnotatedElement} (i.e. declared + * locally or {@linkplain java.lang.annotation.Inherited inherited}) or declared + * within the annotation hierarchy <em>above</em> the {@code AnnotatedElement}. * * <p><strong>Find semantics</strong> are much more exhaustive, providing * <em>get semantics</em> plus support for the following: @@ -76,14 +76,13 @@ import org.springframework.util.MultiValueMap; * </ul> * * <h3>Support for {@code @Inherited}</h3> - * <p>Methods following <em>get semantics</em> will honor the contract of - * Java's {@link java.lang.annotation.Inherited @Inherited} annotation except - * that locally declared annotations (including custom composed annotations) - * will be favored over inherited annotations. In contrast, methods following - * <em>find semantics</em> will completely ignore the presence of - * {@code @Inherited} since the <em>find</em> search algorithm manually - * traverses type and method hierarchies and thereby implicitly supports - * annotation inheritance without the need for {@code @Inherited}. + * <p>Methods following <em>get semantics</em> will honor the contract of Java's + * {@link java.lang.annotation.Inherited @Inherited} annotation except that locally + * declared annotations (including custom composed annotations) will be favored over + * inherited annotations. In contrast, methods following <em>find semantics</em> + * will completely ignore the presence of {@code @Inherited} since the <em>find</em> + * search algorithm manually traverses type and method hierarchies and thereby + * implicitly supports annotation inheritance without a need for {@code @Inherited}. * * @author Phillip Webb * @author Juergen Hoeller @@ -242,7 +241,6 @@ public class AnnotatedElementUtils { return Boolean.TRUE.equals( searchWithGetSemantics(element, annotationType, annotationName, new SimpleAnnotationProcessor<Boolean>() { - @Override public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) { return (metaDepth > 0 ? Boolean.TRUE : CONTINUE); @@ -272,7 +270,6 @@ public class AnnotatedElementUtils { if (element.isAnnotationPresent(annotationType)) { return true; } - return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, null, alwaysTrueAnnotationProcessor)); } @@ -617,7 +614,6 @@ public class AnnotatedElementUtils { if (element.isAnnotationPresent(annotationType)) { return true; } - return Boolean.TRUE.equals(searchWithFindSemantics(element, annotationType, null, alwaysTrueAnnotationProcessor)); } @@ -873,10 +869,10 @@ public class AnnotatedElementUtils { * @param annotationName the fully qualified class name of the annotation * type to find (as an alternative to {@code annotationType}) * @param processor the processor to delegate to - * @return the result of the processor, potentially {@code null} + * @return the result of the processor (potentially {@code null}) */ - private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType, - String annotationName, Processor<T> processor) { + private static <T> T searchWithGetSemantics(AnnotatedElement element, + Class<? extends Annotation> annotationType, String annotationName, Processor<T> processor) { return searchWithGetSemantics(element, annotationType, annotationName, null, processor); } @@ -892,15 +888,16 @@ public class AnnotatedElementUtils { * @param containerType the type of the container that holds repeatable * annotations, or {@code null} if the annotation is not repeatable * @param processor the processor to delegate to - * @return the result of the processor, potentially {@code null} + * @return the result of the processor (potentially {@code null}) * @since 4.3 */ - private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType, - String annotationName, Class<? extends Annotation> containerType, Processor<T> processor) { + private static <T> T searchWithGetSemantics(AnnotatedElement element, + Class<? extends Annotation> annotationType, String annotationName, + Class<? extends Annotation> containerType, Processor<T> processor) { try { - return searchWithGetSemantics(element, annotationType, annotationName, containerType, processor, - new HashSet<AnnotatedElement>(), 0); + return searchWithGetSemantics(element, annotationType, annotationName, + containerType, processor, new HashSet<AnnotatedElement>(), 0); } catch (Throwable ex) { AnnotationUtils.rethrowAnnotationConfigurationException(ex); @@ -923,10 +920,11 @@ public class AnnotatedElementUtils { * @param processor the processor to delegate to * @param visited the set of annotated elements that have already been visited * @param metaDepth the meta-depth of the annotation - * @return the result of the processor, potentially {@code null} + * @return the result of the processor (potentially {@code null}) */ - private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType, - String annotationName, Class<? extends Annotation> containerType, Processor<T> processor, + private static <T> T searchWithGetSemantics(AnnotatedElement element, + Class<? extends Annotation> annotationType, String annotationName, + Class<? extends Annotation> containerType, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) { Assert.notNull(element, "AnnotatedElement must not be null"); @@ -941,7 +939,7 @@ public class AnnotatedElementUtils { return result; } - if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new + if (element instanceof Class) { // otherwise getAnnotations does not return anything new List<Annotation> inheritedAnnotations = new ArrayList<Annotation>(); for (Annotation annotation : element.getAnnotations()) { if (!declaredAnnotations.contains(annotation)) { @@ -984,13 +982,13 @@ public class AnnotatedElementUtils { * @param processor the processor to delegate to * @param visited the set of annotated elements that have already been visited * @param metaDepth the meta-depth of the annotation - * @return the result of the processor, potentially {@code null} + * @return the result of the processor (potentially {@code null}) * @since 4.2 */ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement element, - List<Annotation> annotations, Class<? extends Annotation> annotationType, String annotationName, - Class<? extends Annotation> containerType, Processor<T> processor, Set<AnnotatedElement> visited, - int metaDepth) { + List<Annotation> annotations, Class<? extends Annotation> annotationType, + String annotationName, Class<? extends Annotation> containerType, + Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) { // Search in annotations for (Annotation annotation : annotations) { @@ -1053,10 +1051,11 @@ public class AnnotatedElementUtils { * @param annotationName the fully qualified class name of the annotation * type to find (as an alternative to {@code annotationType}) * @param processor the processor to delegate to - * @return the result of the processor, potentially {@code null} + * @return the result of the processor (potentially {@code null}) * @since 4.2 */ - private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType, + private static <T> T searchWithFindSemantics(AnnotatedElement element, + Class<? extends Annotation> annotationType, String annotationName, Processor<T> processor) { return searchWithFindSemantics(element, annotationType, annotationName, null, processor); @@ -1073,11 +1072,12 @@ public class AnnotatedElementUtils { * @param containerType the type of the container that holds repeatable * annotations, or {@code null} if the annotation is not repeatable * @param processor the processor to delegate to - * @return the result of the processor, potentially {@code null} + * @return the result of the processor (potentially {@code null}) * @since 4.3 */ - private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType, - String annotationName, Class<? extends Annotation> containerType, Processor<T> processor) { + private static <T> T searchWithFindSemantics(AnnotatedElement element, + Class<? extends Annotation> annotationType, String annotationName, + Class<? extends Annotation> containerType, Processor<T> processor) { if (containerType != null && !processor.aggregates()) { throw new IllegalArgumentException( @@ -1085,8 +1085,8 @@ public class AnnotatedElementUtils { } try { - return searchWithFindSemantics( - element, annotationType, annotationName, containerType, processor, new HashSet<AnnotatedElement>(), 0); + return searchWithFindSemantics(element, annotationType, annotationName, + containerType, processor, new HashSet<AnnotatedElement>(), 0); } catch (Throwable ex) { AnnotationUtils.rethrowAnnotationConfigurationException(ex); @@ -1109,7 +1109,7 @@ public class AnnotatedElementUtils { * @param processor the processor to delegate to * @param visited the set of annotated elements that have already been visited * @param metaDepth the meta-depth of the annotation - * @return the result of the processor, potentially {@code null} + * @return the result of the processor (potentially {@code null}) * @since 4.2 */ private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType, @@ -1122,79 +1122,86 @@ public class AnnotatedElementUtils { try { // Locally declared annotations (ignoring @Inherited) Annotation[] annotations = element.getDeclaredAnnotations(); - List<T> aggregatedResults = (processor.aggregates() ? new ArrayList<T>() : null); - - // Search in local annotations - for (Annotation annotation : annotations) { - Class<? extends Annotation> currentAnnotationType = annotation.annotationType(); - if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) { - if (currentAnnotationType == annotationType || - currentAnnotationType.getName().equals(annotationName) || - processor.alwaysProcesses()) { - T result = processor.process(element, annotation, metaDepth); - if (result != null) { - if (processor.aggregates() && metaDepth == 0) { - aggregatedResults.add(result); - } - else { - return result; + if (annotations.length > 0) { + List<T> aggregatedResults = (processor.aggregates() ? new ArrayList<T>() : null); + + // Search in local annotations + for (Annotation annotation : annotations) { + Class<? extends Annotation> currentAnnotationType = annotation.annotationType(); + if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) { + if (currentAnnotationType == annotationType || + currentAnnotationType.getName().equals(annotationName) || + processor.alwaysProcesses()) { + T result = processor.process(element, annotation, metaDepth); + if (result != null) { + if (aggregatedResults != null && metaDepth == 0) { + aggregatedResults.add(result); + } + else { + return result; + } } } - } - // Repeatable annotations in container? - else if (currentAnnotationType == containerType) { - for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) { - T result = processor.process(element, contained, metaDepth); - if (result != null) { - // No need to post-process since repeatable annotations within a - // container cannot be composed annotations. - aggregatedResults.add(result); + // Repeatable annotations in container? + else if (currentAnnotationType == containerType) { + for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) { + T result = processor.process(element, contained, metaDepth); + if (aggregatedResults != null && result != null) { + // No need to post-process since repeatable annotations within a + // container cannot be composed annotations. + aggregatedResults.add(result); + } } } } } - } - // Search in meta annotations on local annotations - for (Annotation annotation : annotations) { - Class<? extends Annotation> currentAnnotationType = annotation.annotationType(); - if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) { - T result = searchWithFindSemantics(currentAnnotationType, annotationType, annotationName, - containerType, processor, visited, metaDepth + 1); - if (result != null) { - processor.postProcess(currentAnnotationType, annotation, result); - if (processor.aggregates() && metaDepth == 0) { - aggregatedResults.add(result); - } - else { - return result; + // Recursively search in meta-annotations + for (Annotation annotation : annotations) { + Class<? extends Annotation> currentAnnotationType = annotation.annotationType(); + if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) { + T result = searchWithFindSemantics(currentAnnotationType, annotationType, annotationName, + containerType, processor, visited, metaDepth + 1); + if (result != null) { + processor.postProcess(currentAnnotationType, annotation, result); + if (aggregatedResults != null && metaDepth == 0) { + aggregatedResults.add(result); + } + else { + return result; + } } } } - } - if (processor.aggregates()) { - // Prepend to support top-down ordering within class hierarchies - processor.getAggregatedResults().addAll(0, aggregatedResults); + if (!CollectionUtils.isEmpty(aggregatedResults)) { + // Prepend to support top-down ordering within class hierarchies + processor.getAggregatedResults().addAll(0, aggregatedResults); + } } if (element instanceof Method) { Method method = (Method) element; + T result; // Search on possibly bridged method Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method); - T result = searchWithFindSemantics(resolvedMethod, annotationType, annotationName, containerType, - processor, visited, metaDepth); - if (result != null) { - return result; + if (resolvedMethod != method) { + result = searchWithFindSemantics(resolvedMethod, annotationType, annotationName, + containerType, processor, visited, metaDepth); + if (result != null) { + return result; + } } // Search on methods in interfaces declared locally Class<?>[] ifcs = method.getDeclaringClass().getInterfaces(); - result = searchOnInterfaces(method, annotationType, annotationName, containerType, processor, - visited, metaDepth, ifcs); - if (result != null) { - return result; + if (ifcs.length > 0) { + result = searchOnInterfaces(method, annotationType, annotationName, + containerType, processor, visited, metaDepth, ifcs); + if (result != null) { + return result; + } } // Search on methods in class hierarchy and interface hierarchy @@ -1204,7 +1211,6 @@ public class AnnotatedElementUtils { if (clazz == null || Object.class == clazz) { break; } - try { Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod); @@ -1217,10 +1223,9 @@ public class AnnotatedElementUtils { catch (NoSuchMethodException ex) { // No equivalent method found } - // Search on interfaces declared on superclass - result = searchOnInterfaces(method, annotationType, annotationName, containerType, processor, - visited, metaDepth, clazz.getInterfaces()); + result = searchOnInterfaces(method, annotationType, annotationName, + containerType, processor, visited, metaDepth, clazz.getInterfaces()); if (result != null) { return result; } @@ -1231,8 +1236,8 @@ public class AnnotatedElementUtils { // Search on interfaces for (Class<?> ifc : clazz.getInterfaces()) { - T result = searchWithFindSemantics(ifc, annotationType, annotationName, containerType, - processor, visited, metaDepth); + T result = searchWithFindSemantics(ifc, annotationType, annotationName, + containerType, processor, visited, metaDepth); if (result != null) { return result; } @@ -1241,8 +1246,8 @@ public class AnnotatedElementUtils { // Search on superclass Class<?> superclass = clazz.getSuperclass(); if (superclass != null && Object.class != superclass) { - T result = searchWithFindSemantics(superclass, annotationType, annotationName, containerType, - processor, visited, metaDepth); + T result = searchWithFindSemantics(superclass, annotationType, annotationName, + containerType, processor, visited, metaDepth); if (result != null) { return result; } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 5e19db46..971568da 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -145,17 +145,17 @@ public abstract class AnnotationUtils { * <p>Note that this method supports only a single level of meta-annotations. * For support for arbitrary levels of meta-annotations, use one of the * {@code find*()} methods instead. - * @param ann the Annotation to check + * @param annotation the Annotation to check * @param annotationType the annotation type to look for, both locally and as a meta-annotation * @return the first matching annotation, or {@code null} if not found * @since 4.0 */ @SuppressWarnings("unchecked") - public static <A extends Annotation> A getAnnotation(Annotation ann, Class<A> annotationType) { - if (annotationType.isInstance(ann)) { - return synthesizeAnnotation((A) ann); + public static <A extends Annotation> A getAnnotation(Annotation annotation, Class<A> annotationType) { + if (annotationType.isInstance(annotation)) { + return synthesizeAnnotation((A) annotation); } - Class<? extends Annotation> annotatedElement = ann.annotationType(); + Class<? extends Annotation> annotatedElement = annotation.annotationType(); try { return synthesizeAnnotation(annotatedElement.getAnnotation(annotationType), annotatedElement); } @@ -568,7 +568,6 @@ public abstract class AnnotationUtils { if (result == null) { Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method); result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType); - if (result == null) { result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces()); } @@ -603,10 +602,10 @@ public abstract class AnnotationUtils { private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class<?>... ifcs) { A annotation = null; - for (Class<?> iface : ifcs) { - if (isInterfaceWithAnnotatedMethods(iface)) { + for (Class<?> ifc : ifcs) { + if (isInterfaceWithAnnotatedMethods(ifc)) { try { - Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes()); + Method equivalentMethod = ifc.getMethod(method.getName(), method.getParameterTypes()); annotation = getAnnotation(equivalentMethod, annotationType); } catch (NoSuchMethodException ex) { @@ -620,13 +619,13 @@ public abstract class AnnotationUtils { return annotation; } - static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) { - Boolean found = annotatedInterfaceCache.get(iface); + static boolean isInterfaceWithAnnotatedMethods(Class<?> ifc) { + Boolean found = annotatedInterfaceCache.get(ifc); if (found != null) { return found; } found = Boolean.FALSE; - for (Method ifcMethod : iface.getMethods()) { + for (Method ifcMethod : ifc.getMethods()) { try { if (ifcMethod.getAnnotations().length > 0) { found = Boolean.TRUE; @@ -637,7 +636,7 @@ public abstract class AnnotationUtils { handleIntrospectionFailure(ifcMethod, ex); } } - annotatedInterfaceCache.put(iface, found); + annotatedInterfaceCache.put(ifc, found); return found; } @@ -933,6 +932,32 @@ public abstract class AnnotationUtils { } /** + * Check the declared attributes of the given annotation, in particular covering + * Google App Engine's late arrival of {@code TypeNotPresentExceptionProxy} for + * {@code Class} values (instead of early {@code Class.getAnnotations() failure}. + * <p>This method not failing indicates that {@link #getAnnotationAttributes(Annotation)} + * won't failure either (when attempted later on). + * @param annotation the annotation to validate + * @throws IllegalStateException if a declared {@code Class} attribute could not be read + * @since 4.3.15 + * @see Class#getAnnotations() + * @see #getAnnotationAttributes(Annotation) + */ + public static void validateAnnotation(Annotation annotation) { + for (Method method : getAttributeMethods(annotation.annotationType())) { + Class<?> returnType = method.getReturnType(); + if (returnType == Class.class || returnType == Class[].class) { + try { + method.invoke(annotation); + } + catch (Throwable ex) { + throw new IllegalStateException("Could not obtain annotation attribute value for " + method, ex); + } + } + } + } + + /** * Retrieve the given annotation's attributes as a {@link Map}, preserving all * attribute types. * <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} @@ -1260,15 +1285,12 @@ public abstract class AnnotationUtils { } Object value = attributes.get(attributeName); boolean valuePresent = (value != null && !(value instanceof DefaultValueHolder)); - for (String aliasedAttributeName : aliasMap.get(attributeName)) { if (valuesAlreadyReplaced.contains(aliasedAttributeName)) { continue; } - Object aliasedValue = attributes.get(aliasedAttributeName); boolean aliasPresent = (aliasedValue != null && !(aliasedValue instanceof DefaultValueHolder)); - // Something to validate or replace with an alias? if (valuePresent || aliasPresent) { if (valuePresent && aliasPresent) { @@ -1882,17 +1904,31 @@ public abstract class AnnotationUtils { if (element instanceof Class && Annotation.class.isAssignableFrom((Class<?>) element)) { // Meta-annotation or (default) value lookup on an annotation type if (loggerToUse.isDebugEnabled()) { - loggerToUse.debug("Failed to meta-introspect annotation [" + element + "]: " + ex); + loggerToUse.debug("Failed to meta-introspect annotation " + element + ": " + ex); } } else { // Direct annotation lookup on regular Class, Method, Field if (loggerToUse.isInfoEnabled()) { - loggerToUse.info("Failed to introspect annotations on [" + element + "]: " + ex); + loggerToUse.info("Failed to introspect annotations on " + element + ": " + ex); } } } + /** + * Clear the internal annotation metadata cache. + * @since 4.3.15 + */ + public static void clearCache() { + findAnnotationCache.clear(); + metaPresentCache.clear(); + annotatedInterfaceCache.clear(); + synthesizableCache.clear(); + attributeAliasesCache.clear(); + attributeMethodsCache.clear(); + aliasDescriptorCache.clear(); + } + /** * Cache key for the AnnotatedElement cache. diff --git a/spring-core/src/main/java/org/springframework/core/convert/Property.java b/spring-core/src/main/java/org/springframework/core/convert/Property.java index 9c6db43c..c7c1bddc 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/Property.java +++ b/spring-core/src/main/java/org/springframework/core/convert/Property.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -36,8 +36,8 @@ import org.springframework.util.StringUtils; * is not available in a number of environments (e.g. Android, Java ME), so this is * desirable for portability of Spring's core conversion facility. * - * <p>Used to build a TypeDescriptor from a property location. - * The built TypeDescriptor can then be used to convert from/to the property type. + * <p>Used to build a {@link TypeDescriptor} from a property location. The built + * {@code TypeDescriptor} can then be used to convert from/to the property type. * * @author Keith Donald * @author Phillip Webb diff --git a/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java index 593687ef..03374f75 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java +++ b/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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,12 +54,12 @@ public class TypeDescriptor implements Serializable { private static final boolean streamAvailable = ClassUtils.isPresent( "java.util.stream.Stream", TypeDescriptor.class.getClassLoader()); - private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<Class<?>, TypeDescriptor>(18); + private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<Class<?>, TypeDescriptor>(32); private static final Class<?>[] CACHED_COMMON_TYPES = { boolean.class, Boolean.class, byte.class, Byte.class, char.class, Character.class, - double.class, Double.class, int.class, Integer.class, long.class, Long.class, - float.class, Float.class, short.class, Short.class, String.class, Object.class}; + double.class, Double.class, float.class, Float.class, int.class, Integer.class, + long.class, Long.class, short.class, Short.class, String.class, Object.class}; static { for (Class<?> preCachedClass : CACHED_COMMON_TYPES) { diff --git a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java index b7ad3c42..d9e0afb6 100644 --- a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java +++ b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java @@ -65,8 +65,8 @@ class SimpleCommandLineArgsParser { String optionName; String optionValue = null; if (optionText.contains("=")) { - optionName = optionText.substring(0, optionText.indexOf("=")); - optionValue = optionText.substring(optionText.indexOf("=")+1, optionText.length()); + optionName = optionText.substring(0, optionText.indexOf('=')); + optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length()); } else { optionName = optionText; diff --git a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java index f1b1f8d7..36631a5a 100644 --- a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java +++ b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2018 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.env; import java.util.List; +import org.springframework.util.StringUtils; + /** * {@link CommandLinePropertySource} implementation backed by a simple String array. * @@ -100,7 +102,7 @@ public class SimpleCommandLinePropertySource extends CommandLinePropertySource<C */ @Override public String[] getPropertyNames() { - return source.getOptionNames().toArray(new String[source.getOptionNames().size()]); + return StringUtils.toStringArray(this.source.getOptionNames()); } @Override diff --git a/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java b/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java index d66b9a63..36c2019b 100644 --- a/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java +++ b/spring-core/src/main/java/org/springframework/core/io/VfsUtils.java @@ -46,24 +46,24 @@ public abstract class VfsUtils { private static final String VFS3_PKG = "org.jboss.vfs."; private static final String VFS_NAME = "VFS"; - private static Method VFS_METHOD_GET_ROOT_URL; - private static Method VFS_METHOD_GET_ROOT_URI; - - private static Method VIRTUAL_FILE_METHOD_EXISTS; - private static Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM; - private static Method VIRTUAL_FILE_METHOD_GET_SIZE; - private static Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED; - private static Method VIRTUAL_FILE_METHOD_TO_URL; - private static Method VIRTUAL_FILE_METHOD_TO_URI; - private static Method VIRTUAL_FILE_METHOD_GET_NAME; - private static Method VIRTUAL_FILE_METHOD_GET_PATH_NAME; - private static Method VIRTUAL_FILE_METHOD_GET_CHILD; - - protected static Class<?> VIRTUAL_FILE_VISITOR_INTERFACE; - protected static Method VIRTUAL_FILE_METHOD_VISIT; - - private static Field VISITOR_ATTRIBUTES_FIELD_RECURSE; - private static Method GET_PHYSICAL_FILE; + private static final Method VFS_METHOD_GET_ROOT_URL; + private static final Method VFS_METHOD_GET_ROOT_URI; + + private static final Method VIRTUAL_FILE_METHOD_EXISTS; + private static final Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM; + private static final Method VIRTUAL_FILE_METHOD_GET_SIZE; + private static final Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED; + private static final Method VIRTUAL_FILE_METHOD_TO_URL; + private static final Method VIRTUAL_FILE_METHOD_TO_URI; + private static final Method VIRTUAL_FILE_METHOD_GET_NAME; + private static final Method VIRTUAL_FILE_METHOD_GET_PATH_NAME; + private static final Method VIRTUAL_FILE_METHOD_GET_CHILD; + + protected static final Class<?> VIRTUAL_FILE_VISITOR_INTERFACE; + protected static final Method VIRTUAL_FILE_METHOD_VISIT; + + private static final Field VISITOR_ATTRIBUTES_FIELD_RECURSE; + private static final Method GET_PHYSICAL_FILE; static { ClassLoader loader = VfsUtils.class.getClassLoader(); diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java index f9ae32cf..131bb0a1 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java @@ -287,7 +287,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol // Generally only look for a pattern after a prefix here, // and on Tomcat only after the "*/" separator for its "war:" protocol. int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 : - locationPattern.indexOf(":") + 1); + locationPattern.indexOf(':') + 1); if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) { // a file pattern return findPathMatchingResources(locationPattern); @@ -525,7 +525,7 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol * @see #retrieveMatchingFiles */ protected String determineRootDir(String location) { - int prefixEnd = location.indexOf(":") + 1; + int prefixEnd = location.indexOf(':') + 1; int rootDirEnd = location.length(); while (rootDirEnd > prefixEnd && getPathMatcher().isPattern(location.substring(prefixEnd, rootDirEnd))) { rootDirEnd = location.lastIndexOf('/', rootDirEnd - 2) + 1; diff --git a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java index 908b54d3..fa378ed0 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -69,7 +69,7 @@ public abstract class SpringFactoriesLoader { /** * Load and instantiate the factory implementations of the given type from * {@value #FACTORIES_RESOURCE_LOCATION}, using the given class loader. - * <p>The returned factories are sorted in accordance with the {@link AnnotationAwareOrderComparator}. + * <p>The returned factories are sorted through {@link AnnotationAwareOrderComparator}. * <p>If a custom instantiation strategy is required, use {@link #loadFactoryNames} * to obtain all registered factory names. * @param factoryClass the interface or abstract class representing the factory diff --git a/spring-core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java b/spring-core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java index 393ecee6..d666e7f3 100644 --- a/spring-core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java +++ b/spring-core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2018 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,18 +24,18 @@ import org.springframework.core.task.TaskExecutor; import org.springframework.util.Assert; /** - * Adapter that takes a Spring {@link org.springframework.core.task.TaskExecutor}) + * Adapter that takes a Spring {@link org.springframework.core.task.TaskExecutor} * and exposes a full {@code java.util.concurrent.ExecutorService} for it. * * <p>This is primarily for adapting to client components that communicate via the * {@code java.util.concurrent.ExecutorService} API. It can also be used as * common ground between a local Spring {@code TaskExecutor} backend and a - * JNDI-located {@code ManagedExecutorService} in a Java EE 6 environment. + * JNDI-located {@code ManagedExecutorService} in a Java EE 7 environment. * * <p><b>NOTE:</b> This ExecutorService adapter does <em>not</em> support the * lifecycle methods in the {@code java.util.concurrent.ExecutorService} API * ("shutdown()" etc), similar to a server-wide {@code ManagedExecutorService} - * in a Java EE 6 environment. The lifecycle is always up to the backend pool, + * in a Java EE 7 environment. The lifecycle is always up to the backend pool, * with this adapter acting as an access-only proxy for that target pool. * * @author Juergen Hoeller diff --git a/spring-core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java b/spring-core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java index 2b2faa4d..9aaea290 100644 --- a/spring-core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java +++ b/spring-core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -70,7 +70,9 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter * @param considerMetaAnnotations whether to also match on meta-annotations * @param considerInterfaces whether to also match interfaces */ - public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) { + public AnnotationTypeFilter( + Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) { + super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces); this.annotationType = annotationType; this.considerMetaAnnotations = considerMetaAnnotations; @@ -99,6 +101,11 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter return false; } else if (typeName.startsWith("java")) { + if (!this.annotationType.getName().startsWith("java")) { + // Standard Java types do not have non-standard annotations on them -> + // skip any load attempt, in particular for Java language interfaces. + return false; + } try { Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader()); return ((this.considerMetaAnnotations ? AnnotationUtils.getAnnotation(clazz, this.annotationType) : diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java index 5a99de2e..89418ced 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -112,7 +112,7 @@ public abstract class ClassUtils { registerCommonClasses(entry.getKey()); } - Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(32); + Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(64); primitiveTypes.addAll(primitiveWrapperTypeMap.values()); primitiveTypes.addAll(Arrays.asList(new Class<?>[] { boolean[].class, byte[].class, char[].class, double[].class, @@ -125,9 +125,10 @@ public abstract class ClassUtils { registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class, Float[].class, Integer[].class, Long[].class, Short[].class); registerCommonClasses(Number.class, Number[].class, String.class, String[].class, - Object.class, Object[].class, Class.class, Class[].class); + Class.class, Class[].class, Object.class, Object[].class); registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class, Error.class, StackTraceElement.class, StackTraceElement[].class); + registerCommonClasses(Enum.class, Iterable.class, Cloneable.class, Comparable.class); } @@ -1064,11 +1065,12 @@ public abstract class ClassUtils { } /** - * Copy the given Collection into a Class array. - * The Collection must contain Class elements only. - * @param collection the Collection to copy - * @return the Class array ({@code null} if the passed-in - * Collection was {@code null}) + * Copy the given {@code Collection} into a {@code Class} array. + * <p>The {@code Collection} must contain {@code Class} elements only. + * @param collection the {@code Collection} to copy + * @return the {@code Class} array + * @since 3.1 + * @see StringUtils#toStringArray */ public static Class<?>[] toClassArray(Collection<Class<?>> collection) { if (collection == null) { @@ -1109,8 +1111,7 @@ public abstract class ClassUtils { * @return all interfaces that the given object implements as an array */ public static Class<?>[] getAllInterfacesForClass(Class<?> clazz, ClassLoader classLoader) { - Set<Class<?>> ifcs = getAllInterfacesForClassAsSet(clazz, classLoader); - return ifcs.toArray(new Class<?>[ifcs.size()]); + return toClassArray(getAllInterfacesForClassAsSet(clazz, classLoader)); } /** @@ -1150,12 +1151,13 @@ public abstract class ClassUtils { return Collections.<Class<?>>singleton(clazz); } Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>(); - while (clazz != null) { - Class<?>[] ifcs = clazz.getInterfaces(); + Class<?> current = clazz; + while (current != null) { + Class<?>[] ifcs = current.getInterfaces(); for (Class<?> ifc : ifcs) { interfaces.addAll(getAllInterfacesForClassAsSet(ifc, classLoader)); } - clazz = clazz.getSuperclass(); + current = current.getSuperclass(); } return interfaces; } diff --git a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java index 17127f2e..cee33acd 100644 --- a/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java +++ b/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -223,18 +223,27 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen @Override public V get(Object key) { - Reference<K, V> reference = getReference(key, Restructure.WHEN_NECESSARY); - Entry<K, V> entry = (reference != null ? reference.get() : null); + Entry<K, V> entry = getEntryIfAvailable(key); return (entry != null ? entry.getValue() : null); } @Override + public V getOrDefault(Object key, V defaultValue) { + Entry<K, V> entry = getEntryIfAvailable(key); + return (entry != null ? entry.getValue() : defaultValue); + } + + @Override public boolean containsKey(Object key) { - Reference<K, V> reference = getReference(key, Restructure.WHEN_NECESSARY); - Entry<K, V> entry = (reference != null ? reference.get() : null); + Entry<K, V> entry = getEntryIfAvailable(key); return (entry != null && ObjectUtils.nullSafeEquals(entry.getKey(), key)); } + private Entry<K, V> getEntryIfAvailable(Object key) { + Reference<K, V> reference = getReference(key, Restructure.WHEN_NECESSARY); + return (reference != null ? reference.get() : null); + } + /** * Return a {@link Reference} to the {@link Entry} for the specified {@code key}, * or {@code null} if not found. @@ -582,17 +591,18 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen } private Reference<K, V> findInChain(Reference<K, V> reference, Object key, int hash) { - while (reference != null) { - if (reference.getHash() == hash) { - Entry<K, V> entry = reference.get(); + Reference<K, V> currRef = reference; + while (currRef != null) { + if (currRef.getHash() == hash) { + Entry<K, V> entry = currRef.get(); if (entry != null) { K entryKey = entry.getKey(); - if (entryKey == key || entryKey.equals(key)) { - return reference; + if (ObjectUtils.nullSafeEquals(entryKey, key)) { + return currRef; } } } - reference = reference.getNext(); + currRef = currRef.getNext(); } return null; } diff --git a/spring-core/src/main/java/org/springframework/util/DigestUtils.java b/spring-core/src/main/java/org/springframework/util/DigestUtils.java index 36b1a583..cc782565 100644 --- a/spring-core/src/main/java/org/springframework/util/DigestUtils.java +++ b/spring-core/src/main/java/org/springframework/util/DigestUtils.java @@ -169,7 +169,7 @@ public abstract class DigestUtils { } private static char[] encodeHex(byte[] bytes) { - char chars[] = new char[32]; + char[] chars = new char[32]; for (int i = 0; i < chars.length; i = i + 2) { byte b = bytes[i / 2]; chars[i] = HEX_CHARS[(b >>> 0x4) & 0xf]; diff --git a/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java b/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java index 5e327797..886f92c0 100644 --- a/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java +++ b/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java @@ -489,6 +489,7 @@ public class FastByteArrayOutputStream extends OutputStream { * Update the message digest with the remaining bytes in this stream. * @param messageDigest The message digest to update */ + @Override public void updateMessageDigest(MessageDigest messageDigest) { updateMessageDigest(messageDigest, available()); } @@ -499,6 +500,7 @@ public class FastByteArrayOutputStream extends OutputStream { * @param messageDigest The message digest to update * @param len how many bytes to read from this stream and use to update the message digest */ + @Override public void updateMessageDigest(MessageDigest messageDigest, int len) { if (this.currentBuffer == null) { // This stream doesn't have any data in it... diff --git a/spring-core/src/main/java/org/springframework/util/MimeType.java b/spring-core/src/main/java/org/springframework/util/MimeType.java index 23ceb3e3..26afb8ef 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeType.java +++ b/spring-core/src/main/java/org/springframework/util/MimeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -29,15 +29,15 @@ import java.util.Map; import java.util.TreeSet; /** - * Represents a MIME Type, as originally defined in RFC 2046 and subsequently used in - * other Internet protocols including HTTP. + * Represents a MIME Type, as originally defined in RFC 2046 and subsequently + * used in other Internet protocols including HTTP. * * <p>This class, however, does not contain support for the q-parameters used - * in HTTP content negotiation. Those can be found in the sub-class + * in HTTP content negotiation. Those can be found in the subclass * {@code org.springframework.http.MediaType} in the {@code spring-web} module. * * <p>Consists of a {@linkplain #getType() type} and a {@linkplain #getSubtype() subtype}. - * Also has functionality to parse media types from a string using + * Also has functionality to parse MIME Type values from a {@code String} using * {@link #valueOf(String)}. For more parsing options see {@link MimeTypeUtils}. * * @author Arjen Poutsma @@ -137,7 +137,7 @@ public class MimeType implements Comparable<MimeType>, Serializable { /** * Copy-constructor that copies the type, subtype, parameters of the given {@code MimeType}, * and allows to set the specified character set. - * @param other the other media type + * @param other the other MimeType * @param charset the character set * @throws IllegalArgumentException if any of the parameters contains illegal characters * @since 4.3 @@ -149,8 +149,8 @@ public class MimeType implements Comparable<MimeType>, Serializable { /** * Copy-constructor that copies the type and subtype of the given {@code MimeType}, * and allows for different parameter. - * @param other the other media type - * @param parameters the parameters, may be {@code null} + * @param other the other MimeType + * @param parameters the parameters (may be {@code null}) * @throws IllegalArgumentException if any of the parameters contains illegal characters */ public MimeType(MimeType other, Map<String, String> parameters) { @@ -161,7 +161,7 @@ public class MimeType implements Comparable<MimeType>, Serializable { * Create a new {@code MimeType} for the given type, subtype, and parameters. * @param type the primary type * @param subtype the subtype - * @param parameters the parameters, may be {@code null} + * @param parameters the parameters (may be {@code null}) * @throws IllegalArgumentException if any of the parameters contains illegal characters */ public MimeType(String type, String subtype, Map<String, String> parameters) { @@ -227,7 +227,7 @@ public class MimeType implements Comparable<MimeType>, Serializable { if (s == null) { return null; } - return isQuotedString(s) ? s.substring(1, s.length() - 1) : s; + return (isQuotedString(s) ? s.substring(1, s.length() - 1) : s); } /** @@ -249,9 +249,9 @@ public class MimeType implements Comparable<MimeType>, Serializable { } /** - * Indicates whether this media type is concrete, i.e. whether neither the type + * Indicates whether this MIME Type is concrete, i.e. whether neither the type * nor the subtype is a wildcard character <code>*</code>. - * @return whether this media type is concrete + * @return whether this MIME Type is concrete */ public boolean isConcrete() { return !isWildcardType() && !isWildcardSubtype(); @@ -310,19 +310,19 @@ public class MimeType implements Comparable<MimeType>, Serializable { } /** - * Indicate whether this {@code MediaType} includes the given media type. + * Indicate whether this MIME Type includes the given MIME Type. * <p>For instance, {@code text/*} includes {@code text/plain} and {@code text/html}, - * and {@code application/*+xml} includes {@code application/soap+xml}, etc. This - * method is <b>not</b> symmetric. - * @param other the reference media type with which to compare - * @return {@code true} if this media type includes the given media type; + * and {@code application/*+xml} includes {@code application/soap+xml}, etc. + * This method is <b>not</b> symmetric. + * @param other the reference MIME Type with which to compare + * @return {@code true} if this MIME Type includes the given MIME Type; * {@code false} otherwise */ public boolean includes(MimeType other) { if (other == null) { return false; } - if (this.isWildcardType()) { + if (isWildcardType()) { // */* includes anything return true; } @@ -330,9 +330,9 @@ public class MimeType implements Comparable<MimeType>, Serializable { if (getSubtype().equals(other.getSubtype())) { return true; } - if (this.isWildcardSubtype()) { - // wildcard with suffix, e.g. application/*+xml - int thisPlusIdx = getSubtype().indexOf('+'); + if (isWildcardSubtype()) { + // Wildcard with suffix, e.g. application/*+xml + int thisPlusIdx = getSubtype().lastIndexOf('+'); if (thisPlusIdx == -1) { return true; } @@ -354,12 +354,12 @@ public class MimeType implements Comparable<MimeType>, Serializable { } /** - * Indicate whether this {@code MediaType} is compatible with the given media type. + * Indicate whether this MIME Type is compatible with the given MIME Type. * <p>For instance, {@code text/*} is compatible with {@code text/plain}, * {@code text/html}, and vice versa. In effect, this method is similar to * {@link #includes}, except that it <b>is</b> symmetric. - * @param other the reference media type with which to compare - * @return {@code true} if this media type is compatible with the given media type; + * @param other the reference MIME Type with which to compare + * @return {@code true} if this MIME Type is compatible with the given MIME Type; * {@code false} otherwise */ public boolean isCompatibleWith(MimeType other) { @@ -373,22 +373,18 @@ public class MimeType implements Comparable<MimeType>, Serializable { if (getSubtype().equals(other.getSubtype())) { return true; } - // wildcard with suffix? e.g. application/*+xml - if (this.isWildcardSubtype() || other.isWildcardSubtype()) { - + // Wildcard with suffix? e.g. application/*+xml + if (isWildcardSubtype() || other.isWildcardSubtype()) { int thisPlusIdx = getSubtype().indexOf('+'); int otherPlusIdx = other.getSubtype().indexOf('+'); - if (thisPlusIdx == -1 && otherPlusIdx == -1) { return true; } else if (thisPlusIdx != -1 && otherPlusIdx != -1) { String thisSubtypeNoSuffix = getSubtype().substring(0, thisPlusIdx); String otherSubtypeNoSuffix = other.getSubtype().substring(0, otherPlusIdx); - String thisSubtypeSuffix = getSubtype().substring(thisPlusIdx + 1); String otherSubtypeSuffix = other.getSubtype().substring(otherPlusIdx + 1); - if (thisSubtypeSuffix.equals(otherSubtypeSuffix) && (WILDCARD_TYPE.equals(thisSubtypeNoSuffix) || WILDCARD_TYPE.equals(otherSubtypeNoSuffix))) { return true; @@ -429,7 +425,6 @@ public class MimeType implements Comparable<MimeType>, Serializable { if (!other.parameters.containsKey(key)) { return false; } - if (PARAM_CHARSET.equals(key)) { if (!ObjectUtils.nullSafeEquals(getCharset(), other.getCharset())) { return false; @@ -475,8 +470,8 @@ public class MimeType implements Comparable<MimeType>, Serializable { } /** - * Compares this {@code MediaType} to another alphabetically. - * @param other media type to compare to + * Compares this MIME Type to another alphabetically. + * @param other the MIME Type to compare to * @see MimeTypeUtils#sortBySpecificity(List) */ @Override @@ -493,12 +488,14 @@ public class MimeType implements Comparable<MimeType>, Serializable { if (comp != 0) { return comp; } + TreeSet<String> thisAttributes = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); thisAttributes.addAll(getParameters().keySet()); TreeSet<String> otherAttributes = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); otherAttributes.addAll(other.getParameters().keySet()); Iterator<String> thisAttributesIterator = thisAttributes.iterator(); Iterator<String> otherAttributesIterator = otherAttributes.iterator(); + while (thisAttributesIterator.hasNext()) { String thisAttribute = thisAttributesIterator.next(); String otherAttribute = otherAttributesIterator.next(); @@ -506,16 +503,35 @@ public class MimeType implements Comparable<MimeType>, Serializable { if (comp != 0) { return comp; } - String thisValue = getParameters().get(thisAttribute); - String otherValue = other.getParameters().get(otherAttribute); - if (otherValue == null) { - otherValue = ""; + if (PARAM_CHARSET.equals(thisAttribute)) { + Charset thisCharset = getCharset(); + Charset otherCharset = other.getCharset(); + if (thisCharset != otherCharset) { + if (thisCharset == null) { + return -1; + } + if (otherCharset == null) { + return 1; + } + comp = thisCharset.compareTo(otherCharset); + if (comp != 0) { + return comp; + } + } } - comp = thisValue.compareTo(otherValue); - if (comp != 0) { - return comp; + else { + String thisValue = getParameters().get(thisAttribute); + String otherValue = other.getParameters().get(otherAttribute); + if (otherValue == null) { + otherValue = ""; + } + comp = thisValue.compareTo(otherValue); + if (comp != 0) { + return comp; + } } } + return 0; } @@ -541,26 +557,26 @@ public class MimeType implements Comparable<MimeType>, Serializable { @Override public int compare(T mimeType1, T mimeType2) { - if (mimeType1.isWildcardType() && !mimeType2.isWildcardType()) { // */* < audio/* + if (mimeType1.isWildcardType() && !mimeType2.isWildcardType()) { // */* < audio/* return 1; } - else if (mimeType2.isWildcardType() && !mimeType1.isWildcardType()) { // audio/* > */* + else if (mimeType2.isWildcardType() && !mimeType1.isWildcardType()) { // audio/* > */* return -1; } - else if (!mimeType1.getType().equals(mimeType2.getType())) { // audio/basic == text/html + else if (!mimeType1.getType().equals(mimeType2.getType())) { // audio/basic == text/html return 0; } - else { // mediaType1.getType().equals(mediaType2.getType()) - if (mimeType1.isWildcardSubtype() && !mimeType2.isWildcardSubtype()) { // audio/* < audio/basic + else { // mediaType1.getType().equals(mediaType2.getType()) + if (mimeType1.isWildcardSubtype() && !mimeType2.isWildcardSubtype()) { // audio/* < audio/basic return 1; } - else if (mimeType2.isWildcardSubtype() && !mimeType1.isWildcardSubtype()) { // audio/basic > audio/* + else if (mimeType2.isWildcardSubtype() && !mimeType1.isWildcardSubtype()) { // audio/basic > audio/* return -1; } - else if (!mimeType1.getSubtype().equals(mimeType2.getSubtype())) { // audio/basic == audio/wave + else if (!mimeType1.getSubtype().equals(mimeType2.getSubtype())) { // audio/basic == audio/wave return 0; } - else { // mediaType2.getSubtype().equals(mediaType2.getSubtype()) + else { // mediaType2.getSubtype().equals(mediaType2.getSubtype()) return compareParameters(mimeType1, mimeType2); } } @@ -569,7 +585,7 @@ public class MimeType implements Comparable<MimeType>, Serializable { protected int compareParameters(T mimeType1, T mimeType2) { int paramsSize1 = mimeType1.getParameters().size(); int paramsSize2 = mimeType2.getParameters().size(); - return (paramsSize2 < paramsSize1 ? -1 : (paramsSize2 == paramsSize1 ? 0 : 1)); // audio/basic;level=1 < audio/basic + return (paramsSize2 < paramsSize1 ? -1 : (paramsSize2 == paramsSize1 ? 0 : 1)); // audio/basic;level=1 < audio/basic } } diff --git a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java index 5b3a7a0f..decf3918 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java +++ b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,7 @@ package org.springframework.util; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -46,7 +47,7 @@ public abstract class MimeTypeUtils { 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; - private static final Random RND = new Random(); + private static final Random RND = new SecureRandom(); private static Charset US_ASCII = Charset.forName("US-ASCII"); @@ -287,8 +288,8 @@ public abstract class MimeTypeUtils { } int eqIndex = parameter.indexOf('='); if (eqIndex >= 0) { - String attribute = parameter.substring(0, eqIndex); - String value = parameter.substring(eqIndex + 1, parameter.length()); + String attribute = parameter.substring(0, eqIndex).trim(); + String value = parameter.substring(eqIndex + 1, parameter.length()).trim(); parameters.put(attribute, value); } } diff --git a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java index 04f3e020..a43d016b 100644 --- a/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ReflectionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -645,8 +645,7 @@ public abstract class ReflectionUtils { } /** - * Invoke the given callback on all fields in the target class, going up the - * class hierarchy to get all declared fields. + * Invoke the given callback on all locally declared fields in the given class. * @param clazz the target class to analyze * @param fc the callback to invoke for each field * @since 4.2 diff --git a/spring-core/src/main/java/org/springframework/util/StreamUtils.java b/spring-core/src/main/java/org/springframework/util/StreamUtils.java index d3374bc3..8feb0f4e 100644 --- a/spring-core/src/main/java/org/springframework/util/StreamUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StreamUtils.java @@ -165,7 +165,7 @@ public abstract class StreamUtils { } long bytesToCopy = end - start + 1; - byte buffer[] = new byte[StreamUtils.BUFFER_SIZE]; + byte[] buffer = new byte[StreamUtils.BUFFER_SIZE]; while (bytesToCopy > 0) { int bytesRead = in.read(buffer); if (bytesRead == -1) { diff --git a/spring-core/src/main/java/org/springframework/util/StringUtils.java b/spring-core/src/main/java/org/springframework/util/StringUtils.java index 5e2fbfec..8dcef81e 100644 --- a/spring-core/src/main/java/org/springframework/util/StringUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StringUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -634,7 +634,7 @@ public abstract class StringUtils { // first path element. This is necessary to correctly parse paths like // "file:core/../core/io/Resource.class", where the ".." should just // strip the first "core" directory while keeping the "file:" prefix. - int prefixIndex = pathToUse.indexOf(":"); + int prefixIndex = pathToUse.indexOf(':'); String prefix = ""; if (prefixIndex != -1) { prefix = pathToUse.substring(0, prefixIndex + 1); @@ -694,11 +694,11 @@ public abstract class StringUtils { } /** - * Parse the given {@code localeString} value into a {@link Locale}. + * Parse the given {@code String} representation into a {@link Locale}. * <p>This is the inverse operation of {@link Locale#toString Locale's toString}. - * @param localeString the locale {@code String}, following {@code Locale's} - * {@code toString()} format ("en", "en_UK", etc); - * also accepts spaces as separators, as an alternative to underscores + * @param localeString the locale {@code String}: following {@code Locale's} + * {@code toString()} format ("en", "en_UK", etc), also accepting spaces as + * separators (as an alternative to underscores) * @return a corresponding {@code Locale} instance, or {@code null} if none * @throws IllegalArgumentException in case of an invalid locale specification */ @@ -815,7 +815,10 @@ public abstract class StringUtils { * @param array1 the first array (can be {@code null}) * @param array2 the second array (can be {@code null}) * @return the new array ({@code null} if both given arrays were {@code null}) + * @deprecated as of 4.3.15, in favor of manual merging via {@link LinkedHashSet} + * (with every entry included at most once, even entries within the first array) */ + @Deprecated public static String[] mergeStringArrays(String[] array1, String[] array2) { if (ObjectUtils.isEmpty(array1)) { return array2; @@ -858,7 +861,6 @@ public abstract class StringUtils { if (collection == null) { return null; } - return collection.toArray(new String[collection.size()]); } @@ -872,9 +874,7 @@ public abstract class StringUtils { if (enumeration == null) { return null; } - - List<String> list = Collections.list(enumeration); - return list.toArray(new String[list.size()]); + return toStringArray(Collections.list(enumeration)); } /** @@ -939,10 +939,9 @@ public abstract class StringUtils { /** * Take an array of strings and split each element based on the given delimiter. - * A {@code Properties} instance is then generated, with the left of the - * delimiter providing the key, and the right of the delimiter providing the value. - * <p>Will trim both the key and value before adding them to the - * {@code Properties} instance. + * A {@code Properties} instance is then generated, with the left of the delimiter + * providing the key, and the right of the delimiter providing the value. + * <p>Will trim both the key and value before adding them to the {@code Properties}. * @param array the array to process * @param delimiter to split each element using (typically the equals symbol) * @return a {@code Properties} instance representing the array contents, diff --git a/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java b/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java index 46eb746b..eca80014 100644 --- a/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java +++ b/spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -134,8 +134,9 @@ public class ListenableFutureCallbackRegistry<T> { synchronized (this.mutex) { this.state = State.SUCCESS; this.result = result; - while (!this.successCallbacks.isEmpty()) { - notifySuccess(this.successCallbacks.poll()); + SuccessCallback<? super T> callback; + while ((callback = this.successCallbacks.poll()) != null) { + notifySuccess(callback); } } } @@ -149,8 +150,9 @@ public class ListenableFutureCallbackRegistry<T> { synchronized (this.mutex) { this.state = State.FAILURE; this.result = ex; - while (!this.failureCallbacks.isEmpty()) { - notifyFailure(this.failureCallbacks.poll()); + FailureCallback callback; + while ((callback = this.failureCallbacks.poll()) != null) { + notifyFailure(callback); } } } diff --git a/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxHandler.java b/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxHandler.java index e4294843..dbc0b700 100644 --- a/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxHandler.java +++ b/spring-core/src/main/java/org/springframework/util/xml/AbstractStaxHandler.java @@ -100,7 +100,7 @@ abstract class AbstractStaxHandler implements ContentHandler, LexicalHandler { } @Override - public final void characters(char ch[], int start, int length) throws SAXException { + public final void characters(char[] ch, int start, int length) throws SAXException { try { String data = new String(ch, start, length); if (!this.inCData) { diff --git a/spring-core/src/main/java/org/springframework/util/xml/DomContentHandler.java b/spring-core/src/main/java/org/springframework/util/xml/DomContentHandler.java index 5a8d92aa..e7987ce0 100644 --- a/spring-core/src/main/java/org/springframework/util/xml/DomContentHandler.java +++ b/spring-core/src/main/java/org/springframework/util/xml/DomContentHandler.java @@ -94,7 +94,7 @@ class DomContentHandler implements ContentHandler { } @Override - public void characters(char ch[], int start, int length) throws SAXException { + public void characters(char[] ch, int start, int length) throws SAXException { String data = new String(ch, start, length); Node parent = getParent(); Node lastChild = parent.getLastChild(); @@ -139,7 +139,7 @@ class DomContentHandler implements ContentHandler { } @Override - public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { } @Override diff --git a/spring-core/src/main/java/org/springframework/util/xml/TransformerUtils.java b/spring-core/src/main/java/org/springframework/util/xml/TransformerUtils.java index 4b48abd4..42d88149 100644 --- a/spring-core/src/main/java/org/springframework/util/xml/TransformerUtils.java +++ b/spring-core/src/main/java/org/springframework/util/xml/TransformerUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2018 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,8 +22,8 @@ import javax.xml.transform.Transformer; import org.springframework.util.Assert; /** - * Contains common behavior relating to {@link javax.xml.transform.Transformer Transformers}, and the - * {@code javax.xml.transform} package in general. + * Contains common behavior relating to {@link javax.xml.transform.Transformer Transformers} + * and the {@code javax.xml.transform} package in general. * * @author Rick Evans * @author Juergen Hoeller @@ -32,16 +32,16 @@ import org.springframework.util.Assert; public abstract class TransformerUtils { /** - * The indent amount of characters if {@link #enableIndenting(javax.xml.transform.Transformer) indenting is enabled}. + * The indent amount of characters if {@link #enableIndenting indenting is enabled}. * <p>Defaults to "2". */ public static final int DEFAULT_INDENT_AMOUNT = 2; + /** - * Enable indenting for the supplied {@link javax.xml.transform.Transformer}. <p>If the underlying XSLT engine is - * Xalan, then the special output key {@code indent-amount} will be also be set to a value of {@link - * #DEFAULT_INDENT_AMOUNT} characters. - * + * Enable indenting for the supplied {@link javax.xml.transform.Transformer}. + * <p>If the underlying XSLT engine is Xalan, then the special output key {@code indent-amount} + * will be also be set to a value of {@link #DEFAULT_INDENT_AMOUNT} characters. * @param transformer the target transformer * @see javax.xml.transform.Transformer#setOutputProperty(String, String) * @see javax.xml.transform.OutputKeys#INDENT @@ -51,18 +51,19 @@ public abstract class TransformerUtils { } /** - * Enable indenting for the supplied {@link javax.xml.transform.Transformer}. <p>If the underlying XSLT engine is - * Xalan, then the special output key {@code indent-amount} will be also be set to a value of {@link - * #DEFAULT_INDENT_AMOUNT} characters. - * - * @param transformer the target transformer - * @param indentAmount the size of the indent (2 characters, 3 characters, etc.) + * Enable indenting for the supplied {@link javax.xml.transform.Transformer}. + * <p>If the underlying XSLT engine is Xalan, then the special output key {@code indent-amount} + * will be also be set to a value of {@link #DEFAULT_INDENT_AMOUNT} characters. + * @param transformer the target transformer + * @param indentAmount the size of the indent (2 characters, 3 characters, etc) * @see javax.xml.transform.Transformer#setOutputProperty(String, String) * @see javax.xml.transform.OutputKeys#INDENT */ public static void enableIndenting(Transformer transformer, int indentAmount) { Assert.notNull(transformer, "Transformer must not be null"); - Assert.isTrue(indentAmount > -1, "The indent amount cannot be less than zero : got " + indentAmount); + if (indentAmount < 0) { + throw new IllegalArgumentException("Invalid indent amount (must not be less than zero): " + indentAmount); + } transformer.setOutputProperty(OutputKeys.INDENT, "yes"); try { // Xalan-specific, but this is the most common XSLT engine in any case @@ -74,7 +75,6 @@ public abstract class TransformerUtils { /** * Disable indenting for the supplied {@link javax.xml.transform.Transformer}. - * * @param transformer the target transformer * @see javax.xml.transform.OutputKeys#INDENT */ diff --git a/spring-core/src/test/java/org/springframework/core/ConventionsTests.java b/spring-core/src/test/java/org/springframework/core/ConventionsTests.java index 74d28bb7..87b43c50 100644 --- a/spring-core/src/test/java/org/springframework/core/ConventionsTests.java +++ b/spring-core/src/test/java/org/springframework/core/ConventionsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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,7 +57,7 @@ public class ConventionsTests { @Test public void emptyList() { - exception.expect(IllegalArgumentException.class); + this.exception.expect(IllegalArgumentException.class); Conventions.getVariableName(new ArrayList<>()); } @@ -67,14 +67,14 @@ public class ConventionsTests { } @Test - public void attributeNameToPropertyName() throws Exception { + public void attributeNameToPropertyName() { assertEquals("transactionManager", Conventions.attributeNameToPropertyName("transaction-manager")); assertEquals("pointcutRef", Conventions.attributeNameToPropertyName("pointcut-ref")); assertEquals("lookupOnStartup", Conventions.attributeNameToPropertyName("lookup-on-startup")); } @Test - public void getQualifiedAttributeName() throws Exception { + public void getQualifiedAttributeName() { String baseName = "foo"; Class<String> cls = String.class; String desiredResult = "java.lang.String.foo"; diff --git a/spring-core/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java b/spring-core/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java index 31090c94..9c17e3d9 100644 --- a/spring-core/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java +++ b/spring-core/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -39,7 +39,7 @@ public class LocalVariableTableParameterNameDiscovererTests { @Test public void methodParameterNameDiscoveryNoArgs() throws NoSuchMethodException { - Method getName = TestObject.class.getMethod("getName", new Class[0]); + Method getName = TestObject.class.getMethod("getName"); String[] names = discoverer.getParameterNames(getName); assertNotNull("should find method info", names); assertEquals("no argument names", 0, names.length); @@ -47,7 +47,7 @@ public class LocalVariableTableParameterNameDiscovererTests { @Test public void methodParameterNameDiscoveryWithArgs() throws NoSuchMethodException { - Method setName = TestObject.class.getMethod("setName", new Class[] { String.class }); + Method setName = TestObject.class.getMethod("setName", String.class); String[] names = discoverer.getParameterNames(setName); assertNotNull("should find method info", names); assertEquals("one argument", 1, names.length); @@ -56,7 +56,7 @@ public class LocalVariableTableParameterNameDiscovererTests { @Test public void consParameterNameDiscoveryNoArgs() throws NoSuchMethodException { - Constructor<TestObject> noArgsCons = TestObject.class.getConstructor(new Class[0]); + Constructor<TestObject> noArgsCons = TestObject.class.getConstructor(); String[] names = discoverer.getParameterNames(noArgsCons); assertNotNull("should find cons info", names); assertEquals("no argument names", 0, names.length); @@ -64,7 +64,7 @@ public class LocalVariableTableParameterNameDiscovererTests { @Test public void consParameterNameDiscoveryArgs() throws NoSuchMethodException { - Constructor<TestObject> twoArgCons = TestObject.class.getConstructor(new Class[] { String.class, int.class }); + Constructor<TestObject> twoArgCons = TestObject.class.getConstructor(String.class, int.class); String[] names = discoverer.getParameterNames(twoArgCons); assertNotNull("should find cons info", names); assertEquals("one argument", 2, names.length); @@ -74,7 +74,7 @@ public class LocalVariableTableParameterNameDiscovererTests { @Test public void staticMethodParameterNameDiscoveryNoArgs() throws NoSuchMethodException { - Method m = getClass().getMethod("staticMethodNoLocalVars", new Class[0]); + Method m = getClass().getMethod("staticMethodNoLocalVars"); String[] names = discoverer.getParameterNames(m); assertNotNull("should find method info", names); assertEquals("no argument names", 0, names.length); @@ -84,14 +84,14 @@ public class LocalVariableTableParameterNameDiscovererTests { public void overloadedStaticMethod() throws Exception { Class<? extends LocalVariableTableParameterNameDiscovererTests> clazz = this.getClass(); - Method m1 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE, Long.TYPE }); + Method m1 = clazz.getMethod("staticMethod", Long.TYPE, Long.TYPE); String[] names = discoverer.getParameterNames(m1); assertNotNull("should find method info", names); assertEquals("two arguments", 2, names.length); assertEquals("x", names[0]); assertEquals("y", names[1]); - Method m2 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE, Long.TYPE, Long.TYPE }); + Method m2 = clazz.getMethod("staticMethod", Long.TYPE, Long.TYPE, Long.TYPE); names = discoverer.getParameterNames(m2); assertNotNull("should find method info", names); assertEquals("three arguments", 3, names.length); @@ -104,13 +104,13 @@ public class LocalVariableTableParameterNameDiscovererTests { public void overloadedStaticMethodInInnerClass() throws Exception { Class<InnerClass> clazz = InnerClass.class; - Method m1 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE }); + Method m1 = clazz.getMethod("staticMethod", Long.TYPE); String[] names = discoverer.getParameterNames(m1); assertNotNull("should find method info", names); assertEquals("one argument", 1, names.length); assertEquals("x", names[0]); - Method m2 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE, Long.TYPE }); + Method m2 = clazz.getMethod("staticMethod", Long.TYPE, Long.TYPE); names = discoverer.getParameterNames(m2); assertNotNull("should find method info", names); assertEquals("two arguments", 2, names.length); @@ -122,14 +122,14 @@ public class LocalVariableTableParameterNameDiscovererTests { public void overloadedMethod() throws Exception { Class<? extends LocalVariableTableParameterNameDiscovererTests> clazz = this.getClass(); - Method m1 = clazz.getMethod("instanceMethod", new Class[] { Double.TYPE, Double.TYPE }); + Method m1 = clazz.getMethod("instanceMethod", Double.TYPE, Double.TYPE); String[] names = discoverer.getParameterNames(m1); assertNotNull("should find method info", names); assertEquals("two arguments", 2, names.length); assertEquals("x", names[0]); assertEquals("y", names[1]); - Method m2 = clazz.getMethod("instanceMethod", new Class[] { Double.TYPE, Double.TYPE, Double.TYPE }); + Method m2 = clazz.getMethod("instanceMethod", Double.TYPE, Double.TYPE, Double.TYPE); names = discoverer.getParameterNames(m2); assertNotNull("should find method info", names); assertEquals("three arguments", 3, names.length); @@ -142,13 +142,13 @@ public class LocalVariableTableParameterNameDiscovererTests { public void overloadedMethodInInnerClass() throws Exception { Class<InnerClass> clazz = InnerClass.class; - Method m1 = clazz.getMethod("instanceMethod", new Class[] { String.class }); + Method m1 = clazz.getMethod("instanceMethod", String.class); String[] names = discoverer.getParameterNames(m1); assertNotNull("should find method info", names); assertEquals("one argument", 1, names.length); assertEquals("aa", names[0]); - Method m2 = clazz.getMethod("instanceMethod", new Class[] { String.class, String.class }); + Method m2 = clazz.getMethod("instanceMethod", String.class, String.class); names = discoverer.getParameterNames(m2); assertNotNull("should find method info", names); assertEquals("two arguments", 2, names.length); @@ -223,6 +223,7 @@ public class LocalVariableTableParameterNameDiscovererTests { assertNull(names); } + public static void staticMethodNoLocalVars() { } @@ -246,6 +247,7 @@ public class LocalVariableTableParameterNameDiscovererTests { return u; } + public static class InnerClass { public int waz = 0; @@ -278,7 +280,9 @@ public class LocalVariableTableParameterNameDiscovererTests { } } + public static class GenerifiedClass<K, V> { + private static long date; static { @@ -317,4 +321,5 @@ public class LocalVariableTableParameterNameDiscovererTests { return date; } } + } diff --git a/spring-core/src/test/java/org/springframework/core/MethodParameterTests.java b/spring-core/src/test/java/org/springframework/core/MethodParameterTests.java index c3c3e7d1..d7b01d52 100644 --- a/spring-core/src/test/java/org/springframework/core/MethodParameterTests.java +++ b/spring-core/src/test/java/org/springframework/core/MethodParameterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2018 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,11 @@ package org.springframework.core; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import org.junit.Before; @@ -25,9 +30,13 @@ import static org.junit.Assert.*; /** * @author Arjen Poutsma + * @author Juergen Hoeller + * @author Sam Brannen */ public class MethodParameterTests { + private Method method; + private MethodParameter stringParameter; private MethodParameter longParameter; @@ -36,13 +45,14 @@ public class MethodParameterTests { @Before - public void setUp() throws NoSuchMethodException { - Method method = getClass().getMethod("method", String.class, Long.TYPE); + public void setup() throws NoSuchMethodException { + method = getClass().getMethod("method", String.class, Long.TYPE); stringParameter = new MethodParameter(method, 0); longParameter = new MethodParameter(method, 1); intReturnType = new MethodParameter(method, -1); } + @Test public void testEquals() throws NoSuchMethodException { assertEquals(stringParameter, stringParameter); @@ -60,8 +70,8 @@ public class MethodParameterTests { MethodParameter methodParameter = new MethodParameter(method, 0); assertEquals(stringParameter, methodParameter); assertEquals(methodParameter, stringParameter); - assertFalse(longParameter.equals(methodParameter)); - assertFalse(methodParameter.equals(longParameter)); + assertNotEquals(longParameter, methodParameter); + assertNotEquals(methodParameter, longParameter); } @Test @@ -73,7 +83,32 @@ public class MethodParameterTests { Method method = getClass().getMethod("method", String.class, Long.TYPE); MethodParameter methodParameter = new MethodParameter(method, 0); assertEquals(stringParameter.hashCode(), methodParameter.hashCode()); - assertTrue(longParameter.hashCode() != methodParameter.hashCode()); + assertNotEquals(longParameter.hashCode(), methodParameter.hashCode()); + } + + @Test + public void annotatedConstructorParameterInStaticNestedClass() throws Exception { + Constructor<?> constructor = NestedClass.class.getDeclaredConstructor(String.class); + MethodParameter methodParameter = MethodParameter.forMethodOrConstructor(constructor, 0); + assertEquals(String.class, methodParameter.getParameterType()); + assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class)); + } + + @Test // SPR-16652 + public void annotatedConstructorParameterInInnerClass() throws Exception { + Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Integer.class); + + MethodParameter methodParameter = MethodParameter.forMethodOrConstructor(constructor, 0); + assertEquals(getClass(), methodParameter.getParameterType()); + assertNull(methodParameter.getParameterAnnotation(Param.class)); + + methodParameter = MethodParameter.forMethodOrConstructor(constructor, 1); + assertEquals(String.class, methodParameter.getParameterType()); + assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class)); + + methodParameter = MethodParameter.forMethodOrConstructor(constructor, 2); + assertEquals(Integer.class, methodParameter.getParameterType()); + assertNull(methodParameter.getParameterAnnotation(Param.class)); } @@ -81,4 +116,23 @@ public class MethodParameterTests { return 42; } + @SuppressWarnings("unused") + private static class NestedClass { + + NestedClass(@Param String s) { + } + } + + @SuppressWarnings("unused") + private class InnerClass { + + public InnerClass(@Param String s, Integer i) { + } + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + private @interface Param { + } + } diff --git a/spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java b/spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java index c0e60ad1..73376ccf 100644 --- a/spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java +++ b/spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -44,19 +44,19 @@ public class NestedExceptionTests { nex.printStackTrace(pw); pw.flush(); String stackTrace = new String(baos.toByteArray()); - assertFalse(stackTrace.indexOf(mesg) == -1); + assertTrue(stackTrace.contains(mesg)); } @Test public void nestedRuntimeExceptionWithRootCause() { String myMessage = "mesg for this exception"; - String rootCauseMesg = "this is the obscure message of the root cause"; - Exception rootCause = new Exception(rootCauseMesg); + String rootCauseMsg = "this is the obscure message of the root cause"; + Exception rootCause = new Exception(rootCauseMsg); // Making a class abstract doesn't _really_ prevent instantiation :-) NestedRuntimeException nex = new NestedRuntimeException(myMessage, rootCause) {}; assertEquals(nex.getCause(), rootCause); - assertTrue(nex.getMessage().indexOf(myMessage) != -1); - assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1); + assertTrue(nex.getMessage().contains(myMessage)); + assertTrue(nex.getMessage().endsWith(rootCauseMsg)); // check PrintStackTrace ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -64,8 +64,8 @@ public class NestedExceptionTests { nex.printStackTrace(pw); pw.flush(); String stackTrace = new String(baos.toByteArray()); - assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1); - assertFalse(stackTrace.indexOf(rootCauseMesg) == -1); + assertTrue(stackTrace.contains(rootCause.getClass().getName())); + assertTrue(stackTrace.contains(rootCauseMsg)); } @Test @@ -82,19 +82,19 @@ public class NestedExceptionTests { nex.printStackTrace(pw); pw.flush(); String stackTrace = new String(baos.toByteArray()); - assertFalse(stackTrace.indexOf(mesg) == -1); + assertTrue(stackTrace.contains(mesg)); } @Test public void nestedCheckedExceptionWithRootCause() { String myMessage = "mesg for this exception"; - String rootCauseMesg = "this is the obscure message of the root cause"; - Exception rootCause = new Exception(rootCauseMesg); + String rootCauseMsg = "this is the obscure message of the root cause"; + Exception rootCause = new Exception(rootCauseMsg); // Making a class abstract doesn't _really_ prevent instantiation :-) NestedCheckedException nex = new NestedCheckedException(myMessage, rootCause) {}; assertEquals(nex.getCause(), rootCause); - assertTrue(nex.getMessage().indexOf(myMessage) != -1); - assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1); + assertTrue(nex.getMessage().contains(myMessage)); + assertTrue(nex.getMessage().endsWith(rootCauseMsg)); // check PrintStackTrace ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -102,8 +102,8 @@ public class NestedExceptionTests { nex.printStackTrace(pw); pw.flush(); String stackTrace = new String(baos.toByteArray()); - assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1); - assertFalse(stackTrace.indexOf(rootCauseMesg) == -1); + assertTrue(stackTrace.contains(rootCause.getClass().getName())); + assertTrue(stackTrace.contains(rootCauseMsg)); } } diff --git a/spring-core/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java b/spring-core/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java index 52209456..d2a1aa75 100644 --- a/spring-core/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java +++ b/spring-core/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java @@ -56,7 +56,7 @@ public class PrioritizedParameterNameDiscovererTests { private final Method anyMethod; public PrioritizedParameterNameDiscovererTests() throws SecurityException, NoSuchMethodException { - anyMethod = TestObject.class.getMethod("getAge", (Class[]) null); + anyMethod = TestObject.class.getMethod("getAge"); } @Test diff --git a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java index ab903fc6..68e5af3b 100644 --- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java +++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -42,7 +42,6 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.Callable; -import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -927,16 +926,6 @@ public class ResolvableTypeTests { assertThat(ResolvableType.forClass(classType).getSuperType().getSource(), equalTo((Object) classType.getGenericSuperclass())); } - private void assertFieldToStringValue(String field, String expected) throws Exception { - ResolvableType type = ResolvableType.forField(Fields.class.getField(field)); - assertThat("field " + field + " toString", type.toString(), equalTo(expected)); - } - - private void assertTypedFieldToStringValue(String field, String expected) throws Exception { - ResolvableType type = ResolvableType.forField(Fields.class.getField(field), TypedFields.class); - assertThat("field " + field + " toString", type.toString(), equalTo(expected)); - } - @Test public void resolveFromOuterClass() throws Exception { Field field = EnclosedInParameterizedType.InnerTyped.class.getField("field"); @@ -954,7 +943,6 @@ public class ResolvableTypeTests { assertThat(type.asCollection().getGeneric().getGeneric().resolve(), equalTo((Type) String.class)); } - @Test public void isAssignableFromMustNotBeNull() throws Exception { this.thrown.expect(IllegalArgumentException.class); @@ -1189,18 +1177,17 @@ public class ResolvableTypeTests { assertThat(forFieldDirect, not(equalTo(forFieldWithImplementation))); } - @SuppressWarnings("unused") - private HashMap<Integer, List<String>> myMap; - @Test public void javaDocSample() throws Exception { ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap")); + assertThat(t.toString(), equalTo("java.util.HashMap<java.lang.Integer, java.util.List<java.lang.String>>")); + assertThat(t.getType().getTypeName(), equalTo("java.util.HashMap<java.lang.Integer, java.util.List<java.lang.String>>")); assertThat(t.getSuperType().toString(), equalTo("java.util.AbstractMap<java.lang.Integer, java.util.List<java.lang.String>>")); assertThat(t.asMap().toString(), equalTo("java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>")); - assertThat(t.getGeneric(0).resolve(), equalTo((Class)Integer.class)); - assertThat(t.getGeneric(1).resolve(), equalTo((Class)List.class)); + assertThat(t.getGeneric(0).resolve(), equalTo(Integer.class)); + assertThat(t.getGeneric(1).resolve(), equalTo(List.class)); assertThat(t.getGeneric(1).toString(), equalTo("java.util.List<java.lang.String>")); - assertThat(t.resolveGeneric(1, 0), equalTo((Class) String.class)); + assertThat(t.resolveGeneric(1, 0), equalTo(String.class)); } @Test @@ -1208,6 +1195,7 @@ public class ResolvableTypeTests { ResolvableType elementType = ResolvableType.forClassWithGenerics(Map.class, Integer.class, String.class); ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); assertThat(listType.toString(), equalTo("java.util.List<java.util.Map<java.lang.Integer, java.lang.String>>")); + assertThat(listType.getType().getTypeName(), equalTo("java.util.List<java.util.Map<java.lang.Integer, java.lang.String>>")); } @Test @@ -1228,7 +1216,7 @@ public class ResolvableTypeTests { ResolvableType elementType = ResolvableType.forField(Fields.class.getField("stringList")); ResolvableType type = ResolvableType.forArrayComponent(elementType); assertThat(type.toString(), equalTo("java.util.List<java.lang.String>[]")); - assertThat(type.resolve(), equalTo((Class) List[].class)); + assertThat(type.resolve(), equalTo(List[].class)); } @Test @@ -1248,14 +1236,14 @@ public class ResolvableTypeTests { @Test public void canResolveVoid() throws Exception { ResolvableType type = ResolvableType.forClass(void.class); - assertThat(type.resolve(), equalTo((Class) void.class)); + assertThat(type.resolve(), equalTo(void.class)); } @Test public void narrow() throws Exception { ResolvableType type = ResolvableType.forField(Fields.class.getField("stringList")); ResolvableType narrow = ResolvableType.forType(ArrayList.class, type); - assertThat(narrow.getGeneric().resolve(), equalTo((Class) String.class)); + assertThat(narrow.getGeneric().resolve(), equalTo(String.class)); } @Test @@ -1330,23 +1318,30 @@ public class ResolvableTypeTests { ResolvableType read = (ResolvableType) ois.readObject(); assertThat(read, equalTo(type)); assertThat(read.getType(), equalTo(type.getType())); - assertThat(read.resolve(), equalTo((Class) type.resolve())); + assertThat(read.resolve(), equalTo(type.resolve())); return read; } - private static AssertAssignbleMatcher assertAssignable(final ResolvableType type, final ResolvableType... fromTypes) { - return new AssertAssignbleMatcher() { - @Override - public void equalTo(boolean... values) { - for (int i = 0; i < fromTypes.length; i++) { - assertThat(stringDesc(type) + " isAssignableFrom " + stringDesc(fromTypes[i]), - type.isAssignableFrom(fromTypes[i]), Matchers.equalTo(values[i])); - } + private void assertFieldToStringValue(String field, String expected) throws Exception { + ResolvableType type = ResolvableType.forField(Fields.class.getField(field)); + assertThat("field " + field + " toString", type.toString(), equalTo(expected)); + } + + private void assertTypedFieldToStringValue(String field, String expected) throws Exception { + ResolvableType type = ResolvableType.forField(Fields.class.getField(field), TypedFields.class); + assertThat("field " + field + " toString", type.toString(), equalTo(expected)); + } + + private AssertAssignbleMatcher assertAssignable(final ResolvableType type, final ResolvableType... fromTypes) { + return values -> { + for (int i = 0; i < fromTypes.length; i++) { + assertThat(stringDesc(type) + " isAssignableFrom " + stringDesc(fromTypes[i]), + type.isAssignableFrom(fromTypes[i]), equalTo(values[i])); } }; } - private static String stringDesc(ResolvableType type) { + private String stringDesc(ResolvableType type) { if (type == ResolvableType.NONE) { return "NONE"; } @@ -1357,7 +1352,11 @@ public class ResolvableTypeTests { } - private static interface AssertAssignbleMatcher { + @SuppressWarnings("unused") + private HashMap<Integer, List<String>> myMap; + + + private interface AssertAssignbleMatcher { void equalTo(boolean... values); } diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java index ca033bb1..620668bf 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,7 +22,6 @@ import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; @@ -38,7 +37,6 @@ import org.springframework.core.Ordered; import org.springframework.core.annotation.subpackage.NonPublicAnnotatedClass; import org.springframework.stereotype.Component; import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; import static java.util.Arrays.*; import static java.util.stream.Collectors.*; @@ -63,23 +61,8 @@ public class AnnotationUtilsTests { @Before - public void clearCachesBeforeTests() { - clearCaches(); - } - - static void clearCaches() { - clearCache("findAnnotationCache", "annotatedInterfaceCache", "metaPresentCache", "synthesizableCache", - "attributeAliasesCache", "attributeMethodsCache", "aliasDescriptorCache"); - } - - static void clearCache(String... cacheNames) { - stream(cacheNames).forEach(cacheName -> getCache(cacheName).clear()); - } - - static Map<?, ?> getCache(String cacheName) { - Field field = ReflectionUtils.findField(AnnotationUtils.class, cacheName); - ReflectionUtils.makeAccessible(field); - return (Map<?, ?>) ReflectionUtils.getField(field, null); + public void clearCacheBeforeTests() { + AnnotationUtils.clearCache(); } @@ -727,7 +710,7 @@ public class AnnotationUtilsTests { public void getAttributeOverrideNameFromWrongTargetAnnotation() throws Exception { Method attribute = AliasedComposedContextConfig.class.getDeclaredMethod("xmlConfigFile"); assertThat("xmlConfigFile is not an alias for @Component.", - getAttributeOverrideName(attribute, Component.class), is(nullValue())); + getAttributeOverrideName(attribute, Component.class), is(nullValue())); } @Test @@ -861,12 +844,6 @@ public class AnnotationUtilsTests { } @Test - public void synthesizeAnnotationsFromNullSources() throws Exception { - assertNull("null annotation", synthesizeAnnotation(null, null)); - assertNull("null map", synthesizeAnnotation(null, WebMapping.class, null)); - } - - @Test public void synthesizeAlreadySynthesizedAnnotation() throws Exception { Method method = WebController.class.getMethod("handleMappedWithValueAttribute"); WebMapping webMapping = method.getAnnotation(WebMapping.class); @@ -927,7 +904,6 @@ public class AnnotationUtilsTests { public void synthesizeAnnotationWithAttributeAliasWithMirroredAliasForWrongAttribute() throws Exception { AliasForWithMirroredAliasForWrongAttribute annotation = AliasForWithMirroredAliasForWrongAttributeClass.class.getAnnotation(AliasForWithMirroredAliasForWrongAttribute.class); - exception.expect(AnnotationConfigurationException.class); exception.expectMessage(startsWith("Attribute 'bar' in")); exception.expectMessage(containsString(AliasForWithMirroredAliasForWrongAttribute.class.getName())); @@ -1035,18 +1011,18 @@ public class AnnotationUtilsTests { @Test public void synthesizeAnnotationWithImplicitAliasesWithImpliedAliasNamesOmitted() throws Exception { assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted( - ValueImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "value"); + ValueImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "value"); assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted( - LocationsImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "location"); + LocationsImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "location"); assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted( - XmlFilesImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "xmlFile"); + XmlFilesImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "xmlFile"); } - private void assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(Class<?> clazz, - String expected) throws Exception { + private void assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted( + Class<?> clazz, String expected) { ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig config = clazz.getAnnotation( - ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class); + ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class); assertNotNull(config); ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig synthesizedConfig = synthesizeAnnotation(config); @@ -1241,9 +1217,11 @@ public class AnnotationUtilsTests { assertEquals("location: ", "", contextConfig.location()); } - @Test(expected = AnnotationConfigurationException.class) - public void synthesizeAnnotationWithAttributeAliasesDifferentValues() throws Exception { - getValue(synthesizeAnnotation(ContextConfigMismatch.class.getAnnotation(ContextConfig.class))); + @Test + public void synthesizeAnnotationWithAttributeAliasesWithDifferentValues() throws Exception { + ContextConfig contextConfig = synthesizeAnnotation(ContextConfigMismatch.class.getAnnotation(ContextConfig.class)); + exception.expect(AnnotationConfigurationException.class); + getValue(contextConfig); } @Test diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java index d3b45602..3fa90396 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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.annotation; import java.lang.annotation.Annotation; +import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -25,9 +26,6 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; -import org.springframework.core.annotation.AnnotationUtilsTests.ImplicitAliasesContextConfig; -import org.springframework.core.annotation.AnnotationUtilsTests.RequestMethod; -import org.springframework.core.annotation.AnnotationUtilsTests.WebMapping; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -44,14 +42,21 @@ import static org.springframework.core.annotation.AnnotationUtilsTests.*; @SuppressWarnings("serial") public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnnotationAttributeExtractorTestCase { + @Override + protected AnnotationAttributeExtractor<?> createExtractorFor(Class<?> clazz, String expected, Class<? extends Annotation> annotationType) { + Map<String, Object> attributes = Collections.singletonMap(expected, expected); + return new MapAnnotationAttributeExtractor(attributes, annotationType, clazz); + } + @Before - public void clearCachesBeforeTests() { - AnnotationUtilsTests.clearCaches(); + public void clearCacheBeforeTests() { + AnnotationUtils.clearCache(); } + @Test - public void enrichAndValidateAttributesWithImplicitAliasesAndMinimalAttributes() { - Map<String, Object> attributes = new HashMap<String, Object>(); + public void enrichAndValidateAttributesWithImplicitAliasesAndMinimalAttributes() throws Exception { + Map<String, Object> attributes = new HashMap<>(); Map<String, Object> expectedAttributes = new HashMap<String, Object>() {{ put("groovyScript", ""); put("xmlFile", ""); @@ -67,7 +72,7 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno } @Test - public void enrichAndValidateAttributesWithImplicitAliases() { + public void enrichAndValidateAttributesWithImplicitAliases() throws Exception { Map<String, Object> attributes = new HashMap<String, Object>() {{ put("groovyScript", "groovy!"); }}; @@ -88,7 +93,6 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno @Test public void enrichAndValidateAttributesWithSingleElementThatOverridesAnArray() { - // @formatter:off Map<String, Object> attributes = new HashMap<String, Object>() {{ // Intentionally storing 'value' as a single String instead of an array. // put("value", asArray("/foo")); @@ -102,7 +106,6 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno put("name", "test"); put("method", new RequestMethod[0]); }}; - // @formatter:on MapAnnotationAttributeExtractor extractor = new MapAnnotationAttributeExtractor(attributes, WebMapping.class, null); Map<String, Object> enriched = extractor.getSource(); @@ -112,22 +115,21 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno } @SuppressWarnings("unchecked") - private void assertEnrichAndValidateAttributes(Map<String, Object> sourceAttributes, Map<String, Object> expected) { + private void assertEnrichAndValidateAttributes(Map<String, Object> sourceAttributes, Map<String, Object> expected) throws Exception { Class<? extends Annotation> annotationType = ImplicitAliasesContextConfig.class; - // Since the ordering of attribute methods returned by the JVM is - // non-deterministic, we have to rig the attributeAliasesCache in AnnotationUtils - // so that the tests consistently fail in case enrichAndValidateAttributes() is - // buggy. - // - // Otherwise, these tests would intermittently pass even for an invalid - // implementation. + // Since the ordering of attribute methods returned by the JVM is non-deterministic, + // we have to rig the attributeAliasesCache in AnnotationUtils so that the tests + // consistently fail in case enrichAndValidateAttributes() is buggy. + // Otherwise, these tests would intermittently pass even for an invalid implementation. + Field cacheField = AnnotationUtils.class.getDeclaredField("attributeAliasesCache"); + cacheField.setAccessible(true); Map<Class<? extends Annotation>, MultiValueMap<String, String>> attributeAliasesCache = - (Map<Class<? extends Annotation>, MultiValueMap<String, String>>) AnnotationUtilsTests.getCache("attributeAliasesCache"); + (Map<Class<? extends Annotation>, MultiValueMap<String, String>>) cacheField.get(null); // Declare aliases in an order that will cause enrichAndValidateAttributes() to // fail unless it considers all aliases in the set of implicit aliases. - MultiValueMap<String, String> aliases = new LinkedMultiValueMap<String, String>(); + MultiValueMap<String, String> aliases = new LinkedMultiValueMap<>(); aliases.put("xmlFile", Arrays.asList("value", "groovyScript", "location1", "location2", "location3")); aliases.put("groovyScript", Arrays.asList("value", "xmlFile", "location1", "location2", "location3")); aliases.put("value", Arrays.asList("xmlFile", "groovyScript", "location1", "location2", "location3")); @@ -144,10 +146,4 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno expected.forEach((attr, expectedValue) -> assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expectedValue))); } - @Override - protected AnnotationAttributeExtractor<?> createExtractorFor(Class<?> clazz, String expected, Class<? extends Annotation> annotationType) { - Map<String, Object> attributes = Collections.singletonMap(expected, expected); - return new MapAnnotationAttributeExtractor(attributes, annotationType, clazz); - } - } diff --git a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java index 2f377fc0..66aaf24f 100644 --- a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -294,9 +294,9 @@ public class AnnotationMetadataTests { assertEquals("direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value")); assertEquals("direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("myValue")); List<Object> allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value"); - assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); + assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional"); - assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct"))))); + assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct"))))); assertTrue(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName())); @@ -309,36 +309,36 @@ public class AnnotationMetadataTests { AnnotationAttributes nestedAnno = specialAttrs.getAnnotation("nestedAnno"); assertThat("na", is(nestedAnno.getString("value"))); assertTrue(nestedAnno.getEnum("anEnum").equals(SomeEnum.LABEL1)); - assertArrayEquals(new Class[] { String.class }, (Class[]) nestedAnno.get("classArray")); + assertArrayEquals(new Class<?>[] {String.class}, (Class<?>[]) nestedAnno.get("classArray")); AnnotationAttributes[] nestedAnnoArray = specialAttrs.getAnnotationArray("nestedAnnoArray"); assertThat(nestedAnnoArray.length, is(2)); assertThat(nestedAnnoArray[0].getString("value"), is("default")); assertTrue(nestedAnnoArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT)); - assertArrayEquals(new Class[] { Void.class }, (Class[]) nestedAnnoArray[0].get("classArray")); + assertArrayEquals(new Class<?>[] {Void.class}, (Class<?>[]) nestedAnnoArray[0].get("classArray")); assertThat(nestedAnnoArray[1].getString("value"), is("na1")); assertTrue(nestedAnnoArray[1].getEnum("anEnum").equals(SomeEnum.LABEL2)); - assertArrayEquals(new Class[] { Number.class }, (Class[]) nestedAnnoArray[1].get("classArray")); - assertArrayEquals(new Class[] { Number.class }, nestedAnnoArray[1].getClassArray("classArray")); + assertArrayEquals(new Class<?>[] {Number.class}, (Class<?>[]) nestedAnnoArray[1].get("classArray")); + assertArrayEquals(new Class<?>[] {Number.class}, nestedAnnoArray[1].getClassArray("classArray")); AnnotationAttributes optional = specialAttrs.getAnnotation("optional"); assertThat(optional.getString("value"), is("optional")); assertTrue(optional.getEnum("anEnum").equals(SomeEnum.DEFAULT)); - assertArrayEquals(new Class[] { Void.class }, (Class[]) optional.get("classArray")); - assertArrayEquals(new Class[] { Void.class }, optional.getClassArray("classArray")); + assertArrayEquals(new Class<?>[] {Void.class}, (Class<?>[]) optional.get("classArray")); + assertArrayEquals(new Class<?>[] {Void.class}, optional.getClassArray("classArray")); AnnotationAttributes[] optionalArray = specialAttrs.getAnnotationArray("optionalArray"); assertThat(optionalArray.length, is(1)); assertThat(optionalArray[0].getString("value"), is("optional")); assertTrue(optionalArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT)); - assertArrayEquals(new Class[] { Void.class }, (Class[]) optionalArray[0].get("classArray")); - assertArrayEquals(new Class[] { Void.class }, optionalArray[0].getClassArray("classArray")); + assertArrayEquals(new Class<?>[] {Void.class}, (Class<?>[]) optionalArray[0].get("classArray")); + assertArrayEquals(new Class<?>[] {Void.class}, optionalArray[0].getClassArray("classArray")); assertEquals("direct", metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value")); allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value"); - assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); + assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional"); - assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct"))))); + assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct"))))); } { // perform tests with classValuesAsString = true AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes( @@ -365,9 +365,9 @@ public class AnnotationMetadataTests { assertArrayEquals(new String[] { Void.class.getName() }, (String[]) optionalArray[0].get("classArray")); assertArrayEquals(new String[] { Void.class.getName() }, optionalArray[0].getStringArray("classArray")); - assertEquals(metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"), "direct"); + assertEquals("direct", metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value")); allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value"); - assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); + assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); } } diff --git a/spring-core/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java b/spring-core/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java index 6dd6dace..01a679d6 100644 --- a/spring-core/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2018 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. @@ -49,7 +49,7 @@ public class AnnotationTypeFilterTests { @Test public void testInheritedAnnotationFromInterfaceDoesNotMatch() throws Exception { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); - String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubClassOfSomeComponentInterface"; + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeClassWithSomeComponentInterface"; MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); @@ -61,7 +61,7 @@ public class AnnotationTypeFilterTests { @Test public void testInheritedAnnotationFromBaseClassDoesMatch() throws Exception { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); - String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubClassOfSomeComponent"; + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubclassOfSomeComponent"; MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); @@ -94,22 +94,21 @@ public class AnnotationTypeFilterTests { @Test public void testMatchesInterfacesIfConfigured() throws Exception { - MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); - String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeComponentInterface"; + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeClassWithSomeComponentInterface"; MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class, false, true); - assertTrue(filter.match(metadataReader, metadataReaderFactory)); ClassloadingAssertions.assertClassNotLoaded(classUnderTest); } + // We must use a standalone set of types to ensure that no one else is loading them // and interfering with ClassloadingAssertions.assertClassNotLoaded() @Inherited - private static @interface InheritedAnnotation { + private @interface InheritedAnnotation { } @@ -119,21 +118,21 @@ public class AnnotationTypeFilterTests { @InheritedAnnotation - private static interface SomeComponentInterface { + private interface SomeComponentInterface { } @SuppressWarnings("unused") - private static class SomeSubClassOfSomeComponentInterface implements SomeComponentInterface { + private static class SomeClassWithSomeComponentInterface implements Cloneable, SomeComponentInterface { } @SuppressWarnings("unused") - private static class SomeSubClassOfSomeComponent extends SomeComponent { + private static class SomeSubclassOfSomeComponent extends SomeComponent { } - private static @interface NonInheritedAnnotation { + private @interface NonInheritedAnnotation { } diff --git a/spring-core/src/test/java/org/springframework/core/type/ClassloadingAssertions.java b/spring-core/src/test/java/org/springframework/core/type/ClassloadingAssertions.java index 16a0e896..53dc8782 100644 --- a/spring-core/src/test/java/org/springframework/core/type/ClassloadingAssertions.java +++ b/spring-core/src/test/java/org/springframework/core/type/ClassloadingAssertions.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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.type; import java.lang.reflect.Method; @@ -30,9 +31,9 @@ abstract class ClassloadingAssertions { private static boolean isClassLoaded(String className) { ClassLoader cl = ClassUtils.getDefaultClassLoader(); - Method findLoadeClassMethod = ReflectionUtils.findMethod(cl.getClass(), "findLoadedClass", new Class[] { String.class }); - ReflectionUtils.makeAccessible(findLoadeClassMethod); - Class<?> loadedClass = (Class<?>) ReflectionUtils.invokeMethod(findLoadeClassMethod, cl, new Object[] { className }); + Method findLoadedClassMethod = ReflectionUtils.findMethod(cl.getClass(), "findLoadedClass", String.class); + ReflectionUtils.makeAccessible(findLoadedClassMethod); + Class<?> loadedClass = (Class<?>) ReflectionUtils.invokeMethod(findLoadedClassMethod, cl, className); return loadedClass != null; } @@ -40,4 +41,4 @@ abstract class ClassloadingAssertions { assertFalse("Class [" + className + "] should not have been loaded", isClassLoaded(className)); } -}
\ No newline at end of file +} diff --git a/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java index 32978f57..8786363c 100644 --- a/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -212,7 +212,7 @@ public class ClassUtilsTests { assertNotNull(method); assertEquals("size", method.getName()); - method = ClassUtils.getMethodIfAvailable(Collection.class, "remove", new Class[] {Object.class}); + method = ClassUtils.getMethodIfAvailable(Collection.class, "remove", Object.class); assertNotNull(method); assertEquals("remove", method.getName()); @@ -239,7 +239,7 @@ public class ClassUtilsTests { @Test public void testNoArgsStaticMethod() throws IllegalAccessException, InvocationTargetException { - Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", (Class[]) null); + Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod"); method.invoke(null, (Object[]) null); assertTrue("no argument method was not invoked.", InnerClass.noArgCalled); @@ -247,19 +247,16 @@ public class ClassUtilsTests { @Test public void testArgsStaticMethod() throws IllegalAccessException, InvocationTargetException { - Method method = ClassUtils.getStaticMethod(InnerClass.class, "argStaticMethod", - new Class[] {String.class}); - method.invoke(null, new Object[] {"test"}); + Method method = ClassUtils.getStaticMethod(InnerClass.class, "argStaticMethod", String.class); + method.invoke(null, "test"); assertTrue("argument method was not invoked.", InnerClass.argCalled); } @Test public void testOverloadedStaticMethod() throws IllegalAccessException, InvocationTargetException { - Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", - new Class[] {String.class}); - method.invoke(null, new Object[] {"test"}); - assertTrue("argument method was not invoked.", - InnerClass.overloadedCalled); + Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", String.class); + method.invoke(null, "test"); + assertTrue("argument method was not invoked.", InnerClass.overloadedCalled); } @Test diff --git a/spring-core/src/test/java/org/springframework/util/ConcurrentReferenceHashMapTests.java b/spring-core/src/test/java/org/springframework/util/ConcurrentReferenceHashMapTests.java index d585d0ae..5930a283 100644 --- a/spring-core/src/test/java/org/springframework/util/ConcurrentReferenceHashMapTests.java +++ b/spring-core/src/test/java/org/springframework/util/ConcurrentReferenceHashMapTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2018 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,50 +50,50 @@ import static org.junit.Assert.*; */ public class ConcurrentReferenceHashMapTests { - private static final Comparator<? super String> NULL_SAFE_STRING_SORT = new NullSafeComparator<String>( - new ComparableComparator<String>(), true); + private static final Comparator<? super String> NULL_SAFE_STRING_SORT = + new NullSafeComparator<String>(new ComparableComparator<String>(), true); @Rule public ExpectedException thrown = ExpectedException.none(); - private TestWeakConcurrentCache<Integer, String> map = new TestWeakConcurrentCache<Integer, String>(); + private TestWeakConcurrentCache<Integer, String> map = new TestWeakConcurrentCache<>(); @Test - public void shouldCreateWithDefaults() throws Exception { - ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(); + public void shouldCreateWithDefaults() { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<>(); assertThat(map.getSegmentsSize(), is(16)); assertThat(map.getSegment(0).getSize(), is(1)); assertThat(map.getLoadFactor(), is(0.75f)); } @Test - public void shouldCreateWithInitialCapacity() throws Exception { - ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(32); + public void shouldCreateWithInitialCapacity() { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<>(32); assertThat(map.getSegmentsSize(), is(16)); assertThat(map.getSegment(0).getSize(), is(2)); assertThat(map.getLoadFactor(), is(0.75f)); } @Test - public void shouldCreateWithInitialCapacityAndLoadFactor() throws Exception { - ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(32, 0.5f); + public void shouldCreateWithInitialCapacityAndLoadFactor() { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<>(32, 0.5f); assertThat(map.getSegmentsSize(), is(16)); assertThat(map.getSegment(0).getSize(), is(2)); assertThat(map.getLoadFactor(), is(0.5f)); } @Test - public void shouldCreateWithInitialCapacityAndConcurrenyLevel() throws Exception { - ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(16, 2); + public void shouldCreateWithInitialCapacityAndConcurrenyLevel() { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<>(16, 2); assertThat(map.getSegmentsSize(), is(2)); assertThat(map.getSegment(0).getSize(), is(8)); assertThat(map.getLoadFactor(), is(0.75f)); } @Test - public void shouldCreateFullyCustom() throws Exception { - ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(5, 0.5f, 3); + public void shouldCreateFullyCustom() { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<>(5, 0.5f, 3); // concurrencyLevel of 3 ends up as 4 (nearest power of 2) assertThat(map.getSegmentsSize(), is(4)); // initialCapacity is 5/4 (rounded up, to nearest power of 2) @@ -102,7 +102,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldNeedNonNegativeInitialCapacity() throws Exception { + public void shouldNeedNonNegativeInitialCapacity() { new ConcurrentReferenceHashMap<Integer, String>(0, 1); this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Initial capacity must not be negative"); @@ -110,7 +110,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldNeedPositiveLoadFactor() throws Exception { + public void shouldNeedPositiveLoadFactor() { new ConcurrentReferenceHashMap<Integer, String>(0, 0.1f, 1); this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Load factor must be positive"); @@ -118,7 +118,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldNeedPositiveConcurrencyLevel() throws Exception { + public void shouldNeedPositiveConcurrencyLevel() { new ConcurrentReferenceHashMap<Integer, String>(1, 1); this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Concurrency level must be positive"); @@ -126,7 +126,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldPutAndGet() throws Exception { + public void shouldPutAndGet() { // NOTE we are using mock references so we don't need to worry about GC assertThat(this.map.size(), is(0)); this.map.put(123, "123"); @@ -139,32 +139,40 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldReplaceOnDoublePut() throws Exception { + public void shouldReplaceOnDoublePut() { this.map.put(123, "321"); this.map.put(123, "123"); assertThat(this.map.get(123), is("123")); } @Test - public void shouldPutNullKey() throws Exception { + public void shouldPutNullKey() { + assertThat(this.map.get(null), is(nullValue())); + assertThat(this.map.getOrDefault(null, "456"), is("456")); this.map.put(null, "123"); assertThat(this.map.get(null), is("123")); + assertThat(this.map.getOrDefault(null, "456"), is("123")); } @Test - public void shouldPutNullValue() throws Exception { + public void shouldPutNullValue() { + assertThat(this.map.get(123), is(nullValue())); + assertThat(this.map.getOrDefault(123, "456"), is("456")); this.map.put(123, "321"); + assertThat(this.map.get(123), is("321")); + assertThat(this.map.getOrDefault(123, "456"), is("321")); this.map.put(123, null); assertThat(this.map.get(123), is(nullValue())); + assertThat(this.map.getOrDefault(123, "456"), is(nullValue())); } @Test - public void shouldGetWithNoItems() throws Exception { + public void shouldGetWithNoItems() { assertThat(this.map.get(123), is(nullValue())); } @Test - public void shouldApplySupplimentalHash() throws Exception { + public void shouldApplySupplimentalHash() { Integer key = 123; this.map.put(key, "123"); assertThat(this.map.getSupplimentalHash(), is(not(key.hashCode()))); @@ -172,9 +180,9 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldGetFollowingNexts() throws Exception { + public void shouldGetFollowingNexts() { // Use loadFactor to disable resize - this.map = new TestWeakConcurrentCache<Integer, String>(1, 10.0f, 1); + this.map = new TestWeakConcurrentCache<>(1, 10.0f, 1); this.map.put(1, "1"); this.map.put(2, "2"); this.map.put(3, "3"); @@ -186,8 +194,8 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldResize() throws Exception { - this.map = new TestWeakConcurrentCache<Integer, String>(1, 0.75f, 1); + public void shouldResize() { + this.map = new TestWeakConcurrentCache<>(1, 0.75f, 1); this.map.put(1, "1"); assertThat(this.map.getSegment(0).getSize(), is(1)); assertThat(this.map.get(1), is("1")); @@ -216,8 +224,8 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldPurgeOnGet() throws Exception { - this.map = new TestWeakConcurrentCache<Integer, String>(1, 0.75f, 1); + public void shouldPurgeOnGet() { + this.map = new TestWeakConcurrentCache<>(1, 0.75f, 1); for (int i = 1; i <= 5; i++) { this.map.put(i, String.valueOf(i)); } @@ -231,8 +239,8 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldPergeOnPut() throws Exception { - this.map = new TestWeakConcurrentCache<Integer, String>(1, 0.75f, 1); + public void shouldPergeOnPut() { + this.map = new TestWeakConcurrentCache<>(1, 0.75f, 1); for (int i = 1; i <= 5; i++) { this.map.put(i, String.valueOf(i)); } @@ -247,28 +255,28 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldPutIfAbsent() throws Exception { + public void shouldPutIfAbsent() { assertThat(this.map.putIfAbsent(123, "123"), is(nullValue())); assertThat(this.map.putIfAbsent(123, "123b"), is("123")); assertThat(this.map.get(123), is("123")); } @Test - public void shouldPutIfAbsentWithNullValue() throws Exception { + public void shouldPutIfAbsentWithNullValue() { assertThat(this.map.putIfAbsent(123, null), is(nullValue())); assertThat(this.map.putIfAbsent(123, "123"), is(nullValue())); assertThat(this.map.get(123), is(nullValue())); } @Test - public void shouldPutIfAbsentWithNullKey() throws Exception { + public void shouldPutIfAbsentWithNullKey() { assertThat(this.map.putIfAbsent(null, "123"), is(nullValue())); assertThat(this.map.putIfAbsent(null, "123b"), is("123")); assertThat(this.map.get(null), is("123")); } @Test - public void shouldRemoveKeyAndValue() throws Exception { + public void shouldRemoveKeyAndValue() { this.map.put(123, "123"); assertThat(this.map.remove(123, "456"), is(false)); assertThat(this.map.get(123), is("123")); @@ -278,7 +286,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldRemoveKeyAndValueWithExistingNull() throws Exception { + public void shouldRemoveKeyAndValueWithExistingNull() { this.map.put(123, null); assertThat(this.map.remove(123, "456"), is(false)); assertThat(this.map.get(123), is(nullValue())); @@ -288,7 +296,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldReplaceOldValueWithNewValue() throws Exception { + public void shouldReplaceOldValueWithNewValue() { this.map.put(123, "123"); assertThat(this.map.replace(123, "456", "789"), is(false)); assertThat(this.map.get(123), is("123")); @@ -297,7 +305,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldReplaceOldNullValueWithNewValue() throws Exception { + public void shouldReplaceOldNullValueWithNewValue() { this.map.put(123, null); assertThat(this.map.replace(123, "456", "789"), is(false)); assertThat(this.map.get(123), is(nullValue())); @@ -306,21 +314,21 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldReplaceValue() throws Exception { + public void shouldReplaceValue() { this.map.put(123, "123"); assertThat(this.map.replace(123, "456"), is("123")); assertThat(this.map.get(123), is("456")); } @Test - public void shouldReplaceNullValue() throws Exception { + public void shouldReplaceNullValue() { this.map.put(123, null); assertThat(this.map.replace(123, "456"), is(nullValue())); assertThat(this.map.get(123), is("456")); } @Test - public void shouldGetSize() throws Exception { + public void shouldGetSize() { assertThat(this.map.size(), is(0)); this.map.put(123, "123"); this.map.put(123, null); @@ -329,7 +337,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldSupportIsEmpty() throws Exception { + public void shouldSupportIsEmpty() { assertThat(this.map.isEmpty(), is(true)); this.map.put(123, "123"); this.map.put(123, null); @@ -338,7 +346,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldContainKey() throws Exception { + public void shouldContainKey() { assertThat(this.map.containsKey(123), is(false)); assertThat(this.map.containsKey(456), is(false)); this.map.put(123, "123"); @@ -348,7 +356,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldContainValue() throws Exception { + public void shouldContainValue() { assertThat(this.map.containsValue("123"), is(false)); assertThat(this.map.containsValue(null), is(false)); this.map.put(123, "123"); @@ -358,7 +366,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldRemoveWhenKeyIsInMap() throws Exception { + public void shouldRemoveWhenKeyIsInMap() { this.map.put(123, null); this.map.put(456, "456"); this.map.put(null, "789"); @@ -369,15 +377,15 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldRemoveWhenKeyIsNotInMap() throws Exception { + public void shouldRemoveWhenKeyIsNotInMap() { assertThat(this.map.remove(123), is(nullValue())); assertThat(this.map.remove(null), is(nullValue())); assertThat(this.map.isEmpty(), is(true)); } @Test - public void shouldPutAll() throws Exception { - Map<Integer, String> m = new HashMap<Integer, String>(); + public void shouldPutAll() { + Map<Integer, String> m = new HashMap<>(); m.put(123, "123"); m.put(456, null); m.put(null, "789"); @@ -389,7 +397,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldClear() throws Exception { + public void shouldClear() { this.map.put(123, "123"); this.map.put(456, null); this.map.put(null, "789"); @@ -401,11 +409,11 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldGetKeySet() throws Exception { + public void shouldGetKeySet() { this.map.put(123, "123"); this.map.put(456, null); this.map.put(null, "789"); - Set<Integer> expected = new HashSet<Integer>(); + Set<Integer> expected = new HashSet<>(); expected.add(123); expected.add(456); expected.add(null); @@ -413,26 +421,26 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldGetValues() throws Exception { + public void shouldGetValues() { this.map.put(123, "123"); this.map.put(456, null); this.map.put(null, "789"); - List<String> actual = new ArrayList<String>(this.map.values()); - List<String> expected = new ArrayList<String>(); + List<String> actual = new ArrayList<>(this.map.values()); + List<String> expected = new ArrayList<>(); expected.add("123"); expected.add(null); expected.add("789"); - Collections.sort(actual, NULL_SAFE_STRING_SORT); - Collections.sort(expected, NULL_SAFE_STRING_SORT); + actual.sort(NULL_SAFE_STRING_SORT); + expected.sort(NULL_SAFE_STRING_SORT); assertThat(actual, is(expected)); } @Test - public void shouldGetEntrySet() throws Exception { + public void shouldGetEntrySet() { this.map.put(123, "123"); this.map.put(456, null); this.map.put(null, "789"); - HashMap<Integer, String> expected = new HashMap<Integer, String>(); + HashMap<Integer, String> expected = new HashMap<>(); expected.put(123, "123"); expected.put(456, null); expected.put(null, "789"); @@ -440,13 +448,13 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldGetEntrySetFollowingNext() throws Exception { + public void shouldGetEntrySetFollowingNext() { // Use loadFactor to disable resize - this.map = new TestWeakConcurrentCache<Integer, String>(1, 10.0f, 1); + this.map = new TestWeakConcurrentCache<>(1, 10.0f, 1); this.map.put(1, "1"); this.map.put(2, "2"); this.map.put(3, "3"); - HashMap<Integer, String> expected = new HashMap<Integer, String>(); + HashMap<Integer, String> expected = new HashMap<>(); expected.put(1, "1"); expected.put(2, "2"); expected.put(3, "3"); @@ -454,7 +462,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldRemoveViaEntrySet() throws Exception { + public void shouldRemoveViaEntrySet() { this.map.put(1, "1"); this.map.put(2, "2"); this.map.put(3, "3"); @@ -469,7 +477,7 @@ public class ConcurrentReferenceHashMapTests { } @Test - public void shouldSetViaEntrySet() throws Exception { + public void shouldSetViaEntrySet() { this.map.put(1, "1"); this.map.put(2, "2"); this.map.put(3, "3"); @@ -484,36 +492,21 @@ public class ConcurrentReferenceHashMapTests { @Test @Ignore("Intended for use during development only") - public void shouldBeFasterThanSynchronizedMap() throws Exception { + public void shouldBeFasterThanSynchronizedMap() throws InterruptedException { Map<Integer, WeakReference<String>> synchronizedMap = Collections.synchronizedMap(new WeakHashMap<Integer, WeakReference<String>>()); - StopWatch mapTime = timeMultiThreaded("SynchronizedMap", synchronizedMap, - new ValueFactory<WeakReference<String>>() { - - @Override - public WeakReference<String> newValue(int v) { - return new WeakReference<String>(String.valueOf(v)); - } - }); + StopWatch mapTime = timeMultiThreaded("SynchronizedMap", synchronizedMap, v -> new WeakReference<>(String.valueOf(v))); System.out.println(mapTime.prettyPrint()); this.map.setDisableTestHooks(true); - StopWatch cacheTime = timeMultiThreaded("WeakConcurrentCache", this.map, - new ValueFactory<String>() { - - @Override - public String newValue(int v) { - return String.valueOf(v); - } - }); + StopWatch cacheTime = timeMultiThreaded("WeakConcurrentCache", this.map, String::valueOf); System.out.println(cacheTime.prettyPrint()); // We should be at least 4 time faster - assertThat(cacheTime.getTotalTimeSeconds(), - is(lessThan(mapTime.getTotalTimeSeconds() / 4.0))); + assertThat(cacheTime.getTotalTimeSeconds(), is(lessThan(mapTime.getTotalTimeSeconds() / 4.0))); } @Test - public void shouldSupportNullReference() throws Exception { + public void shouldSupportNullReference() { // GC could happen during restructure so we must be able to create a reference for a null entry map.createReferenceManager().createReference(null, 1234, null); } @@ -557,7 +550,7 @@ public class ConcurrentReferenceHashMapTests { } - private static interface ValueFactory<V> { + private interface ValueFactory<V> { V newValue(int k); } @@ -567,7 +560,7 @@ public class ConcurrentReferenceHashMapTests { private int supplimentalHash; - private final LinkedList<MockReference<K, V>> queue = new LinkedList<MockReference<K, V>>(); + private final LinkedList<MockReference<K, V>> queue = new LinkedList<>(); private boolean disableTestHooks; @@ -605,12 +598,11 @@ public class ConcurrentReferenceHashMapTests { protected ReferenceManager createReferenceManager() { return new ReferenceManager() { @Override - public Reference<K, V> createReference(Entry<K, V> entry, int hash, - Reference<K, V> next) { + public Reference<K, V> createReference(Entry<K, V> entry, int hash, Reference<K, V> next) { if (TestWeakConcurrentCache.this.disableTestHooks) { return super.createReference(entry, hash, next); } - return new MockReference<K, V>(entry, hash, next, TestWeakConcurrentCache.this.queue); + return new MockReference<>(entry, hash, next, TestWeakConcurrentCache.this.queue); } @Override public Reference<K, V> pollForPurge() { diff --git a/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java b/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java index 43420d36..f855a5f2 100644 --- a/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java +++ b/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -27,7 +27,7 @@ import org.junit.Test; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; -import static java.util.Collections.singletonMap; +import static java.util.Collections.*; import static org.junit.Assert.*; /** @@ -70,7 +70,7 @@ public class MimeTypeTests { } @Test - public void parseCharset() throws Exception { + public void parseCharset() { String s = "text/html; charset=iso-8859-1"; MimeType mimeType = MimeType.valueOf(s); assertEquals("Invalid type", "text", mimeType.getType()); @@ -106,7 +106,7 @@ public class MimeTypeTests { } @Test - public void includes() throws Exception { + public void includes() { MimeType textPlain = MimeTypeUtils.TEXT_PLAIN; assertTrue("Equal types is not inclusive", textPlain.includes(textPlain)); MimeType allText = new MimeType("text"); @@ -133,7 +133,7 @@ public class MimeTypeTests { } @Test - public void isCompatible() throws Exception { + public void isCompatible() { MimeType textPlain = MimeTypeUtils.TEXT_PLAIN; assertTrue("Equal types is not compatible", textPlain.isCompatibleWith(textPlain)); MimeType allText = new MimeType("text"); @@ -160,14 +160,14 @@ public class MimeTypeTests { } @Test - public void testToString() throws Exception { + public void testToString() { MimeType mimeType = new MimeType("text", "plain"); String result = mimeType.toString(); assertEquals("Invalid toString() returned", "text/plain", result); } @Test - public void parseMimeType() throws Exception { + public void parseMimeType() { String s = "audio/*"; MimeType mimeType = MimeTypeUtils.parseMimeType(s); assertEquals("Invalid type", "audio", mimeType.getType()); @@ -200,7 +200,7 @@ public class MimeTypeTests { } @Test(expected = InvalidMimeTypeException.class) - public void parseMimeTypeMissingTypeAndSubtype() throws Exception { + public void parseMimeTypeMissingTypeAndSubtype() { MimeTypeUtils.parseMimeType(" ;a=b"); } @@ -229,31 +229,37 @@ public class MimeTypeTests { MimeTypeUtils.parseMimeType("text/html; charset=foo-bar"); } - /** - * SPR-8917 - */ - @Test + @Test // SPR-8917 public void parseMimeTypeQuotedParameterValue() { MimeType mimeType = MimeTypeUtils.parseMimeType("audio/*;attr=\"v>alue\""); assertEquals("\"v>alue\"", mimeType.getParameter("attr")); } - /** - * SPR-8917 - */ - @Test + @Test // SPR-8917 public void parseMimeTypeSingleQuotedParameterValue() { MimeType mimeType = MimeTypeUtils.parseMimeType("audio/*;attr='v>alue'"); assertEquals("'v>alue'", mimeType.getParameter("attr")); } + @Test // SPR-16630 + public void parseMimeTypeWithSpacesAroundEquals() { + MimeType mimeType = MimeTypeUtils.parseMimeType("multipart/x-mixed-replace;boundary = --myboundary"); + assertEquals("--myboundary", mimeType.getParameter("boundary")); + } + + @Test // SPR-16630 + public void parseMimeTypeWithSpacesAroundEqualsAndQuotedValue() { + MimeType mimeType = MimeTypeUtils.parseMimeType("text/plain; foo = \" bar \" "); + assertEquals("\" bar \"", mimeType.getParameter("foo")); + } + @Test(expected = InvalidMimeTypeException.class) public void parseMimeTypeIllegalQuotedParameterValue() { MimeTypeUtils.parseMimeType("audio/*;attr=\""); } @Test - public void parseMimeTypes() throws Exception { + public void parseMimeTypes() { String s = "text/plain, text/html, text/x-dvi, text/x-c"; List<MimeType> mimeTypes = MimeTypeUtils.parseMimeTypes(s); assertNotNull("No mime types returned", mimeTypes); @@ -325,6 +331,8 @@ public class MimeTypeTests { MimeType m2 = new MimeType("text", "plain", singletonMap("charset", "utf-8")); assertEquals(m1, m2); assertEquals(m2, m1); + assertEquals(0, m1.compareTo(m2)); + assertEquals(0, m2.compareTo(m1)); } } diff --git a/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java index 07bc3a0d..d11ea1f7 100644 --- a/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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,10 +60,10 @@ public class ObjectUtilsTests { @Test public void isCompatibleWithThrowsClause() { - Class<?>[] empty = new Class[0]; - Class<?>[] exception = new Class[] {Exception.class}; - Class<?>[] sqlAndIO = new Class[] {SQLException.class, IOException.class}; - Class<?>[] throwable = new Class[] {Throwable.class}; + Class<?>[] empty = new Class<?>[0]; + Class<?>[] exception = new Class<?>[] {Exception.class}; + Class<?>[] sqlAndIO = new Class<?>[] {SQLException.class, IOException.class}; + Class<?>[] throwable = new Class<?>[] {Throwable.class}; assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException())); assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), empty)); @@ -110,7 +110,7 @@ public class ObjectUtilsTests { assertTrue(isEmpty(Collections.emptyList())); assertTrue(isEmpty(Collections.emptySet())); - Set<String> set = new HashSet<String>(); + Set<String> set = new HashSet<>(); set.add("foo"); assertFalse(isEmpty(set)); assertFalse(isEmpty(Arrays.asList("foo"))); @@ -120,7 +120,7 @@ public class ObjectUtilsTests { public void isEmptyMap() { assertTrue(isEmpty(Collections.emptyMap())); - HashMap<String, Object> map = new HashMap<String, Object>(); + HashMap<String, Object> map = new HashMap<>(); map.put("foo", 42L); assertFalse(isEmpty(map)); } @@ -239,18 +239,21 @@ public class ObjectUtilsTests { } @Test + @Deprecated public void hashCodeWithBooleanFalse() { int expected = Boolean.FALSE.hashCode(); assertEquals(expected, ObjectUtils.hashCode(false)); } @Test + @Deprecated public void hashCodeWithBooleanTrue() { int expected = Boolean.TRUE.hashCode(); assertEquals(expected, ObjectUtils.hashCode(true)); } @Test + @Deprecated public void hashCodeWithDouble() { double dbl = 9830.43; int expected = (new Double(dbl)).hashCode(); @@ -258,6 +261,7 @@ public class ObjectUtilsTests { } @Test + @Deprecated public void hashCodeWithFloat() { float flt = 34.8f; int expected = (new Float(flt)).hashCode(); @@ -265,6 +269,7 @@ public class ObjectUtilsTests { } @Test + @Deprecated public void hashCodeWithLong() { long lng = 883l; int expected = (new Long(lng)).hashCode(); diff --git a/spring-core/src/test/java/org/springframework/util/ReflectionUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ReflectionUtilsTests.java index 3c0c8f84..5cd04e36 100644 --- a/spring-core/src/test/java/org/springframework/util/ReflectionUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/ReflectionUtilsTests.java @@ -86,7 +86,7 @@ public class ReflectionUtilsTests { TestObject bean = new TestObject(); bean.setName(rob); - Method getName = TestObject.class.getMethod("getName", (Class[]) null); + Method getName = TestObject.class.getMethod("getName"); Method setName = TestObject.class.getMethod("setName", String.class); Object name = ReflectionUtils.invokeMethod(getName, bean); diff --git a/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java index 8ccffe38..61e996b4 100644 --- a/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -443,6 +443,7 @@ public class StringUtilsTests { } @Test + @Deprecated public void testMergeStringArrays() { String[] input1 = new String[] {"myString2"}; String[] input2 = new String[] {"myString1", "myString2"}; |