Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
62e5585c
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
62e5585c
编写于
3月 23, 2019
作者:
J
Juergen Hoeller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Avoid package cycle between beans.factory.annotation and b.f.support
See gh-2060
上级
5e15338a
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
371 addition
and
298 deletion
+371
-298
spring-beans/src/main/java/org/springframework/beans/factory/annotation/ParameterResolutionDelegate.java
...beans/factory/annotation/ParameterResolutionDelegate.java
+171
-0
spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java
.../springframework/beans/factory/support/AutowireUtils.java
+7
-140
spring-beans/src/test/java/org/springframework/beans/factory/annotation/ParameterResolutionTests.java
...rk/beans/factory/annotation/ParameterResolutionTests.java
+171
-0
spring-beans/src/test/java/org/springframework/beans/factory/support/AutowireUtilsTests.java
...ngframework/beans/factory/support/AutowireUtilsTests.java
+12
-147
spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java
...framework/test/context/junit/jupiter/SpringExtension.java
+10
-11
未找到文件。
spring-beans/src/main/java/org/springframework/beans/factory/annotation/ParameterResolutionDelegate.java
0 → 100644
浏览文件 @
62e5585c
/*
* Copyright 2002-2019 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.annotation
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.AnnotatedElement
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Executable
;
import
java.lang.reflect.Parameter
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.config.AutowireCapableBeanFactory
;
import
org.springframework.beans.factory.config.DependencyDescriptor
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.core.annotation.AnnotatedElementUtils
;
import
org.springframework.core.annotation.SynthesizingMethodParameter
;
import
org.springframework.lang.Nullable
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ClassUtils
;
/**
* Public delegate for resolving autowirable parameters on externally managed
* constructors and methods.
*
* @author Sam Brannen
* @author Juergen Hoeller
* @since 5.2
* @see #isAutowirable
* @see #resolveDependency
*/
public
final
class
ParameterResolutionDelegate
{
private
static
final
AnnotatedElement
EMPTY_ANNOTATED_ELEMENT
=
new
AnnotatedElement
()
{
@Override
@Nullable
public
<
T
extends
Annotation
>
T
getAnnotation
(
Class
<
T
>
annotationClass
)
{
return
null
;
}
@Override
public
Annotation
[]
getAnnotations
()
{
return
new
Annotation
[
0
];
}
@Override
public
Annotation
[]
getDeclaredAnnotations
()
{
return
new
Annotation
[
0
];
}
};
private
ParameterResolutionDelegate
()
{
}
/**
* Determine if the supplied {@link Parameter} can <em>potentially</em> be
* autowired from an {@link AutowireCapableBeanFactory}.
* <p>Returns {@code true} if the supplied parameter is annotated or
* meta-annotated with {@link Autowired @Autowired},
* {@link Qualifier @Qualifier}, or {@link Value @Value}.
* <p>Note that {@link #resolveDependency} may still be able to resolve the
* dependency for the supplied parameter even if this method returns {@code false}.
* @param parameter the parameter whose dependency should be autowired
* (must not be {@code null})
* @param parameterIndex the index of the parameter in the constructor or method
* that declares the parameter
* @see #resolveDependency
*/
public
static
boolean
isAutowirable
(
Parameter
parameter
,
int
parameterIndex
)
{
Assert
.
notNull
(
parameter
,
"Parameter must not be null"
);
AnnotatedElement
annotatedParameter
=
getEffectiveAnnotatedParameter
(
parameter
,
parameterIndex
);
return
(
AnnotatedElementUtils
.
hasAnnotation
(
annotatedParameter
,
Autowired
.
class
)
||
AnnotatedElementUtils
.
hasAnnotation
(
annotatedParameter
,
Qualifier
.
class
)
||
AnnotatedElementUtils
.
hasAnnotation
(
annotatedParameter
,
Value
.
class
));
}
/**
* Resolve the dependency for the supplied {@link Parameter} from the
* supplied {@link AutowireCapableBeanFactory}.
* <p>Provides comprehensive autowiring support for individual method parameters
* on par with Spring's dependency injection facilities for autowired fields and
* methods, including support for {@link Autowired @Autowired},
* {@link Qualifier @Qualifier}, and {@link Value @Value} with support for property
* placeholders and SpEL expressions in {@code @Value} declarations.
* <p>The dependency is required unless the parameter is annotated or meta-annotated
* with {@link Autowired @Autowired} with the {@link Autowired#required required}
* flag set to {@code false}.
* <p>If an explicit <em>qualifier</em> is not declared, the name of the parameter
* will be used as the qualifier for resolving ambiguities.
* @param parameter the parameter whose dependency should be resolved (must not be
* {@code null})
* @param parameterIndex the index of the parameter in the constructor or method
* that declares the parameter
* @param containingClass the concrete class that contains the parameter; this may
* differ from the class that declares the parameter in that it may be a subclass
* thereof, potentially substituting type variables (must not be {@code null})
* @param beanFactory the {@code AutowireCapableBeanFactory} from which to resolve
* the dependency (must not be {@code null})
* @return the resolved object, or {@code null} if none found
* @throws BeansException if dependency resolution failed
* @see #isAutowirable
* @see Autowired#required
* @see SynthesizingMethodParameter#forExecutable(Executable, int)
* @see AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String)
*/
@Nullable
public
static
Object
resolveDependency
(
Parameter
parameter
,
int
parameterIndex
,
Class
<?>
containingClass
,
AutowireCapableBeanFactory
beanFactory
)
throws
BeansException
{
Assert
.
notNull
(
parameter
,
"Parameter must not be null"
);
Assert
.
notNull
(
containingClass
,
"Containing class must not be null"
);
Assert
.
notNull
(
beanFactory
,
"AutowireCapableBeanFactory must not be null"
);
AnnotatedElement
annotatedParameter
=
getEffectiveAnnotatedParameter
(
parameter
,
parameterIndex
);
Autowired
autowired
=
AnnotatedElementUtils
.
findMergedAnnotation
(
annotatedParameter
,
Autowired
.
class
);
boolean
required
=
(
autowired
==
null
||
autowired
.
required
());
MethodParameter
methodParameter
=
SynthesizingMethodParameter
.
forExecutable
(
parameter
.
getDeclaringExecutable
(),
parameterIndex
);
DependencyDescriptor
descriptor
=
new
DependencyDescriptor
(
methodParameter
,
required
);
descriptor
.
setContainingClass
(
containingClass
);
return
beanFactory
.
resolveDependency
(
descriptor
,
null
);
}
/**
* Due to a bug in {@code javac} on JDK versions prior to JDK 9, looking up
* annotations directly on a {@link Parameter} will fail for inner class
* constructors.
* <h4>Bug in javac in JDK < 9</h4>
* <p>The parameter annotations array in the compiled byte code excludes an entry
* for the implicit <em>enclosing instance</em> parameter for an inner class
* constructor.
* <h4>Workaround</h4>
* <p>This method provides a workaround for this off-by-one error by allowing the
* caller to access annotations on the preceding {@link Parameter} object (i.e.,
* {@code index - 1}). If the supplied {@code index} is zero, this method returns
* an empty {@code AnnotatedElement}.
* <h4>WARNING</h4>
* <p>The {@code AnnotatedElement} returned by this method should never be cast and
* treated as a {@code Parameter} since the metadata (e.g., {@link Parameter#getName()},
* {@link Parameter#getType()}, etc.) will not match those for the declared parameter
* at the given index in an inner class constructor.
* @return the supplied {@code parameter} or the <em>effective</em> {@code Parameter}
* if the aforementioned bug is in effect
*/
private
static
AnnotatedElement
getEffectiveAnnotatedParameter
(
Parameter
parameter
,
int
index
)
{
Executable
executable
=
parameter
.
getDeclaringExecutable
();
if
(
executable
instanceof
Constructor
&&
ClassUtils
.
isInnerClass
(
executable
.
getDeclaringClass
())
&&
executable
.
getParameterAnnotations
().
length
==
executable
.
getParameterCount
()
-
1
)
{
// Bug in javac in JDK <9: annotation array excludes enclosing instance parameter
// for inner classes, so access it with the actual parameter index lowered by 1
return
(
index
==
0
?
EMPTY_ANNOTATED_ELEMENT
:
executable
.
getParameters
()[
index
-
1
]);
}
return
parameter
;
}
}
spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java
浏览文件 @
62e5585c
...
@@ -18,15 +18,12 @@ package org.springframework.beans.factory.support;
...
@@ -18,15 +18,12 @@ package org.springframework.beans.factory.support;
import
java.beans.PropertyDescriptor
;
import
java.beans.PropertyDescriptor
;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.AnnotatedElement
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Executable
;
import
java.lang.reflect.Executable
;
import
java.lang.reflect.InvocationHandler
;
import
java.lang.reflect.InvocationHandler
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Modifier
;
import
java.lang.reflect.Modifier
;
import
java.lang.reflect.Parameter
;
import
java.lang.reflect.ParameterizedType
;
import
java.lang.reflect.ParameterizedType
;
import
java.lang.reflect.Proxy
;
import
java.lang.reflect.Proxy
;
import
java.lang.reflect.Type
;
import
java.lang.reflect.Type
;
...
@@ -36,17 +33,8 @@ import java.util.Comparator;
...
@@ -36,17 +33,8 @@ import java.util.Comparator;
import
java.util.Set
;
import
java.util.Set
;
import
org.springframework.beans.BeanMetadataElement
;
import
org.springframework.beans.BeanMetadataElement
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.ObjectFactory
;
import
org.springframework.beans.factory.ObjectFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.config.AutowireCapableBeanFactory
;
import
org.springframework.beans.factory.config.DependencyDescriptor
;
import
org.springframework.beans.factory.config.TypedStringValue
;
import
org.springframework.beans.factory.config.TypedStringValue
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.core.annotation.AnnotatedElementUtils
;
import
org.springframework.core.annotation.SynthesizingMethodParameter
;
import
org.springframework.lang.Nullable
;
import
org.springframework.lang.Nullable
;
import
org.springframework.util.Assert
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.util.ClassUtils
;
...
@@ -61,29 +49,13 @@ import org.springframework.util.ClassUtils;
...
@@ -61,29 +49,13 @@ import org.springframework.util.ClassUtils;
* @since 1.1.2
* @since 1.1.2
* @see AbstractAutowireCapableBeanFactory
* @see AbstractAutowireCapableBeanFactory
*/
*/
public
abstract
class
AutowireUtils
{
abstract
class
AutowireUtils
{
private
static
final
Comparator
<
Executable
>
EXECUTABLE_COMPARATOR
=
(
e1
,
e2
)
->
{
private
static
final
Comparator
<
Executable
>
EXECUTABLE_COMPARATOR
=
(
e1
,
e2
)
->
{
int
result
=
Boolean
.
compare
(
Modifier
.
isPublic
(
e2
.
getModifiers
()),
Modifier
.
isPublic
(
e1
.
getModifiers
()));
int
result
=
Boolean
.
compare
(
Modifier
.
isPublic
(
e2
.
getModifiers
()),
Modifier
.
isPublic
(
e1
.
getModifiers
()));
return
result
!=
0
?
result
:
Integer
.
compare
(
e2
.
getParameterCount
(),
e1
.
getParameterCount
());
return
result
!=
0
?
result
:
Integer
.
compare
(
e2
.
getParameterCount
(),
e1
.
getParameterCount
());
};
};
private
static
final
AnnotatedElement
EMPTY_ANNOTATED_ELEMENT
=
new
AnnotatedElement
()
{
@Override
@Nullable
public
<
T
extends
Annotation
>
T
getAnnotation
(
Class
<
T
>
annotationClass
)
{
return
null
;
}
@Override
public
Annotation
[]
getAnnotations
()
{
return
new
Annotation
[
0
];
}
@Override
public
Annotation
[]
getDeclaredAnnotations
()
{
return
new
Annotation
[
0
];
}
};
/**
/**
* Sort the given constructors, preferring public constructors and "greedy" ones with
* Sort the given constructors, preferring public constructors and "greedy" ones with
...
@@ -92,7 +64,7 @@ public abstract class AutowireUtils {
...
@@ -92,7 +64,7 @@ public abstract class AutowireUtils {
* decreasing number of arguments.
* decreasing number of arguments.
* @param constructors the constructor array to sort
* @param constructors the constructor array to sort
*/
*/
static
void
sortConstructors
(
Constructor
<?>[]
constructors
)
{
public
static
void
sortConstructors
(
Constructor
<?>[]
constructors
)
{
Arrays
.
sort
(
constructors
,
EXECUTABLE_COMPARATOR
);
Arrays
.
sort
(
constructors
,
EXECUTABLE_COMPARATOR
);
}
}
...
@@ -103,7 +75,7 @@ public abstract class AutowireUtils {
...
@@ -103,7 +75,7 @@ public abstract class AutowireUtils {
* decreasing number of arguments.
* decreasing number of arguments.
* @param factoryMethods the factory method array to sort
* @param factoryMethods the factory method array to sort
*/
*/
static
void
sortFactoryMethods
(
Method
[]
factoryMethods
)
{
public
static
void
sortFactoryMethods
(
Method
[]
factoryMethods
)
{
Arrays
.
sort
(
factoryMethods
,
EXECUTABLE_COMPARATOR
);
Arrays
.
sort
(
factoryMethods
,
EXECUTABLE_COMPARATOR
);
}
}
...
@@ -113,7 +85,7 @@ public abstract class AutowireUtils {
...
@@ -113,7 +85,7 @@ public abstract class AutowireUtils {
* @param pd the PropertyDescriptor of the bean property
* @param pd the PropertyDescriptor of the bean property
* @return whether the bean property is excluded
* @return whether the bean property is excluded
*/
*/
static
boolean
isExcludedFromDependencyCheck
(
PropertyDescriptor
pd
)
{
public
static
boolean
isExcludedFromDependencyCheck
(
PropertyDescriptor
pd
)
{
Method
wm
=
pd
.
getWriteMethod
();
Method
wm
=
pd
.
getWriteMethod
();
if
(
wm
==
null
)
{
if
(
wm
==
null
)
{
return
false
;
return
false
;
...
@@ -135,7 +107,7 @@ public abstract class AutowireUtils {
...
@@ -135,7 +107,7 @@ public abstract class AutowireUtils {
* @param interfaces the Set of interfaces (Class objects)
* @param interfaces the Set of interfaces (Class objects)
* @return whether the setter method is defined by an interface
* @return whether the setter method is defined by an interface
*/
*/
static
boolean
isSetterDefinedInInterface
(
PropertyDescriptor
pd
,
Set
<
Class
<?>>
interfaces
)
{
public
static
boolean
isSetterDefinedInInterface
(
PropertyDescriptor
pd
,
Set
<
Class
<?>>
interfaces
)
{
Method
setter
=
pd
.
getWriteMethod
();
Method
setter
=
pd
.
getWriteMethod
();
if
(
setter
!=
null
)
{
if
(
setter
!=
null
)
{
Class
<?>
targetClass
=
setter
.
getDeclaringClass
();
Class
<?>
targetClass
=
setter
.
getDeclaringClass
();
...
@@ -156,7 +128,7 @@ public abstract class AutowireUtils {
...
@@ -156,7 +128,7 @@ public abstract class AutowireUtils {
* @param requiredType the type to assign the result to
* @param requiredType the type to assign the result to
* @return the resolved value
* @return the resolved value
*/
*/
static
Object
resolveAutowiringValue
(
Object
autowiringValue
,
Class
<?>
requiredType
)
{
public
static
Object
resolveAutowiringValue
(
Object
autowiringValue
,
Class
<?>
requiredType
)
{
if
(
autowiringValue
instanceof
ObjectFactory
&&
!
requiredType
.
isInstance
(
autowiringValue
))
{
if
(
autowiringValue
instanceof
ObjectFactory
&&
!
requiredType
.
isInstance
(
autowiringValue
))
{
ObjectFactory
<?>
factory
=
(
ObjectFactory
<?>)
autowiringValue
;
ObjectFactory
<?>
factory
=
(
ObjectFactory
<?>)
autowiringValue
;
if
(
autowiringValue
instanceof
Serializable
&&
requiredType
.
isInterface
())
{
if
(
autowiringValue
instanceof
Serializable
&&
requiredType
.
isInterface
())
{
...
@@ -201,7 +173,7 @@ public abstract class AutowireUtils {
...
@@ -201,7 +173,7 @@ public abstract class AutowireUtils {
* @return the resolved target return type or the standard method return type
* @return the resolved target return type or the standard method return type
* @since 3.2.5
* @since 3.2.5
*/
*/
static
Class
<?>
resolveReturnTypeForFactoryMethod
(
public
static
Class
<?>
resolveReturnTypeForFactoryMethod
(
Method
method
,
Object
[]
args
,
@Nullable
ClassLoader
classLoader
)
{
Method
method
,
Object
[]
args
,
@Nullable
ClassLoader
classLoader
)
{
Assert
.
notNull
(
method
,
"Method must not be null"
);
Assert
.
notNull
(
method
,
"Method must not be null"
);
...
@@ -292,111 +264,6 @@ public abstract class AutowireUtils {
...
@@ -292,111 +264,6 @@ public abstract class AutowireUtils {
return
method
.
getReturnType
();
return
method
.
getReturnType
();
}
}
/**
* Determine if the supplied {@link Parameter} can <em>potentially</em> be
* autowired from an {@link AutowireCapableBeanFactory}.
* <p>Returns {@code true} if the supplied parameter is annotated or
* meta-annotated with {@link Autowired @Autowired},
* {@link Qualifier @Qualifier}, or {@link Value @Value}.
* <p>Note that {@link #resolveDependency} may still be able to resolve the
* dependency for the supplied parameter even if this method returns {@code false}.
* @param parameter the parameter whose dependency should be autowired
* (must not be {@code null})
* @param parameterIndex the index of the parameter in the constructor or method
* that declares the parameter
* @since 5.2
* @see #resolveDependency
*/
public
static
boolean
isAutowirable
(
Parameter
parameter
,
int
parameterIndex
)
{
Assert
.
notNull
(
parameter
,
"Parameter must not be null"
);
AnnotatedElement
annotatedParameter
=
getEffectiveAnnotatedParameter
(
parameter
,
parameterIndex
);
return
(
AnnotatedElementUtils
.
hasAnnotation
(
annotatedParameter
,
Autowired
.
class
)
||
AnnotatedElementUtils
.
hasAnnotation
(
annotatedParameter
,
Qualifier
.
class
)
||
AnnotatedElementUtils
.
hasAnnotation
(
annotatedParameter
,
Value
.
class
));
}
/**
* Resolve the dependency for the supplied {@link Parameter} from the
* supplied {@link AutowireCapableBeanFactory}.
* <p>Provides comprehensive autowiring support for individual method parameters
* on par with Spring's dependency injection facilities for autowired fields and
* methods, including support for {@link Autowired @Autowired},
* {@link Qualifier @Qualifier}, and {@link Value @Value} with support for property
* placeholders and SpEL expressions in {@code @Value} declarations.
* <p>The dependency is required unless the parameter is annotated or meta-annotated
* with {@link Autowired @Autowired} with the {@link Autowired#required required}
* flag set to {@code false}.
* <p>If an explicit <em>qualifier</em> is not declared, the name of the parameter
* will be used as the qualifier for resolving ambiguities.
* @param parameter the parameter whose dependency should be resolved (must not be
* {@code null})
* @param parameterIndex the index of the parameter in the constructor or method
* that declares the parameter
* @param containingClass the concrete class that contains the parameter; this may
* differ from the class that declares the parameter in that it may be a subclass
* thereof, potentially substituting type variables (must not be {@code null})
* @param beanFactory the {@code AutowireCapableBeanFactory} from which to resolve
* the dependency (must not be {@code null})
* @return the resolved object, or {@code null} if none found
* @throws BeansException if dependency resolution failed
* @since 5.2
* @see #isAutowirable
* @see Autowired#required
* @see SynthesizingMethodParameter#forExecutable(Executable, int)
* @see AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String)
*/
@Nullable
public
static
Object
resolveDependency
(
Parameter
parameter
,
int
parameterIndex
,
Class
<?>
containingClass
,
AutowireCapableBeanFactory
beanFactory
)
throws
BeansException
{
Assert
.
notNull
(
parameter
,
"Parameter must not be null"
);
Assert
.
notNull
(
containingClass
,
"Containing class must not be null"
);
Assert
.
notNull
(
beanFactory
,
"AutowireCapableBeanFactory must not be null"
);
AnnotatedElement
annotatedParameter
=
getEffectiveAnnotatedParameter
(
parameter
,
parameterIndex
);
Autowired
autowired
=
AnnotatedElementUtils
.
findMergedAnnotation
(
annotatedParameter
,
Autowired
.
class
);
boolean
required
=
(
autowired
==
null
||
autowired
.
required
());
MethodParameter
methodParameter
=
SynthesizingMethodParameter
.
forExecutable
(
parameter
.
getDeclaringExecutable
(),
parameterIndex
);
DependencyDescriptor
descriptor
=
new
DependencyDescriptor
(
methodParameter
,
required
);
descriptor
.
setContainingClass
(
containingClass
);
return
beanFactory
.
resolveDependency
(
descriptor
,
null
);
}
/**
* Due to a bug in {@code javac} on JDK versions prior to JDK 9, looking up
* annotations directly on a {@link Parameter} will fail for inner class
* constructors.
* <h4>Bug in javac in JDK < 9</h4>
* <p>The parameter annotations array in the compiled byte code excludes an entry
* for the implicit <em>enclosing instance</em> parameter for an inner class
* constructor.
* <h4>Workaround</h4>
* <p>This method provides a workaround for this off-by-one error by allowing the
* caller to access annotations on the preceding {@link Parameter} object (i.e.,
* {@code index - 1}). If the supplied {@code index} is zero, this method returns
* an empty {@code AnnotatedElement}.
* <h4>WARNING</h4>
* <p>The {@code AnnotatedElement} returned by this method should never be cast and
* treated as a {@code Parameter} since the metadata (e.g., {@link Parameter#getName()},
* {@link Parameter#getType()}, etc.) will not match those for the declared parameter
* at the given index in an inner class constructor.
* @return the supplied {@code parameter} or the <em>effective</em> {@code Parameter}
* if the aforementioned bug is in effect
*/
private
static
AnnotatedElement
getEffectiveAnnotatedParameter
(
Parameter
parameter
,
int
index
)
{
Executable
executable
=
parameter
.
getDeclaringExecutable
();
if
(
executable
instanceof
Constructor
&&
ClassUtils
.
isInnerClass
(
executable
.
getDeclaringClass
())
&&
executable
.
getParameterAnnotations
().
length
==
executable
.
getParameterCount
()
-
1
)
{
// Bug in javac in JDK <9: annotation array excludes enclosing instance parameter
// for inner classes, so access it with the actual parameter index lowered by 1
return
(
index
==
0
?
EMPTY_ANNOTATED_ELEMENT
:
executable
.
getParameters
()[
index
-
1
]);
}
return
parameter
;
}
/**
/**
* Reflective {@link InvocationHandler} for lazy access to the current target object.
* Reflective {@link InvocationHandler} for lazy access to the current target object.
...
...
spring-beans/src/test/java/org/springframework/beans/factory/annotation/ParameterResolutionTests.java
0 → 100644
浏览文件 @
62e5585c
/*
* Copyright 2002-2019 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.annotation
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Executable
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Parameter
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
org.springframework.beans.factory.config.AutowireCapableBeanFactory
;
import
org.springframework.beans.factory.config.DependencyDescriptor
;
import
org.springframework.util.ClassUtils
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
mockito
.
Mockito
.*;
/**
* Unit tests for {@link ParameterResolutionDelegate}.
*
* @author Sam Brannen
* @author Juergen Hoeller
* @author Loïc Ledoyen
*/
public
class
ParameterResolutionTests
{
@Rule
public
final
ExpectedException
exception
=
ExpectedException
.
none
();
@Test
public
void
isAutowirablePreconditions
()
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"Parameter must not be null"
);
ParameterResolutionDelegate
.
isAutowirable
(
null
,
0
);
}
@Test
public
void
annotatedParametersInMethodAreCandidatesForAutowiring
()
throws
Exception
{
Method
method
=
getClass
().
getDeclaredMethod
(
"autowirableMethod"
,
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
assertAutowirableParameters
(
method
);
}
@Test
public
void
annotatedParametersInTopLevelClassConstructorAreCandidatesForAutowiring
()
throws
Exception
{
Constructor
<?>
constructor
=
AutowirableClass
.
class
.
getConstructor
(
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
assertAutowirableParameters
(
constructor
);
}
@Test
public
void
annotatedParametersInInnerClassConstructorAreCandidatesForAutowiring
()
throws
Exception
{
Class
<?>
innerClass
=
AutowirableClass
.
InnerAutowirableClass
.
class
;
assertTrue
(
ClassUtils
.
isInnerClass
(
innerClass
));
Constructor
<?>
constructor
=
innerClass
.
getConstructor
(
AutowirableClass
.
class
,
String
.
class
,
String
.
class
);
assertAutowirableParameters
(
constructor
);
}
private
void
assertAutowirableParameters
(
Executable
executable
)
{
int
startIndex
=
(
executable
instanceof
Constructor
)
&&
ClassUtils
.
isInnerClass
(
executable
.
getDeclaringClass
())
?
1
:
0
;
Parameter
[]
parameters
=
executable
.
getParameters
();
for
(
int
parameterIndex
=
startIndex
;
parameterIndex
<
parameters
.
length
;
parameterIndex
++)
{
Parameter
parameter
=
parameters
[
parameterIndex
];
assertTrue
(
"Parameter "
+
parameter
+
" must be autowirable"
,
ParameterResolutionDelegate
.
isAutowirable
(
parameter
,
parameterIndex
));
}
}
@Test
public
void
nonAnnotatedParametersInTopLevelClassConstructorAreNotCandidatesForAutowiring
()
throws
Exception
{
Constructor
<?>
notAutowirableConstructor
=
AutowirableClass
.
class
.
getConstructor
(
String
.
class
);
Parameter
[]
parameters
=
notAutowirableConstructor
.
getParameters
();
for
(
int
parameterIndex
=
0
;
parameterIndex
<
parameters
.
length
;
parameterIndex
++)
{
Parameter
parameter
=
parameters
[
parameterIndex
];
assertFalse
(
"Parameter "
+
parameter
+
" must not be autowirable"
,
ParameterResolutionDelegate
.
isAutowirable
(
parameter
,
parameterIndex
));
}
}
@Test
public
void
resolveDependencyPreconditionsForParameter
()
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"Parameter must not be null"
);
ParameterResolutionDelegate
.
resolveDependency
(
null
,
0
,
null
,
mock
(
AutowireCapableBeanFactory
.
class
));
}
@Test
public
void
resolveDependencyPreconditionsForContainingClass
()
throws
Exception
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"Containing class must not be null"
);
ParameterResolutionDelegate
.
resolveDependency
(
getParameter
(),
0
,
null
,
null
);
}
@Test
public
void
resolveDependencyPreconditionsForBeanFactory
()
throws
Exception
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"AutowireCapableBeanFactory must not be null"
);
ParameterResolutionDelegate
.
resolveDependency
(
getParameter
(),
0
,
getClass
(),
null
);
}
private
Parameter
getParameter
()
throws
NoSuchMethodException
{
Method
method
=
getClass
().
getDeclaredMethod
(
"autowirableMethod"
,
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
return
method
.
getParameters
()[
0
];
}
@Test
public
void
resolveDependencyForAnnotatedParametersInTopLevelClassConstructor
()
throws
Exception
{
Constructor
<?>
constructor
=
AutowirableClass
.
class
.
getConstructor
(
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
AutowireCapableBeanFactory
beanFactory
=
mock
(
AutowireCapableBeanFactory
.
class
);
// Configure the mocked BeanFactory to return the DependencyDescriptor for convenience and
// to avoid using an ArgumentCaptor.
when
(
beanFactory
.
resolveDependency
(
any
(),
isNull
())).
thenAnswer
(
invocation
->
invocation
.
getArgument
(
0
));
Parameter
[]
parameters
=
constructor
.
getParameters
();
for
(
int
parameterIndex
=
0
;
parameterIndex
<
parameters
.
length
;
parameterIndex
++)
{
Parameter
parameter
=
parameters
[
parameterIndex
];
DependencyDescriptor
intermediateDependencyDescriptor
=
(
DependencyDescriptor
)
ParameterResolutionDelegate
.
resolveDependency
(
parameter
,
parameterIndex
,
AutowirableClass
.
class
,
beanFactory
);
assertEquals
(
constructor
,
intermediateDependencyDescriptor
.
getAnnotatedElement
());
assertEquals
(
parameter
,
intermediateDependencyDescriptor
.
getMethodParameter
().
getParameter
());
}
}
void
autowirableMethod
(
@Autowired
String
firstParameter
,
@Qualifier
(
"someQualifier"
)
String
secondParameter
,
@Value
(
"${someValue}"
)
String
thirdParameter
,
@Autowired
(
required
=
false
)
String
fourthParameter
)
{
}
public
static
class
AutowirableClass
{
public
AutowirableClass
(
@Autowired
String
firstParameter
,
@Qualifier
(
"someQualifier"
)
String
secondParameter
,
@Value
(
"${someValue}"
)
String
thirdParameter
,
@Autowired
(
required
=
false
)
String
fourthParameter
)
{
}
public
AutowirableClass
(
String
notAutowirableParameter
)
{
}
public
class
InnerAutowirableClass
{
public
InnerAutowirableClass
(
@Autowired
String
firstParameter
,
@Qualifier
(
"someQualifier"
)
String
secondParameter
)
{
}
}
}
}
spring-beans/src/test/java/org/springframework/beans/factory/support/AutowireUtilsTests.java
浏览文件 @
62e5585c
...
@@ -16,28 +16,15 @@
...
@@ -16,28 +16,15 @@
package
org.springframework.beans.factory.support
;
package
org.springframework.beans.factory.support
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Executable
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Parameter
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Map
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.config.AutowireCapableBeanFactory
;
import
org.springframework.beans.factory.config.DependencyDescriptor
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.util.ReflectionUtils
;
import
org.springframework.util.ReflectionUtils
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
mockito
.
ArgumentMatchers
.*;
import
static
org
.
mockito
.
Mockito
.*;
/**
/**
* Unit tests for {@link AutowireUtils}.
* Unit tests for {@link AutowireUtils}.
...
@@ -47,52 +34,49 @@ import static org.mockito.Mockito.*;
...
@@ -47,52 +34,49 @@ import static org.mockito.Mockito.*;
* @author Loïc Ledoyen
* @author Loïc Ledoyen
*/
*/
public
class
AutowireUtilsTests
{
public
class
AutowireUtilsTests
{
@Rule
public
final
ExpectedException
exception
=
ExpectedException
.
none
();
@Test
@Test
public
void
genericMethodReturnTypes
()
{
public
void
genericMethodReturnTypes
()
{
Method
notParameterized
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"notParameterized"
);
Method
notParameterized
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"notParameterized"
);
assertEquals
(
String
.
class
,
assertEquals
(
String
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
notParameterized
,
new
Object
[
]{}
,
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
notParameterized
,
new
Object
[
0
]
,
getClass
().
getClassLoader
()));
Method
notParameterizedWithArguments
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"notParameterizedWithArguments"
,
Integer
.
class
,
Boolean
.
class
);
Method
notParameterizedWithArguments
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"notParameterizedWithArguments"
,
Integer
.
class
,
Boolean
.
class
);
assertEquals
(
String
.
class
,
assertEquals
(
String
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
notParameterizedWithArguments
,
new
Object
[]{
99
,
true
},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
notParameterizedWithArguments
,
new
Object
[]
{
99
,
true
},
getClass
().
getClassLoader
()));
Method
createProxy
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createProxy"
,
Object
.
class
);
Method
createProxy
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createProxy"
,
Object
.
class
);
assertEquals
(
String
.
class
,
assertEquals
(
String
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createProxy
,
new
Object
[]{
"foo"
},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createProxy
,
new
Object
[]
{
"foo"
},
getClass
().
getClassLoader
()));
Method
createNamedProxyWithDifferentTypes
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createNamedProxy"
,
String
.
class
,
Object
.
class
);
Method
createNamedProxyWithDifferentTypes
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createNamedProxy"
,
String
.
class
,
Object
.
class
);
assertEquals
(
Long
.
class
,
assertEquals
(
Long
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createNamedProxyWithDifferentTypes
,
new
Object
[]{
"enigma"
,
99L
},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createNamedProxyWithDifferentTypes
,
new
Object
[]
{
"enigma"
,
99L
},
getClass
().
getClassLoader
()));
Method
createNamedProxyWithDuplicateTypes
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createNamedProxy"
,
String
.
class
,
Object
.
class
);
Method
createNamedProxyWithDuplicateTypes
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createNamedProxy"
,
String
.
class
,
Object
.
class
);
assertEquals
(
String
.
class
,
assertEquals
(
String
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createNamedProxyWithDuplicateTypes
,
new
Object
[]{
"enigma"
,
"foo"
},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createNamedProxyWithDuplicateTypes
,
new
Object
[]
{
"enigma"
,
"foo"
},
getClass
().
getClassLoader
()));
Method
createMock
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createMock"
,
Class
.
class
);
Method
createMock
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createMock"
,
Class
.
class
);
assertEquals
(
Runnable
.
class
,
assertEquals
(
Runnable
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createMock
,
new
Object
[]{
Runnable
.
class
},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createMock
,
new
Object
[]
{
Runnable
.
class
},
getClass
().
getClassLoader
()));
assertEquals
(
Runnable
.
class
,
assertEquals
(
Runnable
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createMock
,
new
Object
[]{
Runnable
.
class
.
getName
()},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createMock
,
new
Object
[]
{
Runnable
.
class
.
getName
()},
getClass
().
getClassLoader
()));
Method
createNamedMock
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createNamedMock"
,
String
.
class
,
Class
.
class
);
Method
createNamedMock
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createNamedMock"
,
String
.
class
,
Class
.
class
);
assertEquals
(
Runnable
.
class
,
assertEquals
(
Runnable
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createNamedMock
,
new
Object
[]{
"foo"
,
Runnable
.
class
},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createNamedMock
,
new
Object
[]
{
"foo"
,
Runnable
.
class
},
getClass
().
getClassLoader
()));
Method
createVMock
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createVMock"
,
Object
.
class
,
Class
.
class
);
Method
createVMock
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"createVMock"
,
Object
.
class
,
Class
.
class
);
assertEquals
(
Runnable
.
class
,
assertEquals
(
Runnable
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createVMock
,
new
Object
[]{
"foo"
,
Runnable
.
class
},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
createVMock
,
new
Object
[]
{
"foo"
,
Runnable
.
class
},
getClass
().
getClassLoader
()));
// Ideally we would expect String.class instead of Object.class, but
// Ideally we would expect String.class instead of Object.class, but
// resolveReturnTypeForFactoryMethod() does not currently support this form of
// resolveReturnTypeForFactoryMethod() does not currently support this form of
// look-up.
// look-up.
Method
extractValueFrom
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"extractValueFrom"
,
MyInterfaceType
.
class
);
Method
extractValueFrom
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"extractValueFrom"
,
MyInterfaceType
.
class
);
assertEquals
(
Object
.
class
,
assertEquals
(
Object
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
extractValueFrom
,
new
Object
[]{
new
MySimpleInterfaceType
()},
getClass
().
getClassLoader
()));
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
extractValueFrom
,
new
Object
[]
{
new
MySimpleInterfaceType
()},
getClass
().
getClassLoader
()));
// Ideally we would expect Boolean.class instead of Object.class, but this
// Ideally we would expect Boolean.class instead of Object.class, but this
// information is not available at run-time due to type erasure.
// information is not available at run-time due to type erasure.
...
@@ -100,100 +84,7 @@ public class AutowireUtilsTests {
...
@@ -100,100 +84,7 @@ public class AutowireUtilsTests {
map
.
put
(
0
,
false
);
map
.
put
(
0
,
false
);
map
.
put
(
1
,
true
);
map
.
put
(
1
,
true
);
Method
extractMagicValue
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"extractMagicValue"
,
Map
.
class
);
Method
extractMagicValue
=
ReflectionUtils
.
findMethod
(
MyTypeWithMethods
.
class
,
"extractMagicValue"
,
Map
.
class
);
assertEquals
(
Object
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
extractMagicValue
,
new
Object
[]{
map
},
getClass
().
getClassLoader
()));
assertEquals
(
Object
.
class
,
AutowireUtils
.
resolveReturnTypeForFactoryMethod
(
extractMagicValue
,
new
Object
[]
{
map
},
getClass
().
getClassLoader
()));
}
@Test
public
void
isAutowirablePreconditions
()
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"Parameter must not be null"
);
AutowireUtils
.
isAutowirable
(
null
,
0
);
}
@Test
public
void
annotatedParametersInMethodAreCandidatesForAutowiring
()
throws
Exception
{
Method
method
=
getClass
().
getDeclaredMethod
(
"autowirableMethod"
,
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
assertAutowirableParameters
(
method
);
}
@Test
public
void
annotatedParametersInTopLevelClassConstructorAreCandidatesForAutowiring
()
throws
Exception
{
Constructor
<?>
constructor
=
AutowirableClass
.
class
.
getConstructor
(
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
assertAutowirableParameters
(
constructor
);
}
@Test
public
void
annotatedParametersInInnerClassConstructorAreCandidatesForAutowiring
()
throws
Exception
{
Class
<?>
innerClass
=
AutowirableClass
.
InnerAutowirableClass
.
class
;
assertTrue
(
ClassUtils
.
isInnerClass
(
innerClass
));
Constructor
<?>
constructor
=
innerClass
.
getConstructor
(
AutowirableClass
.
class
,
String
.
class
,
String
.
class
);
assertAutowirableParameters
(
constructor
);
}
private
void
assertAutowirableParameters
(
Executable
executable
)
{
int
startIndex
=
(
executable
instanceof
Constructor
)
&&
ClassUtils
.
isInnerClass
(
executable
.
getDeclaringClass
())
?
1
:
0
;
Parameter
[]
parameters
=
executable
.
getParameters
();
for
(
int
parameterIndex
=
startIndex
;
parameterIndex
<
parameters
.
length
;
parameterIndex
++)
{
Parameter
parameter
=
parameters
[
parameterIndex
];
assertTrue
(
"Parameter "
+
parameter
+
" must be autowirable"
,
AutowireUtils
.
isAutowirable
(
parameter
,
parameterIndex
));
}
}
@Test
public
void
nonAnnotatedParametersInTopLevelClassConstructorAreNotCandidatesForAutowiring
()
throws
Exception
{
Constructor
<?>
notAutowirableConstructor
=
AutowirableClass
.
class
.
getConstructor
(
String
.
class
);
Parameter
[]
parameters
=
notAutowirableConstructor
.
getParameters
();
for
(
int
parameterIndex
=
0
;
parameterIndex
<
parameters
.
length
;
parameterIndex
++)
{
Parameter
parameter
=
parameters
[
parameterIndex
];
assertFalse
(
"Parameter "
+
parameter
+
" must not be autowirable"
,
AutowireUtils
.
isAutowirable
(
parameter
,
parameterIndex
));
}
}
@Test
public
void
resolveDependencyPreconditionsForParameter
()
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"Parameter must not be null"
);
AutowireUtils
.
resolveDependency
(
null
,
0
,
null
,
mock
(
AutowireCapableBeanFactory
.
class
));
}
@Test
public
void
resolveDependencyPreconditionsForContainingClass
()
throws
Exception
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"Containing class must not be null"
);
AutowireUtils
.
resolveDependency
(
getParameter
(),
0
,
null
,
null
);
}
@Test
public
void
resolveDependencyPreconditionsForBeanFactory
()
throws
Exception
{
exception
.
expect
(
IllegalArgumentException
.
class
);
exception
.
expectMessage
(
"AutowireCapableBeanFactory must not be null"
);
AutowireUtils
.
resolveDependency
(
getParameter
(),
0
,
getClass
(),
null
);
}
private
Parameter
getParameter
()
throws
NoSuchMethodException
{
Method
method
=
getClass
().
getDeclaredMethod
(
"autowirableMethod"
,
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
return
method
.
getParameters
()[
0
];
}
@Test
public
void
resolveDependencyForAnnotatedParametersInTopLevelClassConstructor
()
throws
Exception
{
Constructor
<?>
constructor
=
AutowirableClass
.
class
.
getConstructor
(
String
.
class
,
String
.
class
,
String
.
class
,
String
.
class
);
AutowireCapableBeanFactory
beanFactory
=
mock
(
AutowireCapableBeanFactory
.
class
);
// Configure the mocked BeanFactory to return the DependencyDescriptor for convenience and
// to avoid using an ArgumentCaptor.
when
(
beanFactory
.
resolveDependency
(
any
(),
isNull
())).
thenAnswer
(
invocation
->
invocation
.
getArgument
(
0
));
Parameter
[]
parameters
=
constructor
.
getParameters
();
for
(
int
parameterIndex
=
0
;
parameterIndex
<
parameters
.
length
;
parameterIndex
++)
{
Parameter
parameter
=
parameters
[
parameterIndex
];
DependencyDescriptor
intermediateDependencyDescriptor
=
(
DependencyDescriptor
)
AutowireUtils
.
resolveDependency
(
parameter
,
parameterIndex
,
AutowirableClass
.
class
,
beanFactory
);
assertEquals
(
constructor
,
intermediateDependencyDescriptor
.
getAnnotatedElement
());
assertEquals
(
parameter
,
intermediateDependencyDescriptor
.
getMethodParameter
().
getParameter
());
}
}
}
...
@@ -295,30 +186,4 @@ public class AutowireUtilsTests {
...
@@ -295,30 +186,4 @@ public class AutowireUtilsTests {
}
}
}
}
void
autowirableMethod
(
@Autowired
String
firstParameter
,
@Qualifier
(
"someQualifier"
)
String
secondParameter
,
@Value
(
"${someValue}"
)
String
thirdParameter
,
@Autowired
(
required
=
false
)
String
fourthParameter
)
{
}
public
static
class
AutowirableClass
{
public
AutowirableClass
(
@Autowired
String
firstParameter
,
@Qualifier
(
"someQualifier"
)
String
secondParameter
,
@Value
(
"${someValue}"
)
String
thirdParameter
,
@Autowired
(
required
=
false
)
String
fourthParameter
)
{
}
public
AutowirableClass
(
String
notAutowirableParameter
)
{
}
public
class
InnerAutowirableClass
{
public
InnerAutowirableClass
(
@Autowired
String
firstParameter
,
@Qualifier
(
"someQualifier"
)
String
secondParameter
)
{
}
}
}
}
}
spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java
浏览文件 @
62e5585c
...
@@ -35,7 +35,7 @@ import org.junit.jupiter.api.extension.ParameterResolver;
...
@@ -35,7 +35,7 @@ import org.junit.jupiter.api.extension.ParameterResolver;
import
org.junit.jupiter.api.extension.TestInstancePostProcessor
;
import
org.junit.jupiter.api.extension.TestInstancePostProcessor
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.
support.AutowireUtils
;
import
org.springframework.beans.factory.
annotation.ParameterResolutionDelegate
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.core.annotation.AnnotatedElementUtils
;
import
org.springframework.core.annotation.AnnotatedElementUtils
;
import
org.springframework.lang.Nullable
;
import
org.springframework.lang.Nullable
;
...
@@ -146,31 +146,30 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
...
@@ -146,31 +146,30 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
* <p>Returns {@code true} if the parameter is declared in a {@link Constructor}
* <p>Returns {@code true} if the parameter is declared in a {@link Constructor}
* that is annotated with {@link Autowired @Autowired} or if the parameter is
* that is annotated with {@link Autowired @Autowired} or if the parameter is
* of type {@link ApplicationContext} (or a sub-type thereof) and otherwise delegates
* of type {@link ApplicationContext} (or a sub-type thereof) and otherwise delegates
* to {@link
AutowireUtils
#isAutowirable}.
* to {@link
ParameterResolutionDelegate
#isAutowirable}.
* <p><strong>WARNING</strong>: If the parameter is declared in a {@code Constructor}
* <p><strong>WARNING</strong>: If the parameter is declared in a {@code Constructor}
* that is annotated with {@code @Autowired}, Spring will assume the responsibility
* that is annotated with {@code @Autowired}, Spring will assume the responsibility
* for resolving all parameters in the constructor. Consequently, no other registered
* for resolving all parameters in the constructor. Consequently, no other registered
* {@link ParameterResolver} will be able to resolve parameters.
* {@link ParameterResolver} will be able to resolve parameters.
* @see #resolveParameter
* @see #resolveParameter
* @see
AutowireUtils
#isAutowirable
* @see
ParameterResolutionDelegate
#isAutowirable
*/
*/
@Override
@Override
public
boolean
supportsParameter
(
ParameterContext
parameterContext
,
ExtensionContext
extensionContext
)
{
public
boolean
supportsParameter
(
ParameterContext
parameterContext
,
ExtensionContext
extensionContext
)
{
Parameter
parameter
=
parameterContext
.
getParameter
();
Parameter
parameter
=
parameterContext
.
getParameter
();
int
index
=
parameterContext
.
getIndex
();
int
index
=
parameterContext
.
getIndex
();
Executable
executable
=
parameter
.
getDeclaringExecutable
();
Executable
exec
=
parameter
.
getDeclaringExecutable
();
return
(
executable
instanceof
Constructor
&&
return
((
exec
instanceof
Constructor
&&
AnnotatedElementUtils
.
hasAnnotation
(
exec
,
Autowired
.
class
))
||
AnnotatedElementUtils
.
hasAnnotation
(
executable
,
Autowired
.
class
))
||
ApplicationContext
.
class
.
isAssignableFrom
(
parameter
.
getType
())
||
ApplicationContext
.
class
.
isAssignableFrom
(
parameter
.
getType
())
||
AutowireUtils
.
isAutowirable
(
parameter
,
index
);
ParameterResolutionDelegate
.
isAutowirable
(
parameter
,
index
)
);
}
}
/**
/**
* Resolve a value for the {@link Parameter} in the supplied {@link ParameterContext} by
* Resolve a value for the {@link Parameter} in the supplied {@link ParameterContext} by
* retrieving the corresponding dependency from the test's {@link ApplicationContext}.
* retrieving the corresponding dependency from the test's {@link ApplicationContext}.
* <p>Delegates to {@link
AutowireUtils
#resolveDependency}.
* <p>Delegates to {@link
ParameterResolutionDelegate
#resolveDependency}.
* @see #supportsParameter
* @see #supportsParameter
* @see
AutowireUtils
#resolveDependency
* @see
ParameterResolutionDelegate
#resolveDependency
*/
*/
@Override
@Override
@Nullable
@Nullable
...
@@ -179,8 +178,8 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
...
@@ -179,8 +178,8 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes
int
index
=
parameterContext
.
getIndex
();
int
index
=
parameterContext
.
getIndex
();
Class
<?>
testClass
=
extensionContext
.
getRequiredTestClass
();
Class
<?>
testClass
=
extensionContext
.
getRequiredTestClass
();
ApplicationContext
applicationContext
=
getApplicationContext
(
extensionContext
);
ApplicationContext
applicationContext
=
getApplicationContext
(
extensionContext
);
return
AutowireUtils
.
resolveDependency
(
parameter
,
index
,
testClass
,
return
ParameterResolutionDelegate
.
resolveDependency
(
parameter
,
index
,
testClass
,
applicationContext
.
getAutowireCapableBeanFactory
());
applicationContext
.
getAutowireCapableBeanFactory
());
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录