summaryrefslogtreecommitdiff
path: root/spring-core/src/main/java/org
diff options
context:
space:
mode:
authorEmmanuel Bourg <ebourg@apache.org>2018-04-08 23:27:38 +0200
committerEmmanuel Bourg <ebourg@apache.org>2018-04-08 23:27:38 +0200
commite9dafb5ce16aa2faa4fee1019417cc0a7456af57 (patch)
treec38471d22f5c367a45673724d3a6571d5daf591b /spring-core/src/main/java/org
parent6dc3d6835b664af0d21e774a5342b90d4417f628 (diff)
New upstream version 4.3.15
Diffstat (limited to 'spring-core/src/main/java/org')
-rw-r--r--spring-core/src/main/java/org/springframework/asm/ClassWriter.java2
-rw-r--r--spring-core/src/main/java/org/springframework/core/AttributeAccessorSupport.java5
-rw-r--r--spring-core/src/main/java/org/springframework/core/MethodParameter.java25
-rw-r--r--spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java13
-rw-r--r--spring-core/src/main/java/org/springframework/core/ResolvableType.java27
-rw-r--r--spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java42
-rw-r--r--spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java203
-rw-r--r--spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java74
-rw-r--r--spring-core/src/main/java/org/springframework/core/convert/Property.java6
-rw-r--r--spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java8
-rw-r--r--spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java4
-rw-r--r--spring-core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java6
-rw-r--r--spring-core/src/main/java/org/springframework/core/io/VfsUtils.java36
-rw-r--r--spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java4
-rw-r--r--spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java4
-rw-r--r--spring-core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java8
-rw-r--r--spring-core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java11
-rw-r--r--spring-core/src/main/java/org/springframework/util/ClassUtils.java28
-rw-r--r--spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java32
-rw-r--r--spring-core/src/main/java/org/springframework/util/DigestUtils.java2
-rw-r--r--spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java2
-rw-r--r--spring-core/src/main/java/org/springframework/util/MimeType.java114
-rw-r--r--spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java9
-rw-r--r--spring-core/src/main/java/org/springframework/util/ReflectionUtils.java5
-rw-r--r--spring-core/src/main/java/org/springframework/util/StreamUtils.java2
-rw-r--r--spring-core/src/main/java/org/springframework/util/StringUtils.java27
-rw-r--r--spring-core/src/main/java/org/springframework/util/concurrent/ListenableFutureCallbackRegistry.java12
-rw-r--r--spring-core/src/main/java/org/springframework/util/xml/AbstractStaxHandler.java2
-rw-r--r--spring-core/src/main/java/org/springframework/util/xml/DomContentHandler.java4
-rw-r--r--spring-core/src/main/java/org/springframework/util/xml/TransformerUtils.java32
30 files changed, 434 insertions, 315 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&lt;List&lt;String&gt;&gt; typeRef = new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;() {};
* </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>&#42;</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
*/