Consistent UnsatisfiedDependencyException exposure with injection point metadata
Issue: SPR-13968
This commit is contained in:
parent
4c964473b1
commit
b6dd8a9233
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public BeanCreationException(String beanName, String msg) {
|
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;
|
this.beanName = beanName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ public class BeanCreationException extends FatalBeanException {
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public BeanCreationException(String resourceDescription, String beanName, String msg) {
|
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);
|
(resourceDescription != null ? " defined in " + resourceDescription : "") + ": " + msg);
|
||||||
this.resourceDescription = resourceDescription;
|
this.resourceDescription = resourceDescription;
|
||||||
this.beanName = beanName;
|
this.beanName = beanName;
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* factory-aware initialization code fails. BeansExceptions thrown by
|
||||||
* bean factory methods themselves should simply be propagated as-is.
|
* bean factory methods themselves should simply be propagated as-is.
|
||||||
*
|
*
|
||||||
* <p>Note that non-factory-aware initialization methods like afterPropertiesSet()
|
* <p>Note that {@code afterPropertiesSet()} or a custom "init-method"
|
||||||
* or a custom "init-method" can throw any exception.
|
* can throw any exception.
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 13.11.2003
|
* @since 13.11.2003
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,6 +31,9 @@ import org.springframework.util.ClassUtils;
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class UnsatisfiedDependencyException extends BeanCreationException {
|
public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||||
|
|
||||||
|
private InjectionPoint injectionPoint;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new UnsatisfiedDependencyException.
|
* Create a new UnsatisfiedDependencyException.
|
||||||
* @param resourceDescription description of the resource that the bean definition came from
|
* @param resourceDescription description of the resource that the bean definition came from
|
||||||
|
@ -60,6 +63,36 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||||
initCause(ex);
|
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 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.
|
* Create a new UnsatisfiedDependencyException.
|
||||||
* @param resourceDescription description of the resource that the bean definition came from
|
* @param resourceDescription description of the resource that the bean definition came from
|
||||||
|
@ -67,7 +100,9 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||||
* @param ctorArgIndex the index of the constructor argument that couldn't be satisfied
|
* @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 ctorArgType the type of the constructor argument that couldn't be satisfied
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
|
* @deprecated in favor of {@link #UnsatisfiedDependencyException(String, String, InjectionPoint, String)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public UnsatisfiedDependencyException(
|
public UnsatisfiedDependencyException(
|
||||||
String resourceDescription, String beanName, int ctorArgIndex, Class<?> ctorArgType, String msg) {
|
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 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 ctorArgType the type of the constructor argument that couldn't be satisfied
|
||||||
* @param ex the bean creation exception that indicated the unsatisfied dependency
|
* @param ex the bean creation exception that indicated the unsatisfied dependency
|
||||||
|
* @deprecated in favor of {@link #UnsatisfiedDependencyException(String, String, InjectionPoint, BeansException)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public UnsatisfiedDependencyException(
|
public UnsatisfiedDependencyException(
|
||||||
String resourceDescription, String beanName, int ctorArgIndex, Class<?> ctorArgType, BeansException ex) {
|
String resourceDescription, String beanName, int ctorArgIndex, Class<?> ctorArgType, BeansException ex) {
|
||||||
|
|
||||||
|
@ -92,4 +129,13 @@ public class UnsatisfiedDependencyException extends BeanCreationException {
|
||||||
initCause(ex);
|
initCause(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the injection point (field or method/constructor parameter), if known.
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
public InjectionPoint getInjectionPoint() {
|
||||||
|
return this.injectionPoint;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -45,7 +45,9 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.BeanFactoryAware;
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||||
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
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.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||||
|
@ -347,6 +349,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
try {
|
try {
|
||||||
metadata.inject(bean, beanName, pvs);
|
metadata.inject(bean, beanName, pvs);
|
||||||
}
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
|
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
|
||||||
}
|
}
|
||||||
|
@ -365,6 +370,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
try {
|
try {
|
||||||
metadata.inject(bean, null, null);
|
metadata.inject(bean, null, null);
|
||||||
}
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
|
||||||
}
|
}
|
||||||
|
@ -549,7 +557,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
@Override
|
@Override
|
||||||
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
|
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
|
||||||
Field field = (Field) this.member;
|
Field field = (Field) this.member;
|
||||||
try {
|
|
||||||
Object value;
|
Object value;
|
||||||
if (this.cached) {
|
if (this.cached) {
|
||||||
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
|
||||||
|
@ -559,7 +566,12 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
desc.setContainingClass(bean.getClass());
|
desc.setContainingClass(bean.getClass());
|
||||||
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
|
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
|
||||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||||
|
try {
|
||||||
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
||||||
|
}
|
||||||
|
catch (BeansException ex) {
|
||||||
|
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
|
||||||
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!this.cached) {
|
if (!this.cached) {
|
||||||
if (value != null || this.required) {
|
if (value != null || this.required) {
|
||||||
|
@ -586,10 +598,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
field.set(bean, value);
|
field.set(bean, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
|
||||||
throw new BeanCreationException("Could not autowire field: " + field, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -615,7 +623,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Method method = (Method) this.member;
|
Method method = (Method) this.member;
|
||||||
try {
|
|
||||||
Object[] arguments;
|
Object[] arguments;
|
||||||
if (this.cached) {
|
if (this.cached) {
|
||||||
// Shortcut for avoiding synchronization...
|
// Shortcut for avoiding synchronization...
|
||||||
|
@ -629,20 +636,25 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
TypeConverter typeConverter = beanFactory.getTypeConverter();
|
||||||
for (int i = 0; i < arguments.length; i++) {
|
for (int i = 0; i < arguments.length; i++) {
|
||||||
MethodParameter methodParam = new MethodParameter(method, i);
|
MethodParameter methodParam = new MethodParameter(method, i);
|
||||||
DependencyDescriptor desc = new DependencyDescriptor(methodParam, this.required);
|
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
|
||||||
desc.setContainingClass(bean.getClass());
|
currDesc.setContainingClass(bean.getClass());
|
||||||
descriptors[i] = desc;
|
descriptors[i] = currDesc;
|
||||||
Object arg = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
|
try {
|
||||||
|
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
|
||||||
if (arg == null && !this.required) {
|
if (arg == null && !this.required) {
|
||||||
arguments = null;
|
arguments = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
arguments[i] = arg;
|
arguments[i] = arg;
|
||||||
}
|
}
|
||||||
|
catch (BeansException ex) {
|
||||||
|
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!this.cached) {
|
if (!this.cached) {
|
||||||
if (arguments != null) {
|
if (arguments != null) {
|
||||||
this.cachedMethodArguments = new Object[arguments.length];
|
this.cachedMethodArguments = new Object[paramTypes.length];
|
||||||
for (int i = 0; i < arguments.length; i++) {
|
for (int i = 0; i < arguments.length; i++) {
|
||||||
this.cachedMethodArguments[i] = descriptors[i];
|
this.cachedMethodArguments[i] = descriptors[i];
|
||||||
}
|
}
|
||||||
|
@ -667,15 +679,13 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (arguments != null) {
|
if (arguments != null) {
|
||||||
|
try {
|
||||||
ReflectionUtils.makeAccessible(method);
|
ReflectionUtils.makeAccessible(method);
|
||||||
method.invoke(bean, arguments);
|
method.invoke(bean, arguments);
|
||||||
}
|
}
|
||||||
}
|
catch (InvocationTargetException ex){
|
||||||
catch (InvocationTargetException ex) {
|
|
||||||
throw ex.getTargetException();
|
throw ex.getTargetException();
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
|
||||||
throw new BeanCreationException("Could not autowire method: " + method, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.springframework.beans.factory.config;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
@ -27,13 +26,13 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
import org.springframework.core.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Descriptor for a specific dependency that is about to be injected.
|
* Descriptor for a specific dependency that is about to be injected.
|
||||||
|
@ -44,15 +43,9 @@ import org.springframework.util.Assert;
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class DependencyDescriptor implements Serializable {
|
public class DependencyDescriptor extends InjectionPoint implements Serializable {
|
||||||
|
|
||||||
private transient MethodParameter methodParameter;
|
private final Class<?> declaringClass;
|
||||||
|
|
||||||
private transient Field field;
|
|
||||||
|
|
||||||
private Class<?> declaringClass;
|
|
||||||
|
|
||||||
private Class<?> containingClass;
|
|
||||||
|
|
||||||
private String methodName;
|
private String methodName;
|
||||||
|
|
||||||
|
@ -68,7 +61,7 @@ public class DependencyDescriptor implements Serializable {
|
||||||
|
|
||||||
private int nestingLevel = 1;
|
private int nestingLevel = 1;
|
||||||
|
|
||||||
private transient Annotation[] fieldAnnotations;
|
private Class<?> containingClass;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,10 +82,8 @@ public class DependencyDescriptor implements Serializable {
|
||||||
* eagerly resolving potential target beans for type matching
|
* eagerly resolving potential target beans for type matching
|
||||||
*/
|
*/
|
||||||
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
|
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
|
||||||
Assert.notNull(methodParameter, "MethodParameter must not be null");
|
super(methodParameter);
|
||||||
this.methodParameter = methodParameter;
|
|
||||||
this.declaringClass = methodParameter.getDeclaringClass();
|
this.declaringClass = methodParameter.getDeclaringClass();
|
||||||
this.containingClass = methodParameter.getContainingClass();
|
|
||||||
if (this.methodParameter.getMethod() != null) {
|
if (this.methodParameter.getMethod() != null) {
|
||||||
this.methodName = methodParameter.getMethod().getName();
|
this.methodName = methodParameter.getMethod().getName();
|
||||||
this.parameterTypes = methodParameter.getMethod().getParameterTypes();
|
this.parameterTypes = methodParameter.getMethod().getParameterTypes();
|
||||||
|
@ -101,6 +92,7 @@ public class DependencyDescriptor implements Serializable {
|
||||||
this.parameterTypes = methodParameter.getConstructor().getParameterTypes();
|
this.parameterTypes = methodParameter.getConstructor().getParameterTypes();
|
||||||
}
|
}
|
||||||
this.parameterIndex = methodParameter.getParameterIndex();
|
this.parameterIndex = methodParameter.getParameterIndex();
|
||||||
|
this.containingClass = methodParameter.getContainingClass();
|
||||||
this.required = required;
|
this.required = required;
|
||||||
this.eager = eager;
|
this.eager = eager;
|
||||||
}
|
}
|
||||||
|
@ -123,8 +115,7 @@ public class DependencyDescriptor implements Serializable {
|
||||||
* eagerly resolving potential target beans for type matching
|
* eagerly resolving potential target beans for type matching
|
||||||
*/
|
*/
|
||||||
public DependencyDescriptor(Field field, boolean required, boolean eager) {
|
public DependencyDescriptor(Field field, boolean required, boolean eager) {
|
||||||
Assert.notNull(field, "Field must not be null");
|
super(field);
|
||||||
this.field = field;
|
|
||||||
this.declaringClass = field.getDeclaringClass();
|
this.declaringClass = field.getDeclaringClass();
|
||||||
this.fieldName = field.getName();
|
this.fieldName = field.getName();
|
||||||
this.required = required;
|
this.required = required;
|
||||||
|
@ -136,39 +127,19 @@ public class DependencyDescriptor implements Serializable {
|
||||||
* @param original the original descriptor to create a copy from
|
* @param original the original descriptor to create a copy from
|
||||||
*/
|
*/
|
||||||
public DependencyDescriptor(DependencyDescriptor original) {
|
public DependencyDescriptor(DependencyDescriptor original) {
|
||||||
this.methodParameter = (original.methodParameter != null ? new MethodParameter(original.methodParameter) : null);
|
super(original);
|
||||||
this.field = original.field;
|
|
||||||
this.declaringClass = original.declaringClass;
|
this.declaringClass = original.declaringClass;
|
||||||
this.containingClass = original.containingClass;
|
|
||||||
this.methodName = original.methodName;
|
this.methodName = original.methodName;
|
||||||
this.parameterTypes = original.parameterTypes;
|
this.parameterTypes = original.parameterTypes;
|
||||||
this.parameterIndex = original.parameterIndex;
|
this.parameterIndex = original.parameterIndex;
|
||||||
this.fieldName = original.fieldName;
|
this.fieldName = original.fieldName;
|
||||||
|
this.containingClass = original.containingClass;
|
||||||
this.required = original.required;
|
this.required = original.required;
|
||||||
this.eager = original.eager;
|
this.eager = original.eager;
|
||||||
this.nestingLevel = original.nestingLevel;
|
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
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether this dependency is required.
|
* Return whether this dependency is required.
|
||||||
*/
|
*/
|
||||||
|
@ -358,19 +329,18 @@ public class DependencyDescriptor implements Serializable {
|
||||||
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the annotations associated with the wrapped parameter/field, if any.
|
@Override
|
||||||
*/
|
public boolean equals(Object other) {
|
||||||
public Annotation[] getAnnotations() {
|
if (this == other) {
|
||||||
if (this.field != null) {
|
return true;
|
||||||
if (this.fieldAnnotations == null) {
|
|
||||||
this.fieldAnnotations = this.field.getAnnotations();
|
|
||||||
}
|
}
|
||||||
return this.fieldAnnotations;
|
if (!super.equals(other)) {
|
||||||
}
|
return false;
|
||||||
else {
|
|
||||||
return this.methodParameter.getParameterAnnotations();
|
|
||||||
}
|
}
|
||||||
|
DependencyDescriptor otherDesc = (DependencyDescriptor) other;
|
||||||
|
return (this.required == otherDesc.required && this.eager == otherDesc.eager &&
|
||||||
|
this.nestingLevel == otherDesc.nestingLevel && this.containingClass == otherDesc.containingClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -40,6 +40,7 @@ import org.springframework.beans.TypeConverter;
|
||||||
import org.springframework.beans.TypeMismatchException;
|
import org.springframework.beans.TypeMismatchException;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||||
|
@ -159,8 +160,7 @@ class ConstructorResolver {
|
||||||
Set<Constructor<?>> ambiguousConstructors = null;
|
Set<Constructor<?>> ambiguousConstructors = null;
|
||||||
LinkedList<UnsatisfiedDependencyException> causes = null;
|
LinkedList<UnsatisfiedDependencyException> causes = null;
|
||||||
|
|
||||||
for (int i = 0; i < candidates.length; i++) {
|
for (Constructor<?> candidate : candidates) {
|
||||||
Constructor<?> candidate = candidates[i];
|
|
||||||
Class<?>[] paramTypes = candidate.getParameterTypes();
|
Class<?>[] paramTypes = candidate.getParameterTypes();
|
||||||
|
|
||||||
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
|
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
|
||||||
|
@ -665,7 +665,6 @@ class ConstructorResolver {
|
||||||
BeanWrapper bw, Class<?>[] paramTypes, String[] paramNames, Object methodOrCtor,
|
BeanWrapper bw, Class<?>[] paramTypes, String[] paramNames, Object methodOrCtor,
|
||||||
boolean autowiring) throws UnsatisfiedDependencyException {
|
boolean autowiring) throws UnsatisfiedDependencyException {
|
||||||
|
|
||||||
String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
|
|
||||||
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
|
||||||
this.beanFactory.getCustomTypeConverter() : bw);
|
this.beanFactory.getCustomTypeConverter() : bw);
|
||||||
|
|
||||||
|
@ -700,9 +699,9 @@ class ConstructorResolver {
|
||||||
ConstructorArgumentValues.ValueHolder sourceHolder =
|
ConstructorArgumentValues.ValueHolder sourceHolder =
|
||||||
(ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
|
(ConstructorArgumentValues.ValueHolder) valueHolder.getSource();
|
||||||
Object sourceValue = sourceHolder.getValue();
|
Object sourceValue = sourceHolder.getValue();
|
||||||
|
MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex);
|
||||||
try {
|
try {
|
||||||
convertedValue = converter.convertIfNecessary(originalValue, paramType,
|
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
|
||||||
MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex));
|
|
||||||
// TODO re-enable once race condition has been found (SPR-7423)
|
// TODO re-enable once race condition has been found (SPR-7423)
|
||||||
/*
|
/*
|
||||||
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
|
if (originalValue == sourceValue || sourceValue instanceof TypedStringValue) {
|
||||||
|
@ -718,8 +717,8 @@ class ConstructorResolver {
|
||||||
}
|
}
|
||||||
catch (TypeMismatchException ex) {
|
catch (TypeMismatchException ex) {
|
||||||
throw new UnsatisfiedDependencyException(
|
throw new UnsatisfiedDependencyException(
|
||||||
mbd.getResourceDescription(), beanName, paramIndex, paramType,
|
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
|
||||||
"Could not convert " + methodType + " argument value of type [" +
|
"Could not convert argument value of type [" +
|
||||||
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
|
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
|
||||||
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -728,17 +727,18 @@ class ConstructorResolver {
|
||||||
args.rawArguments[paramIndex] = originalValue;
|
args.rawArguments[paramIndex] = originalValue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex);
|
||||||
// No explicit match found: we're either supposed to autowire or
|
// No explicit match found: we're either supposed to autowire or
|
||||||
// have to fail creating an argument array for the given constructor.
|
// have to fail creating an argument array for the given constructor.
|
||||||
if (!autowiring) {
|
if (!autowiring) {
|
||||||
throw new UnsatisfiedDependencyException(
|
throw new UnsatisfiedDependencyException(
|
||||||
mbd.getResourceDescription(), beanName, paramIndex, paramType,
|
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
|
||||||
"Ambiguous " + methodType + " argument types - " +
|
"Ambiguous argument values for parameter of type [" + paramType.getName() +
|
||||||
"did you specify the correct bean references as " + methodType + " arguments?");
|
"] - did you specify the correct bean references as arguments?");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
MethodParameter param = MethodParameter.forMethodOrConstructor(methodOrCtor, paramIndex);
|
Object autowiredArgument =
|
||||||
Object autowiredArgument = resolveAutowiredArgument(param, beanName, autowiredBeanNames, converter);
|
resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter);
|
||||||
args.rawArguments[paramIndex] = autowiredArgument;
|
args.rawArguments[paramIndex] = autowiredArgument;
|
||||||
args.arguments[paramIndex] = autowiredArgument;
|
args.arguments[paramIndex] = autowiredArgument;
|
||||||
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
|
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
|
||||||
|
@ -746,7 +746,7 @@ class ConstructorResolver {
|
||||||
}
|
}
|
||||||
catch (BeansException ex) {
|
catch (BeansException ex) {
|
||||||
throw new UnsatisfiedDependencyException(
|
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);
|
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
|
||||||
if (this.beanFactory.logger.isDebugEnabled()) {
|
if (this.beanFactory.logger.isDebugEnabled()) {
|
||||||
this.beanFactory.logger.debug("Autowiring by type from bean name '" + beanName +
|
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 + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,11 +794,9 @@ class ConstructorResolver {
|
||||||
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
|
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
|
||||||
}
|
}
|
||||||
catch (TypeMismatchException ex) {
|
catch (TypeMismatchException ex) {
|
||||||
String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
|
|
||||||
throw new UnsatisfiedDependencyException(
|
throw new UnsatisfiedDependencyException(
|
||||||
mbd.getResourceDescription(), beanName, argIndex, paramType,
|
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
|
||||||
"Could not convert " + methodType + " argument value of type [" +
|
"Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
|
||||||
ObjectUtils.nullSafeClassName(argValue) +
|
|
||||||
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.springframework.beans.factory;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -49,8 +65,7 @@ public class Spr5475Tests {
|
||||||
cav.addIndexedArgumentValue(1, "bogusArg2".getBytes());
|
cav.addIndexedArgumentValue(1, "bogusArg2".getBytes());
|
||||||
def.setConstructorArgumentValues(cav);
|
def.setConstructorArgumentValues(cav);
|
||||||
|
|
||||||
assertExceptionMessageForMisconfiguredFactoryMethod(
|
assertExceptionMessageForMisconfiguredFactoryMethod(def,
|
||||||
def,
|
|
||||||
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(CharSequence,byte[])'. " +
|
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(CharSequence,byte[])'. " +
|
||||||
"Check that a method with the specified name and arguments exists and that it is static.");
|
"Check that a method with the specified name and arguments exists and that it is static.");
|
||||||
}
|
}
|
||||||
|
@ -62,7 +77,8 @@ public class Spr5475Tests {
|
||||||
try {
|
try {
|
||||||
factory.preInstantiateSingletons();
|
factory.preInstantiateSingletons();
|
||||||
fail("should have failed with BeanCreationException due to incorrectly invoked factory method");
|
fail("should have failed with BeanCreationException due to incorrectly invoked factory method");
|
||||||
} catch (BeanCreationException ex) {
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
assertThat(ex.getMessage(), equalTo(expectedMessage));
|
assertThat(ex.getMessage(), equalTo(expectedMessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,15 +88,17 @@ public class Spr5475Tests {
|
||||||
// calling a factory method that accepts arguments without any arguments emits an exception unlike cases
|
// calling a factory method that accepts arguments without any arguments emits an exception unlike cases
|
||||||
// where a no-arg factory method is called with arguments. Adding this test just to document the difference
|
// where a no-arg factory method is called with arguments. Adding this test just to document the difference
|
||||||
assertExceptionMessageForMisconfiguredFactoryMethod(
|
assertExceptionMessageForMisconfiguredFactoryMethod(
|
||||||
rootBeanDefinition(Foo.class)
|
rootBeanDefinition(Foo.class).
|
||||||
.setFactoryMethod("singleArgFactory").getBeanDefinition(),
|
setFactoryMethod("singleArgFactory").getBeanDefinition(),
|
||||||
"Error creating bean with name 'foo': " +
|
"Error creating bean with name 'foo': " +
|
||||||
"Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]: " +
|
"Unsatisfied dependency expressed through method 'singleArgFactory' parameter 0: " +
|
||||||
"Ambiguous factory method argument types - did you specify the correct bean references as factory method arguments?");
|
"Ambiguous argument values for parameter of type [java.lang.String] - " +
|
||||||
|
"did you specify the correct bean references as arguments?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class Foo {
|
static class Foo {
|
||||||
|
|
||||||
static Foo noArgFactory() {
|
static Foo noArgFactory() {
|
||||||
return new Foo();
|
return new Foo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
bf.registerBeanDefinition("testBean", new GenericBeanDefinition());
|
bf.registerBeanDefinition("testBean", new GenericBeanDefinition());
|
||||||
try {
|
try {
|
||||||
bf.getBean("testBean");
|
bf.getBean("testBean");
|
||||||
|
fail("Should have thrown BeanCreationException");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException ex) {
|
catch (BeanCreationException ex) {
|
||||||
assertTrue(ex.getRootCause() instanceof IllegalStateException);
|
assertTrue(ex.getRootCause() instanceof IllegalStateException);
|
||||||
|
@ -635,6 +636,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
}
|
}
|
||||||
catch (UnsatisfiedDependencyException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertSame(ConstructorWithoutFallbackBean.class, ex.getInjectionPoint().getMethodParameter().getDeclaringClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,8 +840,9 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
bf.getBean("annotatedBean");
|
bf.getBean("annotatedBean");
|
||||||
fail("should have failed, more than one bean of type");
|
fail("should have failed, more than one bean of type");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertSame(MapMethodInjectionBean.class, ex.getInjectionPoint().getMethodParameter().getDeclaringClass());
|
||||||
}
|
}
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1164,7 +1167,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
bf.registerSingleton("testBean", tb);
|
bf.registerSingleton("testBean", tb);
|
||||||
|
|
||||||
CustomAnnotationRequiredFieldResourceInjectionBean bean = (CustomAnnotationRequiredFieldResourceInjectionBean) bf.getBean("customBean");
|
CustomAnnotationRequiredFieldResourceInjectionBean bean =
|
||||||
|
(CustomAnnotationRequiredFieldResourceInjectionBean) bf.getBean("customBean");
|
||||||
assertSame(tb, bean.getTestBean());
|
assertSame(tb, bean.getTestBean());
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1183,10 +1187,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bf.getBean("customBean");
|
bf.getBean("customBean");
|
||||||
fail("expected BeanCreationException; no dependency available for required field");
|
fail("Should have thrown UnsatisfiedDependencyException");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertSame(CustomAnnotationRequiredFieldResourceInjectionBean.class,
|
||||||
|
ex.getInjectionPoint().getField().getDeclaringClass());
|
||||||
}
|
}
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1209,10 +1215,13 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bf.getBean("customBean");
|
bf.getBean("customBean");
|
||||||
fail("expected BeanCreationException; multiple beans of dependency type available");
|
fail("Should have thrown UnsatisfiedDependencyException");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
ex.printStackTrace();
|
||||||
|
assertSame(CustomAnnotationRequiredFieldResourceInjectionBean.class,
|
||||||
|
ex.getInjectionPoint().getField().getDeclaringClass());
|
||||||
}
|
}
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1231,7 +1240,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
bf.registerSingleton("testBean", tb);
|
bf.registerSingleton("testBean", tb);
|
||||||
|
|
||||||
CustomAnnotationRequiredMethodResourceInjectionBean bean = (CustomAnnotationRequiredMethodResourceInjectionBean) bf.getBean("customBean");
|
CustomAnnotationRequiredMethodResourceInjectionBean bean =
|
||||||
|
(CustomAnnotationRequiredMethodResourceInjectionBean) bf.getBean("customBean");
|
||||||
assertSame(tb, bean.getTestBean());
|
assertSame(tb, bean.getTestBean());
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1250,10 +1260,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bf.getBean("customBean");
|
bf.getBean("customBean");
|
||||||
fail("expected BeanCreationException; no dependency available for required method");
|
fail("Should have thrown UnsatisfiedDependencyException");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException e) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertSame(CustomAnnotationRequiredMethodResourceInjectionBean.class,
|
||||||
|
ex.getInjectionPoint().getMethodParameter().getDeclaringClass());
|
||||||
}
|
}
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1276,10 +1288,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bf.getBean("customBean");
|
bf.getBean("customBean");
|
||||||
fail("expected BeanCreationException; multiple beans of dependency type available");
|
fail("Should have thrown UnsatisfiedDependencyException");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertSame(CustomAnnotationRequiredMethodResourceInjectionBean.class,
|
||||||
|
ex.getInjectionPoint().getMethodParameter().getDeclaringClass());
|
||||||
}
|
}
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1298,7 +1312,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
bf.registerSingleton("testBean", tb);
|
bf.registerSingleton("testBean", tb);
|
||||||
|
|
||||||
CustomAnnotationOptionalFieldResourceInjectionBean bean = (CustomAnnotationOptionalFieldResourceInjectionBean) bf.getBean("customBean");
|
CustomAnnotationOptionalFieldResourceInjectionBean bean =
|
||||||
|
(CustomAnnotationOptionalFieldResourceInjectionBean) bf.getBean("customBean");
|
||||||
assertSame(tb, bean.getTestBean3());
|
assertSame(tb, bean.getTestBean3());
|
||||||
assertNull(bean.getTestBean());
|
assertNull(bean.getTestBean());
|
||||||
assertNull(bean.getTestBean2());
|
assertNull(bean.getTestBean2());
|
||||||
|
@ -1317,7 +1332,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
bf.registerBeanDefinition("customBean", new RootBeanDefinition(
|
bf.registerBeanDefinition("customBean", new RootBeanDefinition(
|
||||||
CustomAnnotationOptionalFieldResourceInjectionBean.class));
|
CustomAnnotationOptionalFieldResourceInjectionBean.class));
|
||||||
|
|
||||||
CustomAnnotationOptionalFieldResourceInjectionBean bean = (CustomAnnotationOptionalFieldResourceInjectionBean) bf.getBean("customBean");
|
CustomAnnotationOptionalFieldResourceInjectionBean bean =
|
||||||
|
(CustomAnnotationOptionalFieldResourceInjectionBean) bf.getBean("customBean");
|
||||||
assertNull(bean.getTestBean3());
|
assertNull(bean.getTestBean3());
|
||||||
assertNull(bean.getTestBean());
|
assertNull(bean.getTestBean());
|
||||||
assertNull(bean.getTestBean2());
|
assertNull(bean.getTestBean2());
|
||||||
|
@ -1342,10 +1358,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bf.getBean("customBean");
|
bf.getBean("customBean");
|
||||||
fail("expected BeanCreationException; multiple beans of dependency type available");
|
fail("Should have thrown UnsatisfiedDependencyException");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertSame(CustomAnnotationOptionalFieldResourceInjectionBean.class,
|
||||||
|
ex.getInjectionPoint().getField().getDeclaringClass());
|
||||||
}
|
}
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -1364,7 +1382,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
bf.registerSingleton("testBean", tb);
|
bf.registerSingleton("testBean", tb);
|
||||||
|
|
||||||
CustomAnnotationOptionalMethodResourceInjectionBean bean = (CustomAnnotationOptionalMethodResourceInjectionBean) bf.getBean("customBean");
|
CustomAnnotationOptionalMethodResourceInjectionBean bean =
|
||||||
|
(CustomAnnotationOptionalMethodResourceInjectionBean) bf.getBean("customBean");
|
||||||
assertSame(tb, bean.getTestBean3());
|
assertSame(tb, bean.getTestBean3());
|
||||||
assertNull(bean.getTestBean());
|
assertNull(bean.getTestBean());
|
||||||
assertNull(bean.getTestBean2());
|
assertNull(bean.getTestBean2());
|
||||||
|
@ -1383,7 +1402,8 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
bf.registerBeanDefinition("customBean", new RootBeanDefinition(
|
bf.registerBeanDefinition("customBean", new RootBeanDefinition(
|
||||||
CustomAnnotationOptionalMethodResourceInjectionBean.class));
|
CustomAnnotationOptionalMethodResourceInjectionBean.class));
|
||||||
|
|
||||||
CustomAnnotationOptionalMethodResourceInjectionBean bean = (CustomAnnotationOptionalMethodResourceInjectionBean) bf.getBean("customBean");
|
CustomAnnotationOptionalMethodResourceInjectionBean bean =
|
||||||
|
(CustomAnnotationOptionalMethodResourceInjectionBean) bf.getBean("customBean");
|
||||||
assertNull(bean.getTestBean3());
|
assertNull(bean.getTestBean3());
|
||||||
assertNull(bean.getTestBean());
|
assertNull(bean.getTestBean());
|
||||||
assertNull(bean.getTestBean2());
|
assertNull(bean.getTestBean2());
|
||||||
|
@ -1408,10 +1428,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bf.getBean("customBean");
|
bf.getBean("customBean");
|
||||||
fail("expected BeanCreationException; multiple beans of dependency type available");
|
fail("Should have thrown UnsatisfiedDependencyException");
|
||||||
}
|
}
|
||||||
catch (BeanCreationException ex) {
|
catch (UnsatisfiedDependencyException ex) {
|
||||||
// expected
|
// expected
|
||||||
|
assertSame(CustomAnnotationOptionalMethodResourceInjectionBean.class,
|
||||||
|
ex.getInjectionPoint().getMethodParameter().getDeclaringClass());
|
||||||
}
|
}
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
@ -2644,7 +2666,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public static @interface MyAutowired {
|
public @interface MyAutowired {
|
||||||
|
|
||||||
boolean optional() default false;
|
boolean optional() default false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,14 @@ public class MethodParameter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the wrapped member.
|
* Return the class that declares the underlying Method or Constructor.
|
||||||
|
*/
|
||||||
|
public Class<?> getDeclaringClass() {
|
||||||
|
return getMember().getDeclaringClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the wrapped member.
|
||||||
* @return the Method or Constructor as Member
|
* @return the Method or Constructor as Member
|
||||||
*/
|
*/
|
||||||
public Member getMember() {
|
public Member getMember() {
|
||||||
|
@ -196,7 +203,9 @@ public class MethodParameter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the wrapped annotated element.
|
* Return the wrapped annotated element.
|
||||||
|
* <p>Note: This method exposes the annotations declared on the method/constructor
|
||||||
|
* itself (i.e. at the method/constructor level, not at the parameter level).
|
||||||
* @return the Method or Constructor as AnnotatedElement
|
* @return the Method or Constructor as AnnotatedElement
|
||||||
*/
|
*/
|
||||||
public AnnotatedElement getAnnotatedElement() {
|
public AnnotatedElement getAnnotatedElement() {
|
||||||
|
@ -211,13 +220,6 @@ public class MethodParameter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the class that declares the underlying Method or Constructor.
|
|
||||||
*/
|
|
||||||
public Class<?> getDeclaringClass() {
|
|
||||||
return getMember().getDeclaringClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the index of the method/constructor parameter.
|
* Return the index of the method/constructor parameter.
|
||||||
* @return the parameter index (-1 in case of the return type)
|
* @return the parameter index (-1 in case of the return type)
|
||||||
|
@ -577,6 +579,12 @@ public class MethodParameter {
|
||||||
return (getMember().hashCode() * 31 + this.parameterIndex);
|
return (getMember().hashCode() * 31 + this.parameterIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (this.method != null ? "method '" + this.method.getName() + "'" : "constructor") +
|
||||||
|
" parameter " + this.parameterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodParameter clone() {
|
public MethodParameter clone() {
|
||||||
return new MethodParameter(this);
|
return new MethodParameter(this);
|
||||||
|
|
Loading…
Reference in New Issue