summaryrefslogtreecommitdiff
path: root/spring-beans/src/main/java/org/springframework/beans
diff options
context:
space:
mode:
authorEmmanuel Bourg <ebourg@apache.org>2016-08-03 19:55:01 +0200
committerEmmanuel Bourg <ebourg@apache.org>2016-08-03 19:55:01 +0200
commit75a721d1019da2a2fa86e24ff439df4a224e5b19 (patch)
tree2c44c00ce2c8641cccad177177e5682e187a17ea /spring-beans/src/main/java/org/springframework/beans
parent9eaca6a06af3cbceb3754de19d477be770614265 (diff)
Imported Upstream version 4.3.2
Diffstat (limited to 'spring-beans/src/main/java/org/springframework/beans')
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java10
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java2
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java2
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/BeanInstantiationException.java59
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/BeanUtils.java39
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java13
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java20
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/NullValueInNestedPathException.java15
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/PropertyAccessor.java14
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java16
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java9
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java8
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/BeanInitializationException.java6
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java6
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java167
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java15
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java61
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java46
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java6
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java210
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/annotation/BeanFactoryAnnotationUtils.java17
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java21
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java23
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java12
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java9
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java12
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java123
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.java22
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java59
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java2
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java14
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/PropertiesFactoryBean.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java9
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/config/Scope.java2
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java2
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java8
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java139
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java286
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java57
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java10
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java27
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java6
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomCollectionEditor.java6
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomMapEditor.java6
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/FileEditor.java10
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/InputStreamEditor.java8
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java116
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/ReaderEditor.java8
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java9
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/propertyeditors/URLEditor.java4
-rw-r--r--spring-beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java20
58 files changed, 1367 insertions, 436 deletions
diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java
index cf3ebd9a..f3e3bd14 100644
--- a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java
@@ -90,11 +90,11 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
private int autoGrowCollectionLimit = Integer.MAX_VALUE;
- private Object wrappedObject;
+ Object wrappedObject;
private String nestedPath = "";
- private Object rootObject;
+ Object rootObject;
/**
* Map with cached nested Accessors: nested path -> Accessor instance.
@@ -914,11 +914,9 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
return BeanUtils.instantiate(type);
}
}
- catch (Exception ex) {
- // TODO: Root cause exception context is lost here; just exception message preserved.
- // Should we throw another exception type that preserves context instead?
+ catch (Throwable ex) {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + name,
- "Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path: " + ex);
+ "Could not instantiate property type [" + type.getName() + "] to auto-grow nested property path", ex);
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java
index 07871217..216e5a4a 100644
--- a/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/AbstractPropertyAccessor.java
@@ -148,7 +148,7 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
* @throws InvalidPropertyException if there is no such property or
* if the property isn't writable
* @throws PropertyAccessException if the property was valid but the
- * accessor method failed or a type mismatch occured
+ * accessor method failed or a type mismatch occurred
*/
@Override
public abstract void setPropertyValue(String propertyName, Object value) throws BeansException;
diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java b/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java
index 1906fbfd..4c5fd27c 100644
--- a/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/BeanInfoFactory.java
@@ -24,7 +24,7 @@ import java.beans.IntrospectionException;
* Can be used to plug in custom bean property resolution strategies (e.g. for other
* languages on the JVM) or more efficient {@link BeanInfo} retrieval algorithms.
*
- * <p>BeanInfoFactories are are instantiated by the {@link CachedIntrospectionResults},
+ * <p>BeanInfoFactories are instantiated by the {@link CachedIntrospectionResults},
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader}
* utility class.
*
diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanInstantiationException.java b/spring-beans/src/main/java/org/springframework/beans/BeanInstantiationException.java
index 09190f6f..d8f7d246 100644
--- a/spring-beans/src/main/java/org/springframework/beans/BeanInstantiationException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/BeanInstantiationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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,9 @@
package org.springframework.beans;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
/**
* Exception thrown when instantiation of a bean failed.
* Carries the offending bean class.
@@ -28,6 +31,10 @@ public class BeanInstantiationException extends FatalBeanException {
private Class<?> beanClass;
+ private Constructor<?> constructor;
+
+ private Method constructingMethod;
+
/**
* Create a new BeanInstantiationException.
@@ -49,12 +56,60 @@ public class BeanInstantiationException extends FatalBeanException {
this.beanClass = beanClass;
}
+ /**
+ * Create a new BeanInstantiationException.
+ * @param constructor the offending constructor
+ * @param msg the detail message
+ * @param cause the root cause
+ * @since 4.3
+ */
+ public BeanInstantiationException(Constructor<?> constructor, String msg, Throwable cause) {
+ super("Failed to instantiate [" + constructor.getDeclaringClass().getName() + "]: " + msg, cause);
+ this.beanClass = constructor.getDeclaringClass();
+ this.constructor = constructor;
+ }
/**
- * Return the offending bean class.
+ * Create a new BeanInstantiationException.
+ * @param constructingMethod the delegate for bean construction purposes
+ * (typically, but not necessarily, a static factory method)
+ * @param msg the detail message
+ * @param cause the root cause
+ * @since 4.3
+ */
+ public BeanInstantiationException(Method constructingMethod, String msg, Throwable cause) {
+ super("Failed to instantiate [" + constructingMethod.getReturnType().getName() + "]: " + msg, cause);
+ this.beanClass = constructingMethod.getReturnType();
+ this.constructingMethod = constructingMethod;
+ }
+
+
+ /**
+ * Return the offending bean class (never {@code null}).
+ * @return the class that was to be instantiated
*/
public Class<?> getBeanClass() {
return this.beanClass;
}
+ /**
+ * Return the offending constructor, if known.
+ * @return the constructor in use, or {@code null} in case of a
+ * factory method or in case of default instantiation
+ * @since 4.3
+ */
+ public Constructor<?> getConstructor() {
+ return this.constructor;
+ }
+
+ /**
+ * Return the delegate for bean construction purposes, if known.
+ * @return the method in use (typically a static factory method),
+ * or {@code null} in case of constructor-based instantiation
+ * @since 4.3
+ */
+ public Method getConstructingMethod() {
+ return this.constructingMethod;
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java
index 5c735f16..50c04c3b 100644
--- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java
+++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java
@@ -63,11 +63,10 @@ public abstract class BeanUtils {
/**
* Convenience method to instantiate a class using its no-arg constructor.
- * As this method doesn't try to load classes by name, it should avoid
- * class-loading issues.
* @param clazz class to instantiate
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
+ * @see Class#newInstance()
*/
public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {
Assert.notNull(clazz, "Class must not be null");
@@ -87,13 +86,12 @@ public abstract class BeanUtils {
/**
* Instantiate a class using its no-arg constructor.
- * As this method doesn't try to load classes by name, it should avoid
- * class-loading issues.
* <p>Note that this method tries to set the constructor accessible
* if given a non-accessible (that is, non-public) constructor.
* @param clazz class to instantiate
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
+ * @see Constructor#newInstance
*/
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
Assert.notNull(clazz, "Class must not be null");
@@ -110,18 +108,16 @@ public abstract class BeanUtils {
/**
* Instantiate a class using its no-arg constructor and return the new instance
- * as the the specified assignable type.
- * <p>Useful in cases where
- * the type of the class to instantiate (clazz) is not available, but the type
- * desired (assignableTo) is known.
- * <p>As this method doesn't try to load classes by name, it should avoid
- * class-loading issues.
- * <p>Note that this method tries to set the constructor accessible
- * if given a non-accessible (that is, non-public) constructor.
+ * as the specified assignable type.
+ * <p>Useful in cases where the type of the class to instantiate (clazz) is not
+ * available, but the type desired (assignableTo) is known.
+ * <p>Note that this method tries to set the constructor accessible if given a
+ * non-accessible (that is, non-public) constructor.
* @param clazz class to instantiate
* @param assignableTo type that clazz must be assignableTo
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
+ * @see Constructor#newInstance
*/
@SuppressWarnings("unchecked")
public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
@@ -131,14 +127,13 @@ public abstract class BeanUtils {
/**
* Convenience method to instantiate a class using the given constructor.
- * As this method doesn't try to load classes by name, it should avoid
- * class-loading issues.
- * <p>Note that this method tries to set the constructor accessible
- * if given a non-accessible (that is, non-public) constructor.
+ * <p>Note that this method tries to set the constructor accessible if given a
+ * non-accessible (that is, non-public) constructor.
* @param ctor the constructor to instantiate
* @param args the constructor arguments to apply
* @return the new instance
* @throws BeanInstantiationException if the bean cannot be instantiated
+ * @see Constructor#newInstance
*/
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
@@ -147,20 +142,16 @@ public abstract class BeanUtils {
return ctor.newInstance(args);
}
catch (InstantiationException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Is it an abstract class?", ex);
+ throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Is the constructor accessible?", ex);
+ throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Illegal arguments for constructor", ex);
+ throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
- throw new BeanInstantiationException(ctor.getDeclaringClass(),
- "Constructor threw exception", ex.getTargetException());
+ throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java
index 6615661d..4d10dc0c 100644
--- a/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java
+++ b/spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java
@@ -133,6 +133,19 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
}
+ /**
+ * Set a bean instance to hold, without any unwrapping of {@link java.util.Optional}.
+ * @param object the actual target object
+ * @since 4.3
+ * @see #setWrappedInstance(Object)
+ */
+ public void setBeanInstance(Object object) {
+ this.wrappedObject = object;
+ this.rootObject = object;
+ this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject);
+ setIntrospectionClass(object.getClass());
+ }
+
@Override
public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
super.setWrappedInstance(object, nestedPath, rootObject);
diff --git a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java b/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java
index 41c2f4c5..2efe9dab 100644
--- a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java
+++ b/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -303,6 +303,24 @@ public class CachedIntrospectionResults {
this.propertyDescriptorCache.put(pd.getName(), pd);
}
+ // Explicitly check implemented interfaces for setter/getter methods as well,
+ // in particular for Java 8 default methods...
+ Class<?> clazz = beanClass;
+ while (clazz != null) {
+ Class<?>[] ifcs = clazz.getInterfaces();
+ for (Class<?> ifc : ifcs) {
+ BeanInfo ifcInfo = Introspector.getBeanInfo(ifc, Introspector.IGNORE_ALL_BEANINFO);
+ PropertyDescriptor[] ifcPds = ifcInfo.getPropertyDescriptors();
+ for (PropertyDescriptor pd : ifcPds) {
+ if (!this.propertyDescriptorCache.containsKey(pd.getName())) {
+ pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
+ this.propertyDescriptorCache.put(pd.getName(), pd);
+ }
+ }
+ }
+ clazz = clazz.getSuperclass();
+ }
+
this.typeDescriptorCache = new ConcurrentReferenceHashMap<PropertyDescriptor, TypeDescriptor>();
}
catch (IntrospectionException ex) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/NullValueInNestedPathException.java b/spring-beans/src/main/java/org/springframework/beans/NullValueInNestedPathException.java
index e01fafbf..e15885bc 100644
--- a/spring-beans/src/main/java/org/springframework/beans/NullValueInNestedPathException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/NullValueInNestedPathException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ package org.springframework.beans;
* spouse property of the target object has a null value.
*
* @author Rod Johnson
+ * @author Juergen Hoeller
*/
@SuppressWarnings("serial")
public class NullValueInNestedPathException extends InvalidPropertyException {
@@ -47,4 +48,16 @@ public class NullValueInNestedPathException extends InvalidPropertyException {
super(beanClass, propertyName, msg);
}
+ /**
+ * Create a new NullValueInNestedPathException.
+ * @param beanClass the offending bean class
+ * @param propertyName the offending property
+ * @param msg the detail message
+ * @param cause the root cause
+ * @since 4.3.2
+ */
+ public NullValueInNestedPathException(Class<?> beanClass, String propertyName, String msg, Throwable cause) {
+ super(beanClass, propertyName, msg, cause);
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/PropertyAccessor.java
index 00068ea4..c7faf355 100644
--- a/spring-beans/src/main/java/org/springframework/beans/PropertyAccessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/PropertyAccessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -120,7 +120,7 @@ public interface PropertyAccessor {
* @throws InvalidPropertyException if there is no such property or
* if the property isn't writable
* @throws PropertyAccessException if the property was valid but the
- * accessor method failed or a type mismatch occured
+ * accessor method failed or a type mismatch occurred
*/
void setPropertyValue(String propertyName, Object value) throws BeansException;
@@ -130,7 +130,7 @@ public interface PropertyAccessor {
* @throws InvalidPropertyException if there is no such property or
* if the property isn't writable
* @throws PropertyAccessException if the property was valid but the
- * accessor method failed or a type mismatch occured
+ * accessor method failed or a type mismatch occurred
*/
void setPropertyValue(PropertyValue pv) throws BeansException;
@@ -144,7 +144,7 @@ public interface PropertyAccessor {
* @throws InvalidPropertyException if there is no such property or
* if the property isn't writable
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
- * occured for specific properties during the batch update. This exception bundles
+ * occurred for specific properties during the batch update. This exception bundles
* all individual PropertyAccessExceptions. All other properties will have been
* successfully updated.
*/
@@ -164,7 +164,7 @@ public interface PropertyAccessor {
* @throws InvalidPropertyException if there is no such property or
* if the property isn't writable
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
- * occured for specific properties during the batch update. This exception bundles
+ * occurred for specific properties during the batch update. This exception bundles
* all individual PropertyAccessExceptions. All other properties will have been
* successfully updated.
* @see #setPropertyValues(PropertyValues, boolean, boolean)
@@ -185,7 +185,7 @@ public interface PropertyAccessor {
* @throws InvalidPropertyException if there is no such property or
* if the property isn't writable
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
- * occured for specific properties during the batch update. This exception bundles
+ * occurred for specific properties during the batch update. This exception bundles
* all individual PropertyAccessExceptions. All other properties will have been
* successfully updated.
* @see #setPropertyValues(PropertyValues, boolean, boolean)
@@ -208,7 +208,7 @@ public interface PropertyAccessor {
* @throws InvalidPropertyException if there is no such property or
* if the property isn't writable
* @throws PropertyBatchUpdateException if one or more PropertyAccessExceptions
- * occured for specific properties during the batch update. This exception bundles
+ * occurred for specific properties during the batch update. This exception bundles
* all individual PropertyAccessExceptions. All other properties will have been
* successfully updated.
*/
diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
index f42d6c33..71825c38 100644
--- a/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
+++ b/spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
@@ -59,6 +59,7 @@ import org.springframework.beans.propertyeditors.FileEditor;
import org.springframework.beans.propertyeditors.InputSourceEditor;
import org.springframework.beans.propertyeditors.InputStreamEditor;
import org.springframework.beans.propertyeditors.LocaleEditor;
+import org.springframework.beans.propertyeditors.PathEditor;
import org.springframework.beans.propertyeditors.PatternEditor;
import org.springframework.beans.propertyeditors.PropertiesEditor;
import org.springframework.beans.propertyeditors.ReaderEditor;
@@ -87,11 +88,21 @@ import org.springframework.util.ClassUtils;
*/
public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
+ private static Class<?> pathClass;
+
private static Class<?> zoneIdClass;
static {
+ ClassLoader cl = PropertyEditorRegistrySupport.class.getClassLoader();
+ try {
+ pathClass = ClassUtils.forName("java.nio.file.Path", cl);
+ }
+ catch (ClassNotFoundException ex) {
+ // Java 7 Path class not available
+ pathClass = null;
+ }
try {
- zoneIdClass = ClassUtils.forName("java.time.ZoneId", PropertyEditorRegistrySupport.class.getClassLoader());
+ zoneIdClass = ClassUtils.forName("java.time.ZoneId", cl);
}
catch (ClassNotFoundException ex) {
// Java 8 ZoneId class not available
@@ -211,6 +222,9 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
+ if (pathClass != null) {
+ this.defaultEditors.put(pathClass, new PathEditor());
+ }
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Reader.class, new ReaderEditor());
diff --git a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java
index dd63e8e9..908bfeaf 100644
--- a/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java
+++ b/spring-beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java
@@ -186,8 +186,11 @@ class TypeConverterDelegate {
if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
convertedValue instanceof String) {
TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
- if (elementTypeDesc != null && Enum.class.isAssignableFrom(elementTypeDesc.getType())) {
- convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
+ if (elementTypeDesc != null) {
+ Class<?> elementType = elementTypeDesc.getType();
+ if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
+ convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
+ }
}
}
if (editor == null) {
@@ -266,7 +269,7 @@ class TypeConverterDelegate {
}
else {
// convertedValue == null
- if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
+ if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
convertedValue = javaUtilOptionalEmpty;
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java
index f0c2fa1d..75a38386 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanCreationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@ public class BeanCreationException extends FatalBeanException {
* @param msg the detail message
*/
public BeanCreationException(String beanName, String msg) {
- super("Error creating bean with name '" + beanName + "': " + msg);
+ super("Error creating bean" + (beanName != null ? " with name '" + beanName + "'" : "") + ": " + msg);
this.beanName = beanName;
}
@@ -86,7 +86,7 @@ public class BeanCreationException extends FatalBeanException {
* @param msg the detail message
*/
public BeanCreationException(String resourceDescription, String beanName, String msg) {
- super("Error creating bean with name '" + beanName + "'" +
+ super("Error creating bean" + (beanName != null ? " with name '" + beanName + "'" : "") +
(resourceDescription != null ? " defined in " + resourceDescription : "") + ": " + msg);
this.resourceDescription = resourceDescription;
this.beanName = beanName;
@@ -123,7 +123,7 @@ public class BeanCreationException extends FatalBeanException {
/**
* Add a related cause to this bean creation exception,
- * not being a direct cause of the failure but having occured
+ * not being a direct cause of the failure but having occurred
* earlier in the creation of the same bean instance.
* @param ex the related cause to add
*/
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
index 3c6bd4c8..58b2fd97 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java
@@ -188,12 +188,12 @@ public interface BeanFactory {
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
- * @param requiredType type the bean must match; can be an interface or superclass.
- * {@code null} is disallowed.
* <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
* but may also be translated into a conventional by-name lookup based on the name
* of the given type. For more extensive retrieval operations across sets of beans,
* use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
+ * @param requiredType type the bean must match; can be an interface or superclass.
+ * {@code null} is disallowed.
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @return an instance of the bean
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanInitializationException.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanInitializationException.java
index c52d0ae7..5c5ed79c 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanInitializationException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanInitializationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -23,8 +23,8 @@ import org.springframework.beans.FatalBeanException;
* factory-aware initialization code fails. BeansExceptions thrown by
* bean factory methods themselves should simply be propagated as-is.
*
- * <p>Note that non-factory-aware initialization methods like afterPropertiesSet()
- * or a custom "init-method" can throw any exception.
+ * <p>Note that {@code afterPropertiesSet()} or a custom "init-method"
+ * can throw any exception.
*
* @author Juergen Hoeller
* @since 13.11.2003
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java
index bd6d33fb..6f98f435 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanNotOfRequiredTypeException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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,8 +45,8 @@ public class BeanNotOfRequiredTypeException extends BeansException {
* the expected type
*/
public BeanNotOfRequiredTypeException(String beanName, Class<?> requiredType, Class<?> actualType) {
- super("Bean named '" + beanName + "' must be of type [" + requiredType.getName() +
- "], but was actually of type [" + actualType.getName() + "]");
+ super("Bean named '" + beanName + "' is expected to be of type [" + requiredType.getName() +
+ "] but was actually of type [" + actualType.getName() + "]");
this.beanName = beanName;
this.requiredType = requiredType;
this.actualType = actualType;
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java b/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java
new file mode 100644
index 00000000..0a3d55a9
--- /dev/null
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/InjectionPoint.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.beans.factory;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.util.Assert;
+
+/**
+ * A simple descriptor for an injection point, pointing to a method/constructor
+ * parameter or a field. Exposed by {@link UnsatisfiedDependencyException}.
+ *
+ * @author Juergen Hoeller
+ * @since 4.3
+ * @see UnsatisfiedDependencyException#getInjectionPoint()
+ * @see org.springframework.beans.factory.config.DependencyDescriptor
+ */
+public class InjectionPoint {
+
+ protected MethodParameter methodParameter;
+
+ protected Field field;
+
+ private volatile Annotation[] fieldAnnotations;
+
+
+ /**
+ * Create an injection point descriptor for a method or constructor parameter.
+ * @param methodParameter the MethodParameter to wrap
+ */
+ public InjectionPoint(MethodParameter methodParameter) {
+ Assert.notNull(methodParameter, "MethodParameter must not be null");
+ this.methodParameter = methodParameter;
+ }
+
+ /**
+ * Create an injection point descriptor for a field.
+ * @param field the field to wrap
+ */
+ public InjectionPoint(Field field) {
+ Assert.notNull(field, "Field must not be null");
+ this.field = field;
+ }
+
+ /**
+ * Copy constructor.
+ * @param original the original descriptor to create a copy from
+ */
+ protected InjectionPoint(InjectionPoint original) {
+ this.methodParameter = (original.methodParameter != null ?
+ new MethodParameter(original.methodParameter) : null);
+ this.field = original.field;
+ this.fieldAnnotations = original.fieldAnnotations;
+ }
+
+ /**
+ * Just available for serialization purposes in subclasses.
+ */
+ protected InjectionPoint() {
+ }
+
+
+ /**
+ * Return the wrapped MethodParameter, if any.
+ * <p>Note: Either MethodParameter or Field is available.
+ * @return the MethodParameter, or {@code null} if none
+ */
+ public MethodParameter getMethodParameter() {
+ return this.methodParameter;
+ }
+
+ /**
+ * Return the wrapped Field, if any.
+ * <p>Note: Either MethodParameter or Field is available.
+ * @return the Field, or {@code null} if none
+ */
+ public Field getField() {
+ return this.field;
+ }
+
+ /**
+ * Obtain the annotations associated with the wrapped field or method/constructor parameter.
+ */
+ public Annotation[] getAnnotations() {
+ if (this.field != null) {
+ if (this.fieldAnnotations == null) {
+ this.fieldAnnotations = this.field.getAnnotations();
+ }
+ return this.fieldAnnotations;
+ }
+ else {
+ return this.methodParameter.getParameterAnnotations();
+ }
+ }
+
+ /**
+ * Return the type declared by the underlying field or method/constructor parameter,
+ * indicating the injection type.
+ */
+ public Class<?> getDeclaredType() {
+ return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType());
+ }
+
+ /**
+ * Returns the wrapped member, containing the injection point.
+ * @return the Field / Method / Constructor as Member
+ */
+ public Member getMember() {
+ return (this.field != null ? this.field : this.methodParameter.getMember());
+ }
+
+ /**
+ * Return the wrapped annotated element.
+ * <p>Note: In case of a method/constructor parameter, this exposes
+ * the annotations declared on the method or constructor itself
+ * (i.e. at the method/constructor level, not at the parameter level).
+ * Use {@link #getAnnotations()} to obtain parameter-level annotations in
+ * such a scenario, transparently with corresponding field annotations.
+ * @return the Field / Method / Constructor as AnnotatedElement
+ */
+ public AnnotatedElement getAnnotatedElement() {
+ return (this.field != null ? this.field : this.methodParameter.getAnnotatedElement());
+ }
+
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (getClass() != other.getClass()) {
+ return false;
+ }
+ InjectionPoint otherPoint = (InjectionPoint) other;
+ return (this.field != null ? this.field.equals(otherPoint.field) :
+ this.methodParameter.equals(otherPoint.methodParameter));
+ }
+
+ @Override
+ public int hashCode() {
+ return (this.field != null ? this.field.hashCode() : this.methodParameter.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ return (this.field != null ? "field '" + this.field.getName() + "'" : this.methodParameter.toString());
+ }
+
+}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java b/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java
index 7db0bae6..6bb4f6db 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/NoUniqueBeanDefinitionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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,8 @@ public class NoUniqueBeanDefinitionException extends NoSuchBeanDefinitionExcepti
private int numberOfBeansFound;
+ private Collection<String> beanNamesFound;
+
/**
* Create a new {@code NoUniqueBeanDefinitionException}.
@@ -54,6 +56,7 @@ public class NoUniqueBeanDefinitionException extends NoSuchBeanDefinitionExcepti
public NoUniqueBeanDefinitionException(Class<?> type, Collection<String> beanNamesFound) {
this(type, beanNamesFound.size(), "expected single matching bean but found " + beanNamesFound.size() + ": " +
StringUtils.collectionToCommaDelimitedString(beanNamesFound));
+ this.beanNamesFound = beanNamesFound;
}
/**
@@ -76,4 +79,14 @@ public class NoUniqueBeanDefinitionException extends NoSuchBeanDefinitionExcepti
return this.numberOfBeansFound;
}
+ /**
+ * Return the names of all beans found when only one matching bean was expected.
+ * Note that this may be {@code null} if not specified at construction time.
+ * @since 4.3
+ * @see #getBeanType()
+ */
+ public Collection<String> getBeanNamesFound() {
+ return this.beanNamesFound;
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java
new file mode 100644
index 00000000..ffa2683e
--- /dev/null
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.beans.factory;
+
+import org.springframework.beans.BeansException;
+
+/**
+ * A variant of {@link ObjectFactory} designed specifically for injection points,
+ * allowing for programmatic optionality and lenient not-unique handling.
+ *
+ * @author Juergen Hoeller
+ * @since 4.3
+ */
+public interface ObjectProvider<T> extends ObjectFactory<T> {
+
+ /**
+ * Return an instance (possibly shared or independent) of the object
+ * managed by this factory.
+ * <p>Allows for specifying explicit construction arguments, along the
+ * lines of {@link BeanFactory#getBean(String, Object...)}.
+ * @param args arguments to use when creating a corresponding instance
+ * @return an instance of the bean
+ * @throws BeansException in case of creation errors
+ * @see #getObject()
+ */
+ T getObject(Object... args) throws BeansException;
+
+ /**
+ * Return an instance (possibly shared or independent) of the object
+ * managed by this factory.
+ * @return an instance of the bean, or {@code null} if not available
+ * @throws BeansException in case of creation errors
+ * @see #getObject()
+ */
+ T getIfAvailable() throws BeansException;
+
+ /**
+ * Return an instance (possibly shared or independent) of the object
+ * managed by this factory.
+ * @return an instance of the bean, or {@code null} if not available or
+ * not unique (i.e. multiple candidates found with none marked as primary)
+ * @throws BeansException in case of creation errors
+ * @see #getObject()
+ */
+ T getIfUnique() throws BeansException;
+
+}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java b/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java
index 9ec35a7e..0403abfc 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/UnsatisfiedDependencyException.java
@@ -31,6 +31,9 @@ import org.springframework.util.ClassUtils;
@SuppressWarnings("serial")
public class UnsatisfiedDependencyException extends BeanCreationException {
+ private InjectionPoint injectionPoint;
+
+
/**
* Create a new UnsatisfiedDependencyException.
* @param resourceDescription description of the resource that the bean definition came from
@@ -64,10 +67,42 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
* Create a new UnsatisfiedDependencyException.
* @param resourceDescription description of the resource that the bean definition came from
* @param beanName the name of the bean requested
+ * @param injectionPoint the injection point (field or method/constructor parameter)
+ * @param msg the detail message
+ * @since 4.3
+ */
+ public UnsatisfiedDependencyException(
+ String resourceDescription, String beanName, InjectionPoint injectionPoint, String msg) {
+
+ super(resourceDescription, beanName, "Unsatisfied dependency expressed through " + injectionPoint + ": " + msg);
+ this.injectionPoint = injectionPoint;
+ }
+
+ /**
+ * Create a new UnsatisfiedDependencyException.
+ * @param resourceDescription description of the resource that the bean definition came from
+ * @param beanName the name of the bean requested
+ * @param injectionPoint the injection point (field or method/constructor parameter)
+ * @param ex the bean creation exception that indicated the unsatisfied dependency
+ * @since 4.3
+ */
+ public UnsatisfiedDependencyException(
+ String resourceDescription, String beanName, InjectionPoint injectionPoint, BeansException ex) {
+
+ this(resourceDescription, beanName, injectionPoint, (ex != null ? ex.getMessage() : ""));
+ initCause(ex);
+ }
+
+ /**
+ * Create a new UnsatisfiedDependencyException.
+ * @param resourceDescription description of the resource that the bean definition came from
+ * @param beanName the name of the bean requested
* @param ctorArgIndex the index of the constructor argument that couldn't be satisfied
* @param ctorArgType the type of the constructor argument that couldn't be satisfied
* @param msg the detail message
+ * @deprecated in favor of {@link #UnsatisfiedDependencyException(String, String, InjectionPoint, String)}
*/
+ @Deprecated
public UnsatisfiedDependencyException(
String resourceDescription, String beanName, int ctorArgIndex, Class<?> ctorArgType, String msg) {
@@ -84,7 +119,9 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
* @param ctorArgIndex the index of the constructor argument that couldn't be satisfied
* @param ctorArgType the type of the constructor argument that couldn't be satisfied
* @param ex the bean creation exception that indicated the unsatisfied dependency
+ * @deprecated in favor of {@link #UnsatisfiedDependencyException(String, String, InjectionPoint, BeansException)}
*/
+ @Deprecated
public UnsatisfiedDependencyException(
String resourceDescription, String beanName, int ctorArgIndex, Class<?> ctorArgType, BeansException ex) {
@@ -92,4 +129,13 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
initCause(ex);
}
+
+ /**
+ * Return the injection point (field or method/constructor parameter), if known.
+ * @since 4.3
+ */
+ public InjectionPoint getInjectionPoint() {
+ return this.injectionPoint;
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java b/spring-beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java
index d7758bc1..45be7328 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/access/SingletonBeanFactoryLocator.java
@@ -88,7 +88,7 @@ import org.springframework.core.io.support.ResourcePatternUtils;
* use object from a BeanFactory/ApplicationContext. One solutions is to make the
* class created by the third party code be just a stub or proxy, which gets the
* real object from a BeanFactory/ApplicationContext, and delegates to it. However,
- * it is is not normally workable for the stub to create the BeanFactory on each
+ * it is not normally workable for the stub to create the BeanFactory on each
* use, as depending on what is inside it, that can be an expensive operation.
* Additionally, there is a fairly tight coupling between the stub and the name of
* the definition resource for the BeanFactory/ApplicationContext. This is where
@@ -291,7 +291,7 @@ public class SingletonBeanFactoryLocator implements BeanFactoryLocator {
}
/**
- * Returns an instance which uses the the specified selector, as the name of the
+ * Returns an instance which uses the specified selector, as the name of the
* definition file(s). In the case of a name with a Spring 'classpath*:' prefix,
* or with no prefix, which is treated the same, the current thread context
* ClassLoader's {@code getResources} method will be called with this value
@@ -341,7 +341,7 @@ public class SingletonBeanFactoryLocator implements BeanFactoryLocator {
/**
- * Constructor which uses the the specified name as the resource name
+ * Constructor which uses the specified name as the resource name
* of the definition file(s).
* @param resourceLocation the Spring resource location to use
* (either a URL or a "classpath:" / "classpath*:" pseudo URL)
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java
index fc8b49bc..73779365 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/Autowired.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -64,7 +64,7 @@ import java.lang.annotation.Target;
* @see Qualifier
* @see Value
*/
-@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
index c008a796..258f66bf 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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,11 +45,12 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
-import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.LookupOverride;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -107,6 +108,7 @@ import org.springframework.util.StringUtils;
*
* @author Juergen Hoeller
* @author Mark Fisher
+ * @author Stephane Nicoll
* @since 2.5
* @see #setAutowiredAnnotationType
* @see Autowired
@@ -270,6 +272,19 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
Constructor<?> defaultConstructor = null;
for (Constructor<?> candidate : rawCandidates) {
AnnotationAttributes ann = findAutowiredAnnotation(candidate);
+ if (ann == null) {
+ Class<?> userClass = ClassUtils.getUserClass(beanClass);
+ if (userClass != beanClass) {
+ try {
+ Constructor<?> superCtor =
+ userClass.getDeclaredConstructor(candidate.getParameterTypes());
+ ann = findAutowiredAnnotation(superCtor);
+ }
+ catch (NoSuchMethodException ex) {
+ // Simply proceed, no equivalent superclass constructor found...
+ }
+ }
+ }
if (ann != null) {
if (requiredConstructor != null) {
throw new BeanCreationException(beanName,
@@ -312,6 +327,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
}
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
}
+ else if (rawCandidates.length == 1 && rawCandidates[0].getParameterTypes().length > 0) {
+ candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
+ }
else {
candidateConstructors = new Constructor<?>[0];
}
@@ -330,6 +348,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
try {
metadata.inject(bean, beanName, pvs);
}
+ catch (BeanCreationException ex) {
+ throw ex;
+ }
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
@@ -348,6 +369,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
try {
metadata.inject(bean, null, null);
}
+ catch (BeanCreationException ex) {
+ throw ex;
+ }
catch (Throwable ex) {
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
}
@@ -504,9 +528,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
}
- else if (cachedArgument instanceof RuntimeBeanReference) {
- return this.beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
- }
else {
return cachedArgument;
}
@@ -532,45 +553,46 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
- try {
- Object value;
- if (this.cached) {
- value = resolvedCachedArgument(beanName, this.cachedFieldValue);
- }
- else {
- DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
- desc.setContainingClass(bean.getClass());
- Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
- TypeConverter typeConverter = beanFactory.getTypeConverter();
+ Object value;
+ if (this.cached) {
+ value = resolvedCachedArgument(beanName, this.cachedFieldValue);
+ }
+ else {
+ DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
+ desc.setContainingClass(bean.getClass());
+ Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
+ TypeConverter typeConverter = beanFactory.getTypeConverter();
+ try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
- synchronized (this) {
- if (!this.cached) {
- if (value != null || this.required) {
- this.cachedFieldValue = desc;
- registerDependentBeans(beanName, autowiredBeanNames);
- if (autowiredBeanNames.size() == 1) {
- String autowiredBeanName = autowiredBeanNames.iterator().next();
- if (beanFactory.containsBean(autowiredBeanName)) {
- if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
- this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName);
- }
+ }
+ catch (BeansException ex) {
+ throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
+ }
+ synchronized (this) {
+ if (!this.cached) {
+ if (value != null || this.required) {
+ this.cachedFieldValue = desc;
+ registerDependentBeans(beanName, autowiredBeanNames);
+ if (autowiredBeanNames.size() == 1) {
+ String autowiredBeanName = autowiredBeanNames.iterator().next();
+ if (beanFactory.containsBean(autowiredBeanName)) {
+ if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
+ this.cachedFieldValue = new ShortcutDependencyDescriptor(
+ desc, autowiredBeanName, field.getType());
}
}
}
- else {
- this.cachedFieldValue = null;
- }
- this.cached = true;
}
+ else {
+ this.cachedFieldValue = null;
+ }
+ this.cached = true;
}
}
- if (value != null) {
- ReflectionUtils.makeAccessible(field);
- field.set(bean, value);
- }
}
- catch (Throwable ex) {
- throw new BeanCreationException("Could not autowire field: " + field, ex);
+ if (value != null) {
+ ReflectionUtils.makeAccessible(field);
+ field.set(bean, value);
}
}
}
@@ -598,67 +620,70 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
return;
}
Method method = (Method) this.member;
- try {
- Object[] arguments;
- if (this.cached) {
- // Shortcut for avoiding synchronization...
- arguments = resolveCachedArguments(beanName);
- }
- else {
- Class<?>[] paramTypes = method.getParameterTypes();
- arguments = new Object[paramTypes.length];
- DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
- Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
- TypeConverter typeConverter = beanFactory.getTypeConverter();
- for (int i = 0; i < arguments.length; i++) {
- MethodParameter methodParam = new MethodParameter(method, i);
- DependencyDescriptor desc = new DependencyDescriptor(methodParam, this.required);
- desc.setContainingClass(bean.getClass());
- descriptors[i] = desc;
- Object arg = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
+ Object[] arguments;
+ if (this.cached) {
+ // Shortcut for avoiding synchronization...
+ arguments = resolveCachedArguments(beanName);
+ }
+ else {
+ Class<?>[] paramTypes = method.getParameterTypes();
+ arguments = new Object[paramTypes.length];
+ DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
+ Set<String> autowiredBeanNames = new LinkedHashSet<String>(paramTypes.length);
+ TypeConverter typeConverter = beanFactory.getTypeConverter();
+ for (int i = 0; i < arguments.length; i++) {
+ MethodParameter methodParam = new MethodParameter(method, i);
+ DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
+ currDesc.setContainingClass(bean.getClass());
+ descriptors[i] = currDesc;
+ try {
+ Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
}
- synchronized (this) {
- if (!this.cached) {
- if (arguments != null) {
- this.cachedMethodArguments = new Object[arguments.length];
- for (int i = 0; i < arguments.length; i++) {
- this.cachedMethodArguments[i] = descriptors[i];
- }
- registerDependentBeans(beanName, autowiredBeanNames);
- if (autowiredBeanNames.size() == paramTypes.length) {
- Iterator<String> it = autowiredBeanNames.iterator();
- for (int i = 0; i < paramTypes.length; i++) {
- String autowiredBeanName = it.next();
- if (beanFactory.containsBean(autowiredBeanName)) {
- if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
- this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName);
- }
+ catch (BeansException ex) {
+ throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
+ }
+ }
+ synchronized (this) {
+ if (!this.cached) {
+ if (arguments != null) {
+ this.cachedMethodArguments = new Object[paramTypes.length];
+ for (int i = 0; i < arguments.length; i++) {
+ this.cachedMethodArguments[i] = descriptors[i];
+ }
+ registerDependentBeans(beanName, autowiredBeanNames);
+ if (autowiredBeanNames.size() == paramTypes.length) {
+ Iterator<String> it = autowiredBeanNames.iterator();
+ for (int i = 0; i < paramTypes.length; i++) {
+ String autowiredBeanName = it.next();
+ if (beanFactory.containsBean(autowiredBeanName)) {
+ if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
+ this.cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
+ descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
}
- else {
- this.cachedMethodArguments = null;
- }
- this.cached = true;
}
+ else {
+ this.cachedMethodArguments = null;
+ }
+ this.cached = true;
}
}
- if (arguments != null) {
+ }
+ if (arguments != null) {
+ try {
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
}
- }
- catch (InvocationTargetException ex) {
- throw ex.getTargetException();
- }
- catch (Throwable ex) {
- throw new BeanCreationException("Could not autowire method: " + method, ex);
+ catch (InvocationTargetException ex){
+ throw ex.getTargetException();
+ }
}
}
@@ -674,4 +699,27 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
}
}
+
+ /**
+ * DependencyDescriptor variant with a pre-resolved target bean name.
+ */
+ @SuppressWarnings("serial")
+ private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
+
+ private final String shortcutName;
+
+ private final Class<?> requiredType;
+
+ public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcutName, Class<?> requiredType) {
+ super(original);
+ this.shortcutName = shortcutName;
+ this.requiredType = requiredType;
+ }
+
+ @Override
+ public Object resolveShortcut(BeanFactory beanFactory) {
+ return resolveCandidate(this.shortcutName, this.requiredType, beanFactory);
+ }
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/BeanFactoryAnnotationUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/BeanFactoryAnnotationUtils.java
index eb691a14..65901004 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/BeanFactoryAnnotationUtils.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/BeanFactoryAnnotationUtils.java
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ObjectUtils;
/**
@@ -113,6 +114,7 @@ public class BeanFactoryAnnotationUtils {
if (bf.containsBean(beanName)) {
try {
BeanDefinition bd = bf.getMergedBeanDefinition(beanName);
+ // Explicit qualifier metadata on bean definition? (typically in XML definition)
if (bd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
AutowireCandidateQualifier candidate = abd.getQualifier(Qualifier.class.getName());
@@ -121,15 +123,24 @@ public class BeanFactoryAnnotationUtils {
return true;
}
}
+ // Corresponding qualifier on factory method? (typically in configuration class)
if (bd instanceof RootBeanDefinition) {
Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod();
if (factoryMethod != null) {
- Qualifier targetAnnotation = factoryMethod.getAnnotation(Qualifier.class);
- if (targetAnnotation != null && qualifier.equals(targetAnnotation.value())) {
- return true;
+ Qualifier targetAnnotation = AnnotationUtils.getAnnotation(factoryMethod, Qualifier.class);
+ if (targetAnnotation != null) {
+ return qualifier.equals(targetAnnotation.value());
}
}
}
+ // Corresponding qualifier on bean implementation class? (for custom user types)
+ Class<?> beanType = bf.getType(beanName);
+ if (beanType != null) {
+ Qualifier targetAnnotation = AnnotationUtils.getAnnotation(beanType, Qualifier.class);
+ if (targetAnnotation != null) {
+ return qualifier.equals(targetAnnotation.value());
+ }
+ }
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - can't compare qualifiers for a manually registered singleton object
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java
index 3c7c0577..37433239 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java
@@ -136,7 +136,7 @@ public class InitDestroyAnnotationBeanPostProcessor
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
- throw new BeanCreationException(beanName, "Couldn't invoke init method", ex);
+ throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
@@ -162,10 +162,15 @@ public class InitDestroyAnnotationBeanPostProcessor
}
}
catch (Throwable ex) {
- logger.error("Couldn't invoke destroy method on bean with name '" + beanName + "'", ex);
+ logger.error("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
}
}
+ @Override
+ public boolean requiresDestruction(Object bean) {
+ return findLifecycleMetadata(bean.getClass()).hasDestroyMethods();
+ }
+
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
@@ -308,11 +313,11 @@ public class InitDestroyAnnotationBeanPostProcessor
}
public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
- Collection<LifecycleElement> destroyMethodsToIterate =
+ Collection<LifecycleElement> destroyMethodsToUse =
(this.checkedDestroyMethods != null ? this.checkedDestroyMethods : this.destroyMethods);
- if (!destroyMethodsToIterate.isEmpty()) {
+ if (!destroyMethodsToUse.isEmpty()) {
boolean debug = logger.isDebugEnabled();
- for (LifecycleElement element : destroyMethodsToIterate) {
+ for (LifecycleElement element : destroyMethodsToUse) {
if (debug) {
logger.debug("Invoking destroy method on bean '" + beanName + "': " + element.getMethod());
}
@@ -320,6 +325,12 @@ public class InitDestroyAnnotationBeanPostProcessor
}
}
}
+
+ public boolean hasDestroyMethods() {
+ Collection<LifecycleElement> destroyMethodsToUse =
+ (this.checkedDestroyMethods != null ? this.checkedDestroyMethods : this.destroyMethods);
+ return !destroyMethodsToUse.isEmpty();
+ }
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
index d8fcc731..0f6d1021 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -32,6 +32,8 @@ import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -315,25 +317,20 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
* Determine a suggested value from any of the given candidate annotations.
*/
protected Object findValue(Annotation[] annotationsToSearch) {
- for (Annotation annotation : annotationsToSearch) {
- if (this.valueAnnotationType.isInstance(annotation)) {
- return extractValue(annotation);
- }
- }
- for (Annotation annotation : annotationsToSearch) {
- Annotation metaAnn = annotation.annotationType().getAnnotation(this.valueAnnotationType);
- if (metaAnn != null) {
- return extractValue(metaAnn);
- }
+ AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
+ AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
+ if (attr != null) {
+ return extractValue(attr);
}
return null;
}
/**
* Extract the value attribute from the given annotation.
+ * @since 4.3
*/
- protected Object extractValue(Annotation valueAnnotation) {
- Object value = AnnotationUtils.getValue(valueAnnotation);
+ protected Object extractValue(AnnotationAttributes attr) {
+ Object value = attr.get(AnnotationUtils.VALUE);
if (value == null) {
throw new IllegalStateException("Value annotation must have a value attribute");
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java
index bc8a42f7..85faab00 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/AbstractFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -208,7 +208,7 @@ public abstract class AbstractFactoryBean<T>
* <p>Invoked on initialization of this FactoryBean in case of
* a singleton; else, on each {@link #getObject()} call.
* @return the object returned by this factory
- * @throws Exception if an exception occured during object creation
+ * @throws Exception if an exception occurred during object creation
* @see #getObject()
*/
protected abstract T createInstance() throws Exception;
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java
index ffa8849a..43602b48 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -114,9 +114,9 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* <p>Performs full initialization of the bean, including all applicable
* {@link BeanPostProcessor BeanPostProcessors}.
* <p>Note: This is intended for creating a fresh instance, populating annotated
- * fields and methods as well as applying all standard bean initialiation callbacks.
+ * fields and methods as well as applying all standard bean initialization callbacks.
* It does <i>not</> imply traditional by-name or by-type autowiring of properties;
- * use {@link #createBean(Class, int, boolean)} for that purposes.
+ * use {@link #createBean(Class, int, boolean)} for those purposes.
* @param beanClass the class of the bean to create
* @return the new bean instance
* @throws BeansException if instantiation or wiring failed
@@ -129,7 +129,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* <p>Note: This is essentially intended for (re-)populating annotated fields and
* methods, either for new instances or for deserialized instances. It does
* <i>not</i> imply traditional by-name or by-type autowiring of properties;
- * use {@link #autowireBeanProperties} for that purposes.
+ * use {@link #autowireBeanProperties} for those purposes.
* @param existingBean the existing bean instance
* @throws BeansException if wiring failed
*/
@@ -159,7 +159,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @param descriptor the descriptor for the dependency
* @param beanName the name of the bean which declares the present dependency
* @return the resolved object, or {@code null} if none found
- * @throws BeansException in dependency resolution failed
+ * @throws BeansException if dependency resolution failed
*/
Object resolveDependency(DependencyDescriptor descriptor, String beanName) throws BeansException;
@@ -321,7 +321,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @param typeConverter the TypeConverter to use for populating arrays and
* collections
* @return the resolved object, or {@code null} if none found
- * @throws BeansException in dependency resolution failed
+ * @throws BeansException if dependency resolution failed
*/
Object resolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException;
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java
index d04eb15d..302deec5 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConfigurableBeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -210,6 +210,13 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single
void addEmbeddedValueResolver(StringValueResolver valueResolver);
/**
+ * Determine whether an embedded value resolver has been registered with this
+ * bean factory, to be applied through {@link #resolveEmbeddedValue(String)}.
+ * @since 4.3
+ */
+ boolean hasEmbeddedValueResolver();
+
+ /**
* Resolve the given embedded value, e.g. an annotation attribute.
* @param value the value to resolve
* @return the resolved value (may be the original value as-is)
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java
index 9a57c7ae..6f7d2d90 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/ConstructorArgumentValues.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -156,7 +156,7 @@ public class ConstructorArgumentValues {
* @param requiredType the type to match (can be {@code null} to match
* untyped values only)
* @param requiredName the type to match (can be {@code null} to match
- * unnamed values only)
+ * unnamed values only, or empty String to match any name)
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getIndexedArgumentValue(int index, Class<?> requiredType, String requiredName) {
@@ -165,7 +165,7 @@ public class ConstructorArgumentValues {
if (valueHolder != null &&
(valueHolder.getType() == null ||
(requiredType != null && ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) &&
- (valueHolder.getName() == null ||
+ (valueHolder.getName() == null || "".equals(requiredName) ||
(requiredName != null && requiredName.equals(valueHolder.getName())))) {
return valueHolder;
}
@@ -268,7 +268,7 @@ public class ConstructorArgumentValues {
* @param requiredType the type to match (can be {@code null} to find
* an arbitrary next generic argument value)
* @param requiredName the name to match (can be {@code null} to not
- * match argument values by name)
+ * match argument values by name, or empty String to match any name)
* @param usedValueHolders a Set of ValueHolder objects that have already been used
* in the current resolution process and should therefore not be returned again
* @return the ValueHolder for the argument, or {@code null} if none found
@@ -278,7 +278,7 @@ public class ConstructorArgumentValues {
if (usedValueHolders != null && usedValueHolders.contains(valueHolder)) {
continue;
}
- if (valueHolder.getName() != null &&
+ if (valueHolder.getName() != null && !"".equals(requiredName) &&
(requiredName == null || !valueHolder.getName().equals(requiredName))) {
continue;
}
@@ -335,7 +335,7 @@ public class ConstructorArgumentValues {
* @param requiredType the parameter type to match (can be {@code null}
* to find an untyped argument value)
* @param requiredName the parameter name to match (can be {@code null}
- * to find an unnamed argument value)
+ * to find an unnamed argument value, or empty String to match any name)
* @param usedValueHolders a Set of ValueHolder objects that have already
* been used in the current resolution process and should therefore not
* be returned again (allowing to return the next generic argument match
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
index 88642eb4..82c6883c 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
@@ -19,17 +19,20 @@ package org.springframework.beans.factory.config;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
-import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.util.Map;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.InjectionPoint;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ResolvableType;
-import org.springframework.util.Assert;
/**
* Descriptor for a specific dependency that is about to be injected.
@@ -40,15 +43,9 @@ import org.springframework.util.Assert;
* @since 2.5
*/
@SuppressWarnings("serial")
-public class DependencyDescriptor implements Serializable {
+public class DependencyDescriptor extends InjectionPoint implements Serializable {
- private transient MethodParameter methodParameter;
-
- private transient Field field;
-
- private Class<?> declaringClass;
-
- private Class<?> containingClass;
+ private final Class<?> declaringClass;
private String methodName;
@@ -64,7 +61,7 @@ public class DependencyDescriptor implements Serializable {
private int nestingLevel = 1;
- private transient Annotation[] fieldAnnotations;
+ private Class<?> containingClass;
/**
@@ -85,10 +82,8 @@ public class DependencyDescriptor implements Serializable {
* eagerly resolving potential target beans for type matching
*/
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
- Assert.notNull(methodParameter, "MethodParameter must not be null");
- this.methodParameter = methodParameter;
+ super(methodParameter);
this.declaringClass = methodParameter.getDeclaringClass();
- this.containingClass = methodParameter.getContainingClass();
if (this.methodParameter.getMethod() != null) {
this.methodName = methodParameter.getMethod().getName();
this.parameterTypes = methodParameter.getMethod().getParameterTypes();
@@ -97,6 +92,7 @@ public class DependencyDescriptor implements Serializable {
this.parameterTypes = methodParameter.getConstructor().getParameterTypes();
}
this.parameterIndex = methodParameter.getParameterIndex();
+ this.containingClass = methodParameter.getContainingClass();
this.required = required;
this.eager = eager;
}
@@ -119,8 +115,7 @@ public class DependencyDescriptor implements Serializable {
* eagerly resolving potential target beans for type matching
*/
public DependencyDescriptor(Field field, boolean required, boolean eager) {
- Assert.notNull(field, "Field must not be null");
- this.field = field;
+ super(field);
this.declaringClass = field.getDeclaringClass();
this.fieldName = field.getName();
this.required = required;
@@ -132,52 +127,84 @@ public class DependencyDescriptor implements Serializable {
* @param original the original descriptor to create a copy from
*/
public DependencyDescriptor(DependencyDescriptor original) {
- this.methodParameter = (original.methodParameter != null ? new MethodParameter(original.methodParameter) : null);
- this.field = original.field;
+ super(original);
this.declaringClass = original.declaringClass;
- this.containingClass = original.containingClass;
this.methodName = original.methodName;
this.parameterTypes = original.parameterTypes;
this.parameterIndex = original.parameterIndex;
this.fieldName = original.fieldName;
+ this.containingClass = original.containingClass;
this.required = original.required;
this.eager = original.eager;
this.nestingLevel = original.nestingLevel;
- this.fieldAnnotations = original.fieldAnnotations;
}
/**
- * Return the wrapped MethodParameter, if any.
- * <p>Note: Either MethodParameter or Field is available.
- * @return the MethodParameter, or {@code null} if none
+ * Return whether this dependency is required.
*/
- public MethodParameter getMethodParameter() {
- return this.methodParameter;
+ public boolean isRequired() {
+ return this.required;
}
/**
- * Return the wrapped Field, if any.
- * <p>Note: Either MethodParameter or Field is available.
- * @return the Field, or {@code null} if none
+ * Return whether this dependency is 'eager' in the sense of
+ * eagerly resolving potential target beans for type matching.
*/
- public Field getField() {
- return this.field;
+ public boolean isEager() {
+ return this.eager;
}
/**
- * Return whether this dependency is required.
+ * Resolve the specified not-unique scenario: by default,
+ * throwing a {@link NoUniqueBeanDefinitionException}.
+ * <p>Subclasses may override this to select one of the instances or
+ * to opt out with no result at all through returning {@code null}.
+ * @param type the requested bean type
+ * @param matchingBeans a map of bean names and corresponding bean
+ * instances which have been pre-selected for the given type
+ * (qualifiers etc already applied)
+ * @return a bean instance to proceed with, or {@code null} for none
+ * @throws BeansException in case of the not-unique scenario being fatal
+ * @since 4.3
*/
- public boolean isRequired() {
- return this.required;
+ public Object resolveNotUnique(Class<?> type, Map<String, Object> matchingBeans) throws BeansException {
+ throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
}
/**
- * Return whether this dependency is 'eager' in the sense of
- * eagerly resolving potential target beans for type matching.
+ * Resolve a shortcut for this dependency against the given factory, for example
+ * taking some pre-resolved information into account.
+ * <p>The resolution algorithm will first attempt to resolve a shortcut through this
+ * method before going into the regular type matching algorithm across all beans.
+ * Subclasses may override this method to improve resolution performance based on
+ * pre-cached information while still receiving {@link InjectionPoint} exposure etc.
+ * @param beanFactory the associated factory
+ * @return the shortcut result if any, or {@code null} if none
+ * @throws BeansException if the shortcut could not be obtained
+ * @since 4.3.1
*/
- public boolean isEager() {
- return this.eager;
+ public Object resolveShortcut(BeanFactory beanFactory) throws BeansException {
+ return null;
+ }
+
+ /**
+ * Resolve the specified bean name, as a candidate result of the matching
+ * algorithm for this dependency, to a bean instance from the given factory.
+ * <p>The default implementation calls {@link BeanFactory#getBean(String)}.
+ * Subclasses may provide additional arguments or other customizations.
+ * @param beanName the bean name, as a candidate result for this dependency
+ * @param requiredType the expected type of the bean (as an assertion)
+ * @param beanFactory the associated factory
+ * @return the bean instance (never {@code null})
+ * @throws BeansException if the bean could not be obtained
+ * @since 4.3.2
+ * @see BeanFactory#getBean(String)
+ */
+ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
+ throws BeansException {
+
+ return beanFactory.getBean(beanName, requiredType);
}
@@ -272,6 +299,7 @@ public class DependencyDescriptor implements Serializable {
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
type = args[args.length - 1];
}
+ // TODO: Object.class if unresolvable
}
if (type instanceof Class) {
return (Class<?>) type;
@@ -323,19 +351,18 @@ public class DependencyDescriptor implements Serializable {
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
}
- /**
- * Obtain the annotations associated with the wrapped parameter/field, if any.
- */
- public Annotation[] getAnnotations() {
- if (this.field != null) {
- if (this.fieldAnnotations == null) {
- this.fieldAnnotations = this.field.getAnnotations();
- }
- return this.fieldAnnotations;
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
}
- else {
- return this.methodParameter.getParameterAnnotations();
+ if (!super.equals(other)) {
+ return false;
}
+ DependencyDescriptor otherDesc = (DependencyDescriptor) other;
+ return (this.required == otherDesc.required && this.eager == otherDesc.eager &&
+ this.nestingLevel == otherDesc.nestingLevel && this.containingClass == otherDesc.containingClass);
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.java
index 76de1390..92316f13 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -43,4 +43,24 @@ public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
*/
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
+ /**
+ * Determine whether the given bean instance requires destruction by this
+ * post-processor.
+ * <p><b>NOTE:</b> Even as a late addition, this method has been introduced on
+ * {@code DestructionAwareBeanPostProcessor} itself instead of on a SmartDABPP
+ * subinterface. This allows existing {@code DestructionAwareBeanPostProcessor}
+ * implementations to easily provide {@code requiresDestruction} logic while
+ * retaining compatibility with Spring <4.3, and it is also an easier onramp to
+ * declaring {@code requiresDestruction} as a Java 8 default method in Spring 5.
+ * <p>If an implementation of {@code DestructionAwareBeanPostProcessor} does
+ * not provide a concrete implementation of this method, Spring's invocation
+ * mechanism silently assumes a method returning {@code true} (the effective
+ * default before 4.3, and the to-be-default in the Java 8 method in Spring 5).
+ * @param bean the bean instance to check
+ * @return {@code true} if {@link #postProcessBeforeDestruction} is supposed to
+ * be called for this bean instance eventually, or {@code false} if not needed
+ * @since 4.3
+ */
+ boolean requiresDestruction(Object bean);
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java
new file mode 100644
index 00000000..bd8c1666
--- /dev/null
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/EmbeddedValueResolver.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.beans.factory.config;
+
+import org.springframework.util.StringValueResolver;
+
+/**
+ * {@link StringValueResolver} adapter for resolving placeholders and
+ * expressions against a {@link ConfigurableBeanFactory}.
+ *
+ * <p>Note that this adapter resolves expressions as well, in contrast
+ * to the {@link ConfigurableBeanFactory#resolveEmbeddedValue} method.
+ * The {@link BeanExpressionContext} used is for the plain bean factory,
+ * with no scope specified for any contextual objects to access.
+ *
+ * @author Juergen Hoeller
+ * @since 4.3
+ * @see ConfigurableBeanFactory#resolveEmbeddedValue(String)
+ * @see ConfigurableBeanFactory#getBeanExpressionResolver()
+ * @see BeanExpressionContext
+ */
+public class EmbeddedValueResolver implements StringValueResolver {
+
+ private final BeanExpressionContext exprContext;
+
+ private final BeanExpressionResolver exprResolver;
+
+
+ public EmbeddedValueResolver(ConfigurableBeanFactory beanFactory) {
+ this.exprContext = new BeanExpressionContext(beanFactory, null);
+ this.exprResolver = beanFactory.getBeanExpressionResolver();
+ }
+
+
+ @Override
+ public String resolveStringValue(String strVal) {
+ String value = this.exprContext.getBeanFactory().resolveEmbeddedValue(strVal);
+ if (this.exprResolver != null && value != null) {
+ Object evaluated = this.exprResolver.evaluate(value, this.exprContext);
+ value = (evaluated != null ? evaluated.toString() : null);
+ }
+ return value;
+ }
+
+}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java
index f508e3ff..964ee204 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java
@@ -96,7 +96,7 @@ public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
* dependency types - which the factory handles specifically - already filtered out)
* @param bean the bean instance created, but whose properties have not yet been set
* @param beanName the name of the bean
- * @return the actual property values to apply to to the given bean
+ * @return the actual property values to apply to the given bean
* (can be the passed-in PropertyValues instance), or {@code null}
* to skip property population
* @throws org.springframework.beans.BeansException in case of errors
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java
index a0152ed4..f7223a9a 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -107,6 +107,8 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
+ protected boolean trimValues = false;
+
protected String nullValue;
protected boolean ignoreUnresolvablePlaceholders = false;
@@ -143,6 +145,16 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
}
/**
+ * Specify whether to trim resolved values before applying them,
+ * removing superfluous whitespace from the beginning and end.
+ * <p>Default is {@code false}.
+ * @since 4.3
+ */
+ public void setTrimValues(boolean trimValues) {
+ this.trimValues = trimValues;
+ }
+
+ /**
* Set a value that should be treated as {@code null} when resolved
* as a placeholder value: e.g. "" (empty String) or "null".
* <p>Note that this will only apply to full property values,
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertiesFactoryBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertiesFactoryBean.java
index 93a97a8d..adc415d0 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertiesFactoryBean.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertiesFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -95,7 +95,7 @@ public class PropertiesFactoryBean extends PropertiesLoaderSupport
* <p>Invoked on initialization of this FactoryBean in case of a
* shared singleton; else, on each {@link #getObject()} call.
* @return the object returned by this factory
- * @throws IOException if an exception occured during properties loading
+ * @throws IOException if an exception occurred during properties loading
* @see #mergeProperties()
*/
protected Properties createProperties() throws IOException {
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java
index f98ce40e..a0243a33 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -255,8 +255,11 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
@Override
public String resolveStringValue(String strVal) throws BeansException {
- String value = this.helper.replacePlaceholders(strVal, this.resolver);
- return (value.equals(nullValue) ? null : value);
+ String resolved = this.helper.replacePlaceholders(strVal, this.resolver);
+ if (trimValues) {
+ resolved = resolved.trim();
+ }
+ return (resolved.equals(nullValue) ? null : resolved);
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/Scope.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/Scope.java
index 8777fa61..2911a123 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/Scope.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/Scope.java
@@ -100,7 +100,7 @@ public interface Scope {
* at the appropriate time. If such a callback is not supported by the
* underlying runtime environment at all, the callback <i>must be
* ignored and a corresponding warning should be logged</i>.
- * <p>Note that 'destruction' refers to to automatic destruction of
+ * <p>Note that 'destruction' refers to automatic destruction of
* the object as part of the scope's own lifecycle, not to the individual
* scoped object having been explicitly removed by the application.
* If a scoped object gets removed via this facade's {@link #remove(String)}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java
index e90712fc..bca9efeb 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java
@@ -68,7 +68,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
* {@link org.springframework.context.ApplicationContext} implementations.
* <p>If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a
* {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
- * <p>If the the passed-in bean factory also implements {@link EnvironmentCapable} its
+ * <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its
* environment will be used by this reader. Otherwise, the reader will initialize and
* use a {@link StandardEnvironment}. All ApplicationContext implementations are
* EnvironmentCapable, while normal BeanFactory implementations are not.
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
index 80e91528..62dfa38e 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
@@ -799,6 +799,11 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
@Override
+ public boolean hasEmbeddedValueResolver() {
+ return !this.embeddedValueResolvers.isEmpty();
+ }
+
+ @Override
public String resolveEmbeddedValue(String value) {
String result = value;
for (StringValueResolver resolver : this.embeddedValueResolvers) {
@@ -1619,7 +1624,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
*/
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
return (bean != null &&
- (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || hasDestructionAwareBeanPostProcessors()));
+ (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() &&
+ DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
}
/**
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java
index 41653c84..cbb9d2f1 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -115,7 +115,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
- instance = BeanUtils.instantiate(subclass);
+ instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
index 50c56791..7c871d46 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -40,12 +40,14 @@ import org.springframework.beans.TypeConverter;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
+import org.springframework.core.NamedThreadLocal;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
@@ -68,6 +70,9 @@ import org.springframework.util.StringUtils;
*/
class ConstructorResolver {
+ private static final NamedThreadLocal<InjectionPoint> currentInjectionPoint =
+ new NamedThreadLocal<InjectionPoint>("Current injection point");
+
private final AbstractAutowireCapableBeanFactory beanFactory;
@@ -151,7 +156,7 @@ class ConstructorResolver {
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
- "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
+ "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
AutowireUtils.sortConstructors(candidates);
@@ -159,8 +164,7 @@ class ConstructorResolver {
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
- for (int i = 0; i < candidates.length; i++) {
- Constructor<?> candidate = candidates[i];
+ for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
@@ -182,8 +186,8 @@ class ConstructorResolver {
paramNames = pnd.getParameterNames(candidate);
}
}
- argsHolder = createArgumentArray(
- beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
+ argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
+ getUserDeclaredConstructor(candidate), autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
@@ -268,7 +272,7 @@ class ConstructorResolver {
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
- bw.setWrappedInstance(beanInstance);
+ bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
@@ -444,10 +448,9 @@ class ConstructorResolver {
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
- List<Exception> causes = null;
+ LinkedList<UnsatisfiedDependencyException> causes = null;
- for (int i = 0; i < candidates.length; i++) {
- Method candidate = candidates[i];
+ for (Method candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
@@ -469,22 +472,12 @@ class ConstructorResolver {
this.beanFactory.logger.trace("Ignoring factory method [" + candidate +
"] of bean '" + beanName + "': " + ex);
}
- if (i == candidates.length - 1 && argsHolderToUse == null) {
- if (causes != null) {
- for (Exception cause : causes) {
- this.beanFactory.onSuppressedException(cause);
- }
- }
- throw ex;
- }
- else {
- // Swallow and try next overloaded factory method.
- if (causes == null) {
- causes = new LinkedList<Exception>();
- }
- causes.add(ex);
- continue;
+ // Swallow and try next overloaded factory method.
+ if (causes == null) {
+ causes = new LinkedList<UnsatisfiedDependencyException>();
}
+ causes.add(ex);
+ continue;
}
}
@@ -525,6 +518,13 @@ class ConstructorResolver {
}
if (factoryMethodToUse == null) {
+ if (causes != null) {
+ UnsatisfiedDependencyException ex = causes.removeLast();
+ for (Exception cause : causes) {
+ this.beanFactory.onSuppressedException(cause);
+ }
+ throw ex;
+ }
List<String> argTypes = new ArrayList<String>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
@@ -592,7 +592,7 @@ class ConstructorResolver {
if (beanInstance == null) {
return null;
}
- bw.setWrappedInstance(beanInstance);
+ bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
@@ -609,8 +609,8 @@ class ConstructorResolver {
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
- TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
- this.beanFactory.getCustomTypeConverter() : bw);
+ TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
+ TypeConverter converter = (customConverter != null ? customConverter : bw);
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
@@ -665,9 +665,8 @@ class ConstructorResolver {
BeanWrapper bw, Class<?>[] paramTypes, String[] paramNames, Object methodOrCtor,
boolean autowiring) throws UnsatisfiedDependencyException {
- String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
- TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
- this.beanFactory.getCustomTypeConverter() : bw);
+ TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
+ TypeConverter converter = (customConverter != null ? customConverter : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
@@ -676,14 +675,14 @@ class ConstructorResolver {
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
- String paramName = (paramNames != null ? paramNames[paramIndex] : null);
+ String paramName = (paramNames != null ? paramNames[paramIndex] : "");
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder =
resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// If we couldn't find a direct match and are not supposed to autowire,
// let's try the next generic, untyped argument value as fallback:
// it could match after type conversion (for example, String -> int).
- if (valueHolder == null && !autowiring) {
+ if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
if (valueHolder != null) {
@@ -700,9 +699,9 @@ class ConstructorResolver {
ConstructorArgumentValues.ValueHolder sourceHolder =
(ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
Object sourceValue = sourceHolder.getValue();
+ MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex);
try {
- convertedValue = converter.convertIfNecessary(originalValue, paramType,
- MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
+ convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
// TODO re-enable once race condition has been found (SPR-7423)
/*
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
@@ -718,8 +717,8 @@ class ConstructorResolver {
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
- mbd.getResourceDescription(), beanName, paramIndex, paramType,
- "Could not convert " + methodType + " argument value of type [" +
+ mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
+ "Could not convert argument value of type [" +
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
@@ -728,17 +727,18 @@ class ConstructorResolver {
args.rawArguments[paramIndex] = originalValue;
}
else {
+ MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex);
// No explicit match found: we're either supposed to autowire or
// have to fail creating an argument array for the given constructor.
if (!autowiring) {
throw new UnsatisfiedDependencyException(
- mbd.getResourceDescription(), beanName, paramIndex, paramType,
- "Ambiguous " + methodType + " argument types - " +
- "did you specify the correct bean references as " + methodType + " arguments?");
+ mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
+ "Ambiguous argument values for parameter of type [" + paramType.getName() +
+ "] - did you specify the correct bean references as arguments?");
}
try {
- MethodParameter param = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex);
- Object autowiredArgument = resolveAutowiredArgument(param, beanName, autowiredBeanNames, converter);
+ Object autowiredArgument =
+ resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
@@ -746,7 +746,7 @@ class ConstructorResolver {
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
- mbd.getResourceDescription(), beanName, paramIndex, paramType, ex);
+ mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
@@ -755,7 +755,8 @@ class ConstructorResolver {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (this.beanFactory.logger.isDebugEnabled()) {
this.beanFactory.logger.debug("Autowiring by type from bean name '" + beanName +
- "' via " + methodType + " to bean named '" + autowiredBeanName + "'");
+ "' via " + (methodOrCtor instanceof Constructor ? "constructor" : "factory method") +
+ " to bean named '" + autowiredBeanName + "'");
}
}
@@ -768,12 +769,13 @@ class ConstructorResolver {
private Object[] resolvePreparedArguments(
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
- Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
- ((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes());
- TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
- this.beanFactory.getCustomTypeConverter() : bw);
+ TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
+ TypeConverter converter = (customConverter != null ? customConverter : bw);
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
+ Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
+ ((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes());
+
Object[] resolvedArgs = new Object[argsToResolve.length];
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
Object argValue = argsToResolve[argIndex];
@@ -793,28 +795,61 @@ class ConstructorResolver {
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
- String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
throw new UnsatisfiedDependencyException(
- mbd.getResourceDescription(), beanName, argIndex, paramType,
- "Could not convert " + methodType + " argument value of type [" +
- ObjectUtils.nullSafeClassName(argValue) +
+ mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
+ "Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
}
return resolvedArgs;
}
+ protected Constructor<?> getUserDeclaredConstructor(Constructor<?> constructor) {
+ Class<?> declaringClass = constructor.getDeclaringClass();
+ Class<?> userClass = ClassUtils.getUserClass(declaringClass);
+ if (userClass != declaringClass) {
+ try {
+ return userClass.getDeclaredConstructor(constructor.getParameterTypes());
+ }
+ catch (NoSuchMethodException ex) {
+ // No equivalent constructor on user class (superclass)...
+ // Let's proceed with the given constructor as we usually would.
+ }
+ }
+ return constructor;
+ }
+
/**
* Template method for resolving the specified argument which is supposed to be autowired.
*/
protected Object resolveAutowiredArgument(
MethodParameter param, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) {
+ if (InjectionPoint.class.isAssignableFrom(param.getParameterType())) {
+ InjectionPoint injectionPoint = currentInjectionPoint.get();
+ if (injectionPoint == null) {
+ throw new IllegalStateException("No current InjectionPoint available for " + param);
+ }
+ return injectionPoint;
+ }
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
}
+
+ static InjectionPoint setCurrentInjectionPoint(InjectionPoint injectionPoint) {
+ InjectionPoint old = currentInjectionPoint.get();
+ if (injectionPoint != null) {
+ currentInjectionPoint.set(injectionPoint);
+ }
+ else {
+ currentInjectionPoint.remove();
+ }
+ return old;
+ }
+
+
/**
* Private inner class for holding argument combinations.
*/
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
index 7a32060e..bb4ef59b 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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,7 +45,6 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Provider;
import org.springframework.beans.BeansException;
-import org.springframework.beans.FatalBeanException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
@@ -53,11 +52,14 @@ import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -615,10 +617,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public void registerResolvableDependency(Class<?> dependencyType, Object autowiredValue) {
- Assert.notNull(dependencyType, "Type must not be null");
+ Assert.notNull(dependencyType, "Dependency type must not be null");
if (autowiredValue != null) {
- Assert.isTrue((autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue)),
- "Value [" + autowiredValue + "] does not implement specified type [" + dependencyType.getName() + "]");
+ if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
+ throw new IllegalArgumentException("Value [" + autowiredValue +
+ "] does not implement specified dependency type [" + dependencyType.getName() + "]");
+ }
this.resolvableDependencies.put(dependencyType, autowiredValue);
}
}
@@ -999,14 +1003,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
- if (descriptor.getDependencyType().equals(javaUtilOptionalClass)) {
+ if (javaUtilOptionalClass == descriptor.getDependencyType()) {
return new OptionalDependencyFactory().createOptionalDependency(descriptor, beanName);
}
- else if (ObjectFactory.class == descriptor.getDependencyType()) {
- return new DependencyObjectFactory(descriptor, beanName);
+ else if (ObjectFactory.class == descriptor.getDependencyType() ||
+ ObjectProvider.class == descriptor.getDependencyType()) {
+ return new DependencyObjectProvider(descriptor, beanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
- return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);
+ return new Jsr330ProviderFactory().createDependencyProvider(descriptor, beanName);
}
else {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, beanName);
@@ -1020,29 +1025,79 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
- Class<?> type = descriptor.getDependencyType();
- Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
- if (value != null) {
- if (value instanceof String) {
- String strVal = resolveEmbeddedValue((String) value);
- BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
- value = evaluateBeanDefinitionString(strVal, bd);
+ InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
+ try {
+ Object shortcut = descriptor.resolveShortcut(this);
+ if (shortcut != null) {
+ return shortcut;
}
- TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
- return (descriptor.getField() != null ?
- converter.convertIfNecessary(value, type, descriptor.getField()) :
- converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
+
+ Class<?> type = descriptor.getDependencyType();
+ Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
+ if (value != null) {
+ if (value instanceof String) {
+ String strVal = resolveEmbeddedValue((String) value);
+ BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
+ value = evaluateBeanDefinitionString(strVal, bd);
+ }
+ TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
+ return (descriptor.getField() != null ?
+ converter.convertIfNecessary(value, type, descriptor.getField()) :
+ converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
+ }
+
+ Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
+ if (multipleBeans != null) {
+ return multipleBeans;
+ }
+
+ Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
+ if (matchingBeans.isEmpty()) {
+ if (descriptor.isRequired()) {
+ raiseNoMatchingBeanFound(type, descriptor.getResolvableType().toString(), descriptor);
+ }
+ return null;
+ }
+ if (matchingBeans.size() > 1) {
+ String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
+ if (primaryBeanName == null) {
+ if (descriptor.isRequired() || !indicatesMultipleBeans(type)) {
+ return descriptor.resolveNotUnique(type, matchingBeans);
+ }
+ else {
+ // In case of an optional Collection/Map, silently ignore a non-unique case:
+ // possibly it was meant to be an empty collection of multiple regular beans
+ // (before 4.3 in particular when we didn't even look for collection beans).
+ return null;
+ }
+ }
+ if (autowiredBeanNames != null) {
+ autowiredBeanNames.add(primaryBeanName);
+ }
+ return matchingBeans.get(primaryBeanName);
+ }
+ // We have exactly one match.
+ Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
+ if (autowiredBeanNames != null) {
+ autowiredBeanNames.add(entry.getKey());
+ }
+ return entry.getValue();
+ }
+ finally {
+ ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
+ }
+
+ private Object resolveMultipleBeans(DependencyDescriptor descriptor, String beanName,
+ Set<String> autowiredBeanNames, TypeConverter typeConverter) {
+ Class<?> type = descriptor.getDependencyType();
if (type.isArray()) {
Class<?> componentType = type.getComponentType();
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
targetDesc.increaseNestingLevel();
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, targetDesc);
if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
- }
return null;
}
if (autowiredBeanNames != null) {
@@ -1058,18 +1113,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getCollectionType();
if (elementType == null) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
- }
return null;
}
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
targetDesc.increaseNestingLevel();
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, targetDesc);
if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
- }
return null;
}
if (autowiredBeanNames != null) {
@@ -1085,26 +1134,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> keyType = descriptor.getMapKeyType();
if (String.class != keyType) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
- "] must be [java.lang.String]");
- }
return null;
}
Class<?> valueType = descriptor.getMapValueType();
if (valueType == null) {
- if (descriptor.isRequired()) {
- throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
- }
return null;
}
DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
targetDesc.increaseNestingLevel();
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, targetDesc);
if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
- }
return null;
}
if (autowiredBeanNames != null) {
@@ -1113,32 +1152,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return matchingBeans;
}
else {
- Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
- if (matchingBeans.isEmpty()) {
- if (descriptor.isRequired()) {
- raiseNoSuchBeanDefinitionException(type, "", descriptor);
- }
- return null;
- }
- if (matchingBeans.size() > 1) {
- String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
- if (primaryBeanName == null) {
- throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
- }
- if (autowiredBeanNames != null) {
- autowiredBeanNames.add(primaryBeanName);
- }
- return matchingBeans.get(primaryBeanName);
- }
- // We have exactly one match.
- Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
- if (autowiredBeanNames != null) {
- autowiredBeanNames.add(entry.getKey());
- }
- return entry.getValue();
+ return null;
}
}
+ private boolean indicatesMultipleBeans(Class<?> type) {
+ return (type.isArray() || (type.isInterface() &&
+ (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type))));
+ }
+
private Comparator<Object> adaptDependencyComparator(Map<String, Object> matchingBeans) {
Comparator<Object> comparator = getDependencyComparator();
if (comparator instanceof OrderComparator) {
@@ -1189,14 +1211,23 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
for (String candidateName : candidateNames) {
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
- result.put(candidateName, getBean(candidateName));
+ result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
}
}
- if (result.isEmpty()) {
+ if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
+ // Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidateName : candidateNames) {
- if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
- result.put(candidateName, getBean(candidateName));
+ if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
+ result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
+ }
+ }
+ if (result.isEmpty()) {
+ // Consider self references before as a final pass
+ for (String candidateName : candidateNames) {
+ if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
+ result.put(candidateName, descriptor.resolveCandidate(candidateName, requiredType, this));
+ }
}
}
}
@@ -1362,17 +1393,43 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
/**
- * Raise a NoSuchBeanDefinitionException for an unresolvable dependency.
+ * Raise a NoSuchBeanDefinitionException or BeanNotOfRequiredTypeException
+ * for an unresolvable dependency.
*/
- private void raiseNoSuchBeanDefinitionException(
- Class<?> type, String dependencyDescription, DependencyDescriptor descriptor)
- throws NoSuchBeanDefinitionException {
+ private void raiseNoMatchingBeanFound(
+ Class<?> type, String dependencyDescription, DependencyDescriptor descriptor) throws BeansException {
+
+ checkBeanNotOfRequiredType(type, descriptor);
throw new NoSuchBeanDefinitionException(type, dependencyDescription,
"expected at least 1 bean which qualifies as autowire candidate for this dependency. " +
"Dependency annotations: " + ObjectUtils.nullSafeToString(descriptor.getAnnotations()));
}
+ /**
+ * Raise a BeanNotOfRequiredTypeException for an unresolvable dependency, if applicable,
+ * i.e. if the target type of the bean would match but an exposed proxy doesn't.
+ */
+ private void checkBeanNotOfRequiredType(Class<?> type, DependencyDescriptor descriptor) {
+ for (String beanName : this.beanDefinitionNames) {
+ RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
+ Class<?> targetType = mbd.getTargetType();
+ if (targetType != null && type.isAssignableFrom(targetType) &&
+ isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) {
+ // Probably a poxy interfering with target type match -> throw meaningful exception.
+ Object beanInstance = getSingleton(beanName, false);
+ Class<?> beanType = (beanInstance != null ? beanInstance.getClass() : predictBeanType(beanName, mbd));
+ if (type != beanType) {
+ throw new BeanNotOfRequiredTypeException(beanName, type, beanType);
+ }
+ }
+ }
+
+ if (getParentBeanFactory() instanceof DefaultListableBeanFactory) {
+ ((DefaultListableBeanFactory) getParentBeanFactory()).checkBeanNotOfRequiredType(type, descriptor);
+ }
+ }
+
@Override
public String toString() {
@@ -1424,16 +1481,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private Object readResolve() {
Reference<?> ref = serializableFactories.get(this.id);
- if (ref == null) {
- throw new IllegalStateException(
- "Cannot deserialize BeanFactory with id " + this.id + ": no factory registered for this id");
- }
- Object result = ref.get();
- if (result == null) {
- throw new IllegalStateException(
- "Cannot deserialize BeanFactory with id " + this.id + ": factory has been garbage-collected");
+ if (ref != null) {
+ Object result = ref.get();
+ if (result != null) {
+ return result;
+ }
}
- return result;
+ // Lenient fallback: dummy factory in case of original factory not found...
+ return new StaticListableBeanFactory(Collections.<String, Object> emptyMap());
}
}
@@ -1444,12 +1499,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@UsesJava8
private class OptionalDependencyFactory {
- public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName) {
+ public Object createOptionalDependency(DependencyDescriptor descriptor, String beanName, final Object... args) {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
@Override
public boolean isRequired() {
return false;
}
+ @Override
+ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
+ return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, requiredType, args) :
+ super.resolveCandidate(beanName, requiredType, beanFactory));
+ }
};
descriptorToUse.increaseNestingLevel();
return Optional.ofNullable(doResolveDependency(descriptorToUse, beanName, null, null));
@@ -1458,9 +1518,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/**
- * Serializable ObjectFactory for lazy resolution of a dependency.
+ * Serializable ObjectFactory/ObjectProvider for lazy resolution of a dependency.
*/
- private class DependencyObjectFactory implements ObjectFactory<Object>, Serializable {
+ private class DependencyObjectProvider implements ObjectProvider<Object>, Serializable {
private final DependencyDescriptor descriptor;
@@ -1468,7 +1528,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private final String beanName;
- public DependencyObjectFactory(DependencyDescriptor descriptor, String beanName) {
+ public DependencyObjectProvider(DependencyDescriptor descriptor, String beanName) {
this.descriptor = new DependencyDescriptor(descriptor);
this.descriptor.increaseNestingLevel();
this.optional = this.descriptor.getDependencyType().equals(javaUtilOptionalClass);
@@ -1484,15 +1544,67 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return doResolveDependency(this.descriptor, this.beanName, null, null);
}
}
+
+ @Override
+ public Object getObject(final Object... args) throws BeansException {
+ if (this.optional) {
+ return new OptionalDependencyFactory().createOptionalDependency(this.descriptor, this.beanName, args);
+ }
+ else {
+ DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
+ @Override
+ public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
+ return ((AbstractBeanFactory) beanFactory).getBean(beanName, requiredType, args);
+ }
+ };
+ return doResolveDependency(descriptorToUse, this.beanName, null, null);
+ }
+ }
+
+ @Override
+ public Object getIfAvailable() throws BeansException {
+ if (this.optional) {
+ return new OptionalDependencyFactory().createOptionalDependency(this.descriptor, this.beanName);
+ }
+ else {
+ DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
+ @Override
+ public boolean isRequired() {
+ return false;
+ }
+ };
+ return doResolveDependency(descriptorToUse, this.beanName, null, null);
+ }
+ }
+
+ @Override
+ public Object getIfUnique() throws BeansException {
+ DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
+ @Override
+ public boolean isRequired() {
+ return false;
+ }
+ @Override
+ public Object resolveNotUnique(Class<?> type, Map<String, Object> matchingBeans) {
+ return null;
+ }
+ };
+ if (this.optional) {
+ return new OptionalDependencyFactory().createOptionalDependency(descriptorToUse, this.beanName);
+ }
+ else {
+ return doResolveDependency(descriptorToUse, this.beanName, null, null);
+ }
+ }
}
/**
* Serializable ObjectFactory for lazy resolution of a dependency.
*/
- private class DependencyProvider extends DependencyObjectFactory implements Provider<Object> {
+ private class Jsr330DependencyProvider extends DependencyObjectProvider implements Provider<Object> {
- public DependencyProvider(DependencyDescriptor descriptor, String beanName) {
+ public Jsr330DependencyProvider(DependencyDescriptor descriptor, String beanName) {
super(descriptor, beanName);
}
@@ -1506,10 +1618,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/**
* Separate inner class for avoiding a hard dependency on the {@code javax.inject} API.
*/
- private class DependencyProviderFactory {
+ private class Jsr330ProviderFactory {
public Object createDependencyProvider(DependencyDescriptor descriptor, String beanName) {
- return new DependencyProvider(descriptor, beanName);
+ return new Jsr330DependencyProvider(descriptor, beanName);
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java
index 9042bad5..d3d21347 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -449,10 +449,10 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
private boolean isDependent(String beanName, String dependentBeanName, Set<String> alreadySeen) {
- String canonicalName = canonicalName(beanName);
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
+ String canonicalName = canonicalName(beanName);
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
return false;
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
index d3a6c361..b79403d6 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
@@ -139,7 +139,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
}
}
- this.beanPostProcessors = filterPostProcessors(postProcessors);
+ this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}
/**
@@ -155,7 +155,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.invokeDisposableBean = (this.bean instanceof DisposableBean);
this.nonPublicAccessAllowed = true;
this.acc = acc;
- this.beanPostProcessors = filterPostProcessors(postProcessors);
+ this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}
/**
@@ -214,16 +214,26 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
/**
* Search for all DestructionAwareBeanPostProcessors in the List.
- * @param postProcessors the List to search
+ * @param processors the List to search
* @return the filtered List of DestructionAwareBeanPostProcessors
*/
- private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> postProcessors) {
+ private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
- if (!CollectionUtils.isEmpty(postProcessors)) {
- filteredPostProcessors = new ArrayList<DestructionAwareBeanPostProcessor>(postProcessors.size());
- for (BeanPostProcessor postProcessor : postProcessors) {
- if (postProcessor instanceof DestructionAwareBeanPostProcessor) {
- filteredPostProcessors.add((DestructionAwareBeanPostProcessor) postProcessor);
+ if (!CollectionUtils.isEmpty(processors)) {
+ filteredPostProcessors = new ArrayList<DestructionAwareBeanPostProcessor>(processors.size());
+ for (BeanPostProcessor processor : processors) {
+ if (processor instanceof DestructionAwareBeanPostProcessor) {
+ DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
+ try {
+ if (dabpp.requiresDestruction(bean)) {
+ filteredPostProcessors.add(dabpp);
+ }
+ }
+ catch (AbstractMethodError err) {
+ // A pre-4.3 third-party DestructionAwareBeanPostProcessor...
+ // As of 5.0, we can let requiresDestruction be a Java 8 default method which returns true.
+ filteredPostProcessors.add(dabpp);
+ }
}
}
}
@@ -401,9 +411,36 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
String destroyMethodName = beanDefinition.getDestroyMethodName();
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
- return ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME);
+ return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
+ ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
}
return StringUtils.hasLength(destroyMethodName);
}
+ /**
+ * Check whether the given bean has destruction-aware post-processors applying to it.
+ * @param bean the bean instance
+ * @param postProcessors the post-processor candidates
+ */
+ public static boolean hasApplicableProcessors(Object bean, List<BeanPostProcessor> postProcessors) {
+ if (!CollectionUtils.isEmpty(postProcessors)) {
+ for (BeanPostProcessor processor : postProcessors) {
+ if (processor instanceof DestructionAwareBeanPostProcessor) {
+ DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
+ try {
+ if (dabpp.requiresDestruction(bean)) {
+ return true;
+ }
+ }
+ catch (AbstractMethodError err) {
+ // A pre-4.3 third-party DestructionAwareBeanPostProcessor...
+ // As of 5.0, we can let requiresDestruction be a Java 8 default method which returns true.
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
index d2ac971c..91ad5d8e 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -125,7 +125,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
setBeanClass(beanClass);
setAutowireMode(autowireMode);
if (dependencyCheck && getResolvedAutowireMode() != AUTOWIRE_CONSTRUCTOR) {
- setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
+ setDependencyCheck(DEPENDENCY_CHECK_OBJECTS);
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java
index f878c57e..421805cb 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,7 +81,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
- catch (Exception ex) {
+ catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
@@ -171,12 +171,12 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
}
}
catch (IllegalArgumentException ex) {
- throw new BeanInstantiationException(factoryMethod.getReturnType(),
+ throw new BeanInstantiationException(factoryMethod,
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
}
catch (IllegalAccessException ex) {
- throw new BeanInstantiationException(factoryMethod.getReturnType(),
+ throw new BeanInstantiationException(factoryMethod,
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
}
catch (InvocationTargetException ex) {
@@ -186,7 +186,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg;
}
- throw new BeanInstantiationException(factoryMethod.getReturnType(), msg, ex.getTargetException());
+ throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
index 6e064c5d..32866846 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -58,7 +59,31 @@ import org.springframework.util.StringUtils;
public class StaticListableBeanFactory implements ListableBeanFactory {
/** Map from bean name to bean instance */
- private final Map<String, Object> beans = new LinkedHashMap<String, Object>();
+ private final Map<String, Object> beans;
+
+
+ /**
+ * Create a regular {@code StaticListableBeanFactory}, to be populated
+ * with singleton bean instances through {@link #addBean} calls.
+ */
+ public StaticListableBeanFactory() {
+ this.beans = new LinkedHashMap<String, Object>();
+ }
+
+ /**
+ * Create a {@code StaticListableBeanFactory} wrapping the given {@code Map}.
+ * <p>Note that the given {@code Map} may be pre-populated with beans;
+ * or new, still allowing for beans to be registered via {@link #addBean};
+ * or {@link java.util.Collections#emptyMap()} for a dummy factory which
+ * enforces operating against an empty set of beans.
+ * @param beans a {@code Map} for holding this factory's beans, with the
+ * bean name String as key and the corresponding singleton object as value
+ * @since 4.3
+ */
+ public StaticListableBeanFactory(Map<String, Object> beans) {
+ Assert.notNull(beans, "Beans Map must not be null");
+ this.beans = beans;
+ }
/**
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java b/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java
index 494bcd39..6e2f6ad9 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -129,6 +129,10 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
+ "] not matching: " + getReaderContext().getResource());
+ }
return;
}
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomCollectionEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomCollectionEditor.java
index 607a99af..4c63ac79 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomCollectionEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomCollectionEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -154,9 +154,9 @@ public class CustomCollectionEditor extends PropertyEditorSupport {
try {
return collectionType.newInstance();
}
- catch (Exception ex) {
+ catch (Throwable ex) {
throw new IllegalArgumentException(
- "Could not instantiate collection class [" + collectionType.getName() + "]: " + ex.getMessage());
+ "Could not instantiate collection class: " + collectionType.getName(), ex);
}
}
else if (List.class == collectionType) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomMapEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomMapEditor.java
index 85865e54..05b5d872 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomMapEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/CustomMapEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -132,9 +132,9 @@ public class CustomMapEditor extends PropertyEditorSupport {
try {
return mapType.newInstance();
}
- catch (Exception ex) {
+ catch (Throwable ex) {
throw new IllegalArgumentException(
- "Could not instantiate map class [" + mapType.getName() + "]: " + ex.getMessage());
+ "Could not instantiate map class: " + mapType.getName(), ex);
}
}
else if (SortedMap.class == mapType) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/FileEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/FileEditor.java
index a57b69ea..676fd0c6 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/FileEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/FileEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -59,16 +59,14 @@ public class FileEditor extends PropertyEditorSupport {
/**
- * Create a new FileEditor,
- * using the default ResourceEditor underneath.
+ * Create a new FileEditor, using a default ResourceEditor underneath.
*/
public FileEditor() {
this.resourceEditor = new ResourceEditor();
}
/**
- * Create a new FileEditor,
- * using the given ResourceEditor underneath.
+ * Create a new FileEditor, using the given ResourceEditor underneath.
* @param resourceEditor the ResourceEditor to use
*/
public FileEditor(ResourceEditor resourceEditor) {
@@ -105,7 +103,7 @@ public class FileEditor extends PropertyEditorSupport {
}
catch (IOException ex) {
throw new IllegalArgumentException(
- "Could not retrieve File for " + resource + ": " + ex.getMessage());
+ "Could not retrieve file for " + resource + ": " + ex.getMessage());
}
}
else {
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/InputStreamEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/InputStreamEditor.java
index b4b014b7..dc982393 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/InputStreamEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/InputStreamEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -47,16 +47,14 @@ public class InputStreamEditor extends PropertyEditorSupport {
/**
- * Create a new InputStreamEditor,
- * using the default ResourceEditor underneath.
+ * Create a new InputStreamEditor, using the default ResourceEditor underneath.
*/
public InputStreamEditor() {
this.resourceEditor = new ResourceEditor();
}
/**
- * Create a new InputStreamEditor,
- * using the given ResourceEditor underneath.
+ * Create a new InputStreamEditor, using the given ResourceEditor underneath.
* @param resourceEditor the ResourceEditor to use
*/
public InputStreamEditor(ResourceEditor resourceEditor) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java
new file mode 100644
index 00000000..4767b198
--- /dev/null
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/PathEditor.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2002-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.beans.propertyeditors;
+
+import java.beans.PropertyEditorSupport;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceEditor;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.lang.UsesJava7;
+import org.springframework.util.Assert;
+
+/**
+ * Editor for {@code java.nio.file.Path}, to directly populate a Path
+ * property instead of using a String property as bridge.
+ *
+ * <p>Based on {@link Paths#get(URI)}'s resolution algorithm, checking
+ * registered NIO file system providers, including the default file system
+ * for "file:..." paths. Also supports Spring-style URL notation: any fully
+ * qualified standard URL and Spring's special "classpath:" pseudo-URL,
+ * as well as Spring's context-specific relative file paths.
+ *
+ * <p>Note that, in contrast to {@link FileEditor}, relative paths are only
+ * supported by Spring's resource abstraction here. Direct {@code Paths.get}
+ * resolution in a file system always has to go through the corresponding
+ * file system provider's scheme, i.e. "file" for the default file system.
+ *
+ * @author Juergen Hoeller
+ * @since 4.3.2
+ * @see java.nio.file.Path
+ * @see Paths#get(URI)
+ * @see ResourceEditor
+ * @see org.springframework.core.io.ResourceLoader
+ * @see FileEditor
+ * @see URLEditor
+ */
+@UsesJava7
+public class PathEditor extends PropertyEditorSupport {
+
+ private final ResourceEditor resourceEditor;
+
+
+ /**
+ * Create a new PathEditor, using the default ResourceEditor underneath.
+ */
+ public PathEditor() {
+ this.resourceEditor = new ResourceEditor();
+ }
+
+ /**
+ * Create a new PathEditor, using the given ResourceEditor underneath.
+ * @param resourceEditor the ResourceEditor to use
+ */
+ public PathEditor(ResourceEditor resourceEditor) {
+ Assert.notNull(resourceEditor, "ResourceEditor must not be null");
+ this.resourceEditor = resourceEditor;
+ }
+
+
+ @Override
+ public void setAsText(String text) throws IllegalArgumentException {
+ if (!text.startsWith("/") && !text.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX)) {
+ try {
+ URI uri = new URI(text);
+ if (uri.getScheme() != null) {
+ // Let's try NIO file system providers via Paths.get(URI)
+ setValue(Paths.get(uri).normalize());
+ return;
+ }
+ }
+ catch (URISyntaxException ex) {
+ // Not a valid URI: Let's try as Spring resource location.
+ }
+ catch (FileSystemNotFoundException ex) {
+ // URI scheme not registered for NIO:
+ // Let's try URL protocol handlers via Spring's resource mechanism.
+ }
+ }
+
+ this.resourceEditor.setAsText(text);
+ Resource resource = (Resource) this.resourceEditor.getValue();
+ try {
+ setValue(resource != null ? resource.getFile().toPath() : null);
+ }
+ catch (IOException ex) {
+ throw new IllegalArgumentException("Failed to retrieve file for " + resource, ex);
+ }
+ }
+
+ @Override
+ public String getAsText() {
+ Path value = (Path) getValue();
+ return (value != null ? value.toString() : "");
+ }
+
+}
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ReaderEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ReaderEditor.java
index 826760ee..894d9770 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ReaderEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/ReaderEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -47,16 +47,14 @@ public class ReaderEditor extends PropertyEditorSupport {
/**
- * Create a new ReaderEditor,
- * using the default ResourceEditor underneath.
+ * Create a new ReaderEditor, using the default ResourceEditor underneath.
*/
public ReaderEditor() {
this.resourceEditor = new ResourceEditor();
}
/**
- * Create a new ReaderEditor,
- * using the given ResourceEditor underneath.
+ * Create a new ReaderEditor, using the given ResourceEditor underneath.
* @param resourceEditor the ResourceEditor to use
*/
public ReaderEditor(ResourceEditor resourceEditor) {
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java
index c8875b38..85adf515 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/StringArrayPropertyEditor.java
@@ -84,7 +84,7 @@ public class StringArrayPropertyEditor extends PropertyEditorSupport {
* @param emptyArrayAsNull {@code true} if an empty String array
* is to be transformed into {@code null}
* @param trimValues {@code true} if the values in the parsed arrays
- * are to be be trimmed of whitespace (default is true).
+ * are to be trimmed of whitespace (default is true).
*/
public StringArrayPropertyEditor(String separator, boolean emptyArrayAsNull, boolean trimValues) {
this(separator, null, emptyArrayAsNull, trimValues);
@@ -112,7 +112,7 @@ public class StringArrayPropertyEditor extends PropertyEditorSupport {
* @param emptyArrayAsNull {@code true} if an empty String array
* is to be transformed into {@code null}
* @param trimValues {@code true} if the values in the parsed arrays
- * are to be be trimmed of whitespace (default is true).
+ * are to be trimmed of whitespace (default is true).
*/
public StringArrayPropertyEditor(String separator, String charsToDelete, boolean emptyArrayAsNull, boolean trimValues) {
this.separator = separator;
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java
index f5ac6d6a..7dc173a0 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URIEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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,8 +60,7 @@ public class URIEditor extends PropertyEditorSupport {
* standard URIs (not trying to resolve them into physical resources).
*/
public URIEditor() {
- this.classLoader = null;
- this.encode = true;
+ this(true);
}
/**
@@ -74,7 +73,6 @@ public class URIEditor extends PropertyEditorSupport {
this.encode = encode;
}
-
/**
* Create a new URIEditor, using the given ClassLoader to resolve
* "classpath:" locations into physical resource URLs.
@@ -82,8 +80,7 @@ public class URIEditor extends PropertyEditorSupport {
* (may be {@code null} to indicate the default ClassLoader)
*/
public URIEditor(ClassLoader classLoader) {
- this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
- this.encode = true;
+ this(classLoader, true);
}
/**
diff --git a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URLEditor.java b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URLEditor.java
index c5f9755d..85ef824d 100644
--- a/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URLEditor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/propertyeditors/URLEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,7 +50,7 @@ public class URLEditor extends PropertyEditorSupport {
/**
- * Create a new URLEditor, using the default ResourceEditor underneath.
+ * Create a new URLEditor, using a default ResourceEditor underneath.
*/
public URLEditor() {
this.resourceEditor = new ResourceEditor();
diff --git a/spring-beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java b/spring-beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java
index 06d2ee5d..8cffcc78 100644
--- a/spring-beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java
+++ b/spring-beans/src/main/java/org/springframework/beans/support/ResourceEditorRegistrar.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -33,6 +33,7 @@ import org.springframework.beans.propertyeditors.ClassEditor;
import org.springframework.beans.propertyeditors.FileEditor;
import org.springframework.beans.propertyeditors.InputSourceEditor;
import org.springframework.beans.propertyeditors.InputStreamEditor;
+import org.springframework.beans.propertyeditors.PathEditor;
import org.springframework.beans.propertyeditors.ReaderEditor;
import org.springframework.beans.propertyeditors.URIEditor;
import org.springframework.beans.propertyeditors.URLEditor;
@@ -43,6 +44,7 @@ import org.springframework.core.io.ResourceEditor;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourceArrayPropertyEditor;
import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.util.ClassUtils;
/**
* PropertyEditorRegistrar implementation that populates a given
@@ -58,6 +60,19 @@ import org.springframework.core.io.support.ResourcePatternResolver;
*/
public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
+ private static Class<?> pathClass;
+
+ static {
+ try {
+ pathClass = ClassUtils.forName("java.nio.file.Path", ResourceEditorRegistrar.class.getClassLoader());
+ }
+ catch (ClassNotFoundException ex) {
+ // Java 7 Path class not available
+ pathClass = null;
+ }
+ }
+
+
private final PropertyResolver propertyResolver;
private final ResourceLoader resourceLoader;
@@ -103,6 +118,9 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
+ if (pathClass != null) {
+ doRegisterEditor(registry, pathClass, new PathEditor(baseEditor));
+ }
doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));