Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
9683da52
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,体验更适合开发者的 AI 搜索 >>
提交
9683da52
编写于
11月 05, 2015
作者:
J
Juergen Hoeller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Avoid annotation synthesizing for getAnnotationAttributes retrieval
Issue: SPR-13621
上级
971f0469
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
152 addition
and
165 deletion
+152
-165
spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
...pringframework/core/annotation/AnnotatedElementUtils.java
+3
-3
spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
.../org/springframework/core/annotation/AnnotationUtils.java
+126
-136
spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
...framework/core/annotation/AnnotatedElementUtilsTests.java
+23
-26
未找到文件。
spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
浏览文件 @
9683da52
...
...
@@ -977,7 +977,7 @@ public class AnnotatedElementUtils {
* annotation attributes from lower levels in the annotation hierarchy
* during the {@link #postProcess} phase.
* @since 4.2
* @see AnnotationUtils#
getAnnotationAttributes(AnnotatedElement, Annotation, boolea
n, boolean, boolean)
* @see AnnotationUtils#
retrieveAnnotationAttributes(AnnotatedElement, Annotatio
n, boolean, boolean)
* @see AnnotationUtils#postProcessAnnotationAttributes
*/
private
static
class
MergedAnnotationAttributesProcessor
implements
Processor
<
AnnotationAttributes
>
{
...
...
@@ -1003,8 +1003,8 @@ public class AnnotatedElementUtils {
public
AnnotationAttributes
process
(
AnnotatedElement
annotatedElement
,
Annotation
annotation
,
int
metaDepth
)
{
boolean
found
=
(
this
.
annotationType
!=
null
?
annotation
.
annotationType
()
==
this
.
annotationType
:
annotation
.
annotationType
().
getName
().
equals
(
this
.
annotationName
));
return
(
found
?
AnnotationUtils
.
get
AnnotationAttributes
(
annotatedElement
,
annotation
,
this
.
classValuesAsString
,
this
.
nestedAnnotationsAsMap
,
true
)
:
null
);
return
(
found
?
AnnotationUtils
.
retrieve
AnnotationAttributes
(
annotatedElement
,
annotation
,
this
.
classValuesAsString
,
this
.
nestedAnnotationsAsMap
)
:
null
);
}
@Override
...
...
spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
浏览文件 @
9683da52
...
...
@@ -25,8 +25,8 @@ import java.lang.reflect.Method;
import
java.lang.reflect.Proxy
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.LinkedHashMap
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Map
;
...
...
@@ -112,12 +112,6 @@ public abstract class AnnotationUtils {
public
static
final
String
VALUE
=
"value"
;
/**
* An object that can be stored in {@link AnnotationAttributes} as a
* placeholder for an attribute's declared default value.
*/
private
static
final
Object
DEFAULT_VALUE_PLACEHOLDER
=
new
String
(
"<SPRING DEFAULT VALUE PLACEHOLDER>"
);
private
static
final
Map
<
AnnotationCacheKey
,
Annotation
>
findAnnotationCache
=
new
ConcurrentReferenceHashMap
<
AnnotationCacheKey
,
Annotation
>(
256
);
...
...
@@ -1002,7 +996,10 @@ public abstract class AnnotationUtils {
public
static
AnnotationAttributes
getAnnotationAttributes
(
AnnotatedElement
annotatedElement
,
Annotation
annotation
,
boolean
classValuesAsString
,
boolean
nestedAnnotationsAsMap
)
{
return
getAnnotationAttributes
(
annotatedElement
,
annotation
,
classValuesAsString
,
nestedAnnotationsAsMap
,
false
);
AnnotationAttributes
attributes
=
retrieveAnnotationAttributes
(
annotatedElement
,
annotation
,
classValuesAsString
,
nestedAnnotationsAsMap
);
postProcessAnnotationAttributes
(
annotatedElement
,
attributes
,
classValuesAsString
,
nestedAnnotationsAsMap
);
return
attributes
;
}
/**
...
...
@@ -1010,16 +1007,9 @@ public abstract class AnnotationUtils {
* <p>This method provides fully recursive annotation reading capabilities on par with
* the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
* <p><strong>NOTE</strong>: This variant of {@code getAnnotationAttributes()} is
* only intended for use within the framework. Specifically, the {@code mergeMode} flag
* can be set to {@code true} in order to support processing of attribute aliases while
* merging attributes within an annotation hierarchy. When running in <em>merge mode</em>,
* the following special rules apply:
* only intended for use within the framework. The following special rules apply:
* <ol>
* <li>The supplied annotation will <em>not</em> be
* {@linkplain #synthesizeAnnotation synthesized} before retrieving its attributes;
* however, nested annotations and arrays of nested annotations <em>will</em> be
* synthesized.</li>
* <li>Default values will be replaced with {@link #DEFAULT_VALUE_PLACEHOLDER}.</li>
* <li>Default values will be replaced with default value placeholders.</li>
* <li>The resulting, merged annotation attributes should eventually be
* {@linkplain #postProcessAnnotationAttributes post-processed} in order to
* ensure that placeholders have been replaced by actual default values and
...
...
@@ -1035,33 +1025,26 @@ public abstract class AnnotationUtils {
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
* {@code Annotation} instances
* @param mergeMode whether the annotation attributes should be created
* using <em>merge mode</em>
* @return the annotation attributes (a specialized Map) with attribute names as keys
* and corresponding attribute values as values (never {@code null})
* @since 4.2
* @see #postProcessAnnotationAttributes
*/
static
AnnotationAttributes
getAnnotationAttributes
(
AnnotatedElement
annotatedElement
,
Annotation
annotation
,
boolean
classValuesAsString
,
boolean
nestedAnnotationsAsMap
,
boolean
mergeMode
)
{
if
(!
mergeMode
)
{
annotation
=
synthesizeAnnotation
(
annotation
,
annotatedElement
);
}
static
AnnotationAttributes
retrieveAnnotationAttributes
(
AnnotatedElement
annotatedElement
,
Annotation
annotation
,
boolean
classValuesAsString
,
boolean
nestedAnnotationsAsMap
)
{
Class
<?
extends
Annotation
>
annotationType
=
annotation
.
annotationType
();
AnnotationAttributes
attrs
=
new
AnnotationAttributes
(
annotationType
);
AnnotationAttributes
attributes
=
new
AnnotationAttributes
(
annotationType
);
for
(
Method
method
:
getAttributeMethods
(
annotationType
))
{
try
{
Object
v
alue
=
method
.
invoke
(
annotation
);
Object
attributeV
alue
=
method
.
invoke
(
annotation
);
Object
defaultValue
=
method
.
getDefaultValue
();
if
(
mergeMode
&&
defaultValue
!=
null
)
{
if
(
ObjectUtils
.
nullSafeEquals
(
value
,
defaultValue
))
{
value
=
DEFAULT_VALUE_PLACEHOLDER
;
}
if
(
defaultValue
!=
null
&&
ObjectUtils
.
nullSafeEquals
(
attributeValue
,
defaultValue
))
{
attributeValue
=
new
DefaultValueHolder
(
defaultValue
);
}
attrs
.
put
(
method
.
getName
(),
adaptValue
(
annotatedElement
,
v
alue
,
classValuesAsString
,
nestedAnnotationsAsMap
));
attr
ibute
s
.
put
(
method
.
getName
(),
adaptValue
(
annotatedElement
,
attributeV
alue
,
classValuesAsString
,
nestedAnnotationsAsMap
));
}
catch
(
Exception
ex
)
{
if
(
ex
instanceof
InvocationTargetException
)
{
...
...
@@ -1071,7 +1054,8 @@ public abstract class AnnotationUtils {
throw
new
IllegalStateException
(
"Could not obtain annotation attribute value for "
+
method
,
ex
);
}
}
return
attrs
;
return
attributes
;
}
/**
...
...
@@ -1109,7 +1093,6 @@ public abstract class AnnotationUtils {
if
(
value
instanceof
Annotation
)
{
Annotation
annotation
=
(
Annotation
)
value
;
if
(
nestedAnnotationsAsMap
)
{
return
getAnnotationAttributes
(
annotatedElement
,
annotation
,
classValuesAsString
,
true
);
}
...
...
@@ -1120,12 +1103,11 @@ public abstract class AnnotationUtils {
if
(
value
instanceof
Annotation
[])
{
Annotation
[]
annotations
=
(
Annotation
[])
value
;
if
(
nestedAnnotationsAsMap
)
{
AnnotationAttributes
[]
mappedAnnotations
=
new
AnnotationAttributes
[
annotations
.
length
];
for
(
int
i
=
0
;
i
<
annotations
.
length
;
i
++)
{
mappedAnnotations
[
i
]
=
getAnnotationAttributes
(
annotatedElement
,
annotations
[
i
],
classValuesAsString
,
true
);
mappedAnnotations
[
i
]
=
getAnnotationAttributes
(
annotatedElement
,
annotations
[
i
],
classValuesAsString
,
true
);
}
return
mappedAnnotations
;
}
...
...
@@ -1138,6 +1120,101 @@ public abstract class AnnotationUtils {
return
value
;
}
/**
* Post-process the supplied {@link AnnotationAttributes}.
* <p>Specifically, this method enforces <em>attribute alias</em> semantics
* for annotation attributes that are annotated with {@link AliasFor @AliasFor}
* and replaces default value placeholders with their original default values.
* @param annotatedElement the element that is annotated with an annotation or
* annotation hierarchy from which the supplied attributes were created;
* may be {@code null} if unknown
* @param attributes the annotation attributes to post-process
* @param classValuesAsString whether to convert Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata})
* or to preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested annotations into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
* {@code Annotation} instances
* @since 4.2
* @see #retrieveAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
* @see #getDefaultValue(Class, String)
*/
static
void
postProcessAnnotationAttributes
(
AnnotatedElement
annotatedElement
,
AnnotationAttributes
attributes
,
boolean
classValuesAsString
,
boolean
nestedAnnotationsAsMap
)
{
// Abort?
if
(
attributes
==
null
)
{
return
;
}
Class
<?
extends
Annotation
>
annotationType
=
attributes
.
annotationType
();
// Track which attribute values have already been replaced so that we can short
// circuit the search algorithms.
Set
<
String
>
valuesAlreadyReplaced
=
new
HashSet
<
String
>();
// Validate @AliasFor configuration
Map
<
String
,
List
<
String
>>
aliasMap
=
getAttributeAliasMap
(
annotationType
);
for
(
String
attributeName
:
aliasMap
.
keySet
())
{
if
(
valuesAlreadyReplaced
.
contains
(
attributeName
))
{
continue
;
}
Object
value
=
attributes
.
get
(
attributeName
);
boolean
valuePresent
=
(
value
!=
null
&&
!(
value
instanceof
DefaultValueHolder
));
for
(
String
aliasedAttributeName
:
aliasMap
.
get
(
attributeName
))
{
if
(
valuesAlreadyReplaced
.
contains
(
aliasedAttributeName
))
{
continue
;
}
Object
aliasedValue
=
attributes
.
get
(
aliasedAttributeName
);
boolean
aliasPresent
=
(
aliasedValue
!=
null
&&
!(
aliasedValue
instanceof
DefaultValueHolder
));
// Something to validate or replace with an alias?
if
(
valuePresent
||
aliasPresent
)
{
if
(
valuePresent
&&
aliasPresent
)
{
// Since annotation attributes can be arrays, we must use ObjectUtils.nullSafeEquals().
if
(!
ObjectUtils
.
nullSafeEquals
(
value
,
aliasedValue
))
{
String
elementAsString
=
(
annotatedElement
!=
null
?
annotatedElement
.
toString
()
:
"unknown element"
);
throw
new
AnnotationConfigurationException
(
String
.
format
(
"In AnnotationAttributes for annotation [%s] declared on %s, "
+
"attribute '%s' and its alias '%s' are declared with values of [%s] and [%s], "
+
"but only one is permitted."
,
annotationType
.
getName
(),
elementAsString
,
attributeName
,
aliasedAttributeName
,
ObjectUtils
.
nullSafeToString
(
value
),
ObjectUtils
.
nullSafeToString
(
aliasedValue
)));
}
}
else
if
(
aliasPresent
)
{
// Replace value with aliasedValue
attributes
.
put
(
attributeName
,
adaptValue
(
annotatedElement
,
aliasedValue
,
classValuesAsString
,
nestedAnnotationsAsMap
));
valuesAlreadyReplaced
.
add
(
attributeName
);
}
else
{
// Replace aliasedValue with value
attributes
.
put
(
aliasedAttributeName
,
adaptValue
(
annotatedElement
,
value
,
classValuesAsString
,
nestedAnnotationsAsMap
));
valuesAlreadyReplaced
.
add
(
aliasedAttributeName
);
}
}
}
}
// Replace any remaining placeholders with actual default values
for
(
String
attributeName
:
attributes
.
keySet
())
{
if
(
valuesAlreadyReplaced
.
contains
(
attributeName
))
{
continue
;
}
Object
value
=
attributes
.
get
(
attributeName
);
if
(
value
instanceof
DefaultValueHolder
)
{
value
=
((
DefaultValueHolder
)
value
).
defaultValue
;
attributes
.
put
(
attributeName
,
adaptValue
(
annotatedElement
,
value
,
classValuesAsString
,
nestedAnnotationsAsMap
));
}
}
}
/**
* Retrieve the <em>value</em> of the {@code value} attribute of a
* single-element Annotation, given an annotation instance.
...
...
@@ -1436,7 +1513,7 @@ public abstract class AnnotationUtils {
return
map
;
}
map
=
new
HashMap
<
String
,
List
<
String
>>();
map
=
new
Linked
HashMap
<
String
,
List
<
String
>>();
for
(
Method
attribute
:
getAttributeMethods
(
annotationType
))
{
List
<
String
>
aliasNames
=
getAttributeAliasNames
(
attribute
);
if
(!
aliasNames
.
isEmpty
())
{
...
...
@@ -1609,103 +1686,6 @@ public abstract class AnnotationUtils {
return
(
method
!=
null
&&
method
.
getName
().
equals
(
"annotationType"
)
&&
method
.
getParameterTypes
().
length
==
0
);
}
/**
* Post-process the supplied {@link AnnotationAttributes}.
* <p>Specifically, this method enforces <em>attribute alias</em> semantics
* for annotation attributes that are annotated with {@link AliasFor @AliasFor}
* and replaces {@linkplain #DEFAULT_VALUE_PLACEHOLDER placeholders} with their
* original default values.
* @param element the element that is annotated with an annotation or
* annotation hierarchy from which the supplied attributes were created;
* may be {@code null} if unknown
* @param attributes the annotation attributes to post-process
* @param classValuesAsString whether to convert Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata})
* or to preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested annotations into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata}) or to preserve them as
* {@code Annotation} instances
* @since 4.2
* @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean, boolean)
* @see #DEFAULT_VALUE_PLACEHOLDER
* @see #getDefaultValue(Class, String)
*/
static
void
postProcessAnnotationAttributes
(
AnnotatedElement
element
,
AnnotationAttributes
attributes
,
boolean
classValuesAsString
,
boolean
nestedAnnotationsAsMap
)
{
// Abort?
if
(
attributes
==
null
)
{
return
;
}
Class
<?
extends
Annotation
>
annotationType
=
attributes
.
annotationType
();
// Track which attribute values have already been replaced so that we can short
// circuit the search algorithms.
Set
<
String
>
valuesAlreadyReplaced
=
new
HashSet
<
String
>();
// Validate @AliasFor configuration
Map
<
String
,
List
<
String
>>
aliasMap
=
getAttributeAliasMap
(
annotationType
);
for
(
String
attributeName
:
aliasMap
.
keySet
())
{
if
(
valuesAlreadyReplaced
.
contains
(
attributeName
))
{
continue
;
}
Object
value
=
attributes
.
get
(
attributeName
);
boolean
valuePresent
=
(
value
!=
null
&&
value
!=
DEFAULT_VALUE_PLACEHOLDER
);
for
(
String
aliasedAttributeName
:
aliasMap
.
get
(
attributeName
))
{
if
(
valuesAlreadyReplaced
.
contains
(
aliasedAttributeName
))
{
continue
;
}
Object
aliasedValue
=
attributes
.
get
(
aliasedAttributeName
);
boolean
aliasPresent
=
(
aliasedValue
!=
null
&&
aliasedValue
!=
DEFAULT_VALUE_PLACEHOLDER
);
// Something to validate or replace with an alias?
if
(
valuePresent
||
aliasPresent
)
{
if
(
valuePresent
&&
aliasPresent
)
{
// Since annotation attributes can be arrays, we must use ObjectUtils.nullSafeEquals().
if
(!
ObjectUtils
.
nullSafeEquals
(
value
,
aliasedValue
))
{
String
elementAsString
=
(
element
!=
null
?
element
.
toString
()
:
"unknown element"
);
String
msg
=
String
.
format
(
"In AnnotationAttributes for annotation [%s] declared on [%s], "
+
"attribute [%s] and its alias [%s] are declared with values of [%s] and [%s], "
+
"but only one declaration is permitted."
,
annotationType
.
getName
(),
elementAsString
,
attributeName
,
aliasedAttributeName
,
ObjectUtils
.
nullSafeToString
(
value
),
ObjectUtils
.
nullSafeToString
(
aliasedValue
));
throw
new
AnnotationConfigurationException
(
msg
);
}
}
else
if
(
aliasPresent
)
{
// Replace value with aliasedValue
attributes
.
put
(
attributeName
,
adaptValue
(
element
,
aliasedValue
,
classValuesAsString
,
nestedAnnotationsAsMap
));
valuesAlreadyReplaced
.
add
(
attributeName
);
}
else
{
// Replace aliasedValue with value
attributes
.
put
(
aliasedAttributeName
,
adaptValue
(
element
,
value
,
classValuesAsString
,
nestedAnnotationsAsMap
));
valuesAlreadyReplaced
.
add
(
aliasedAttributeName
);
}
}
}
}
// Replace any remaining placeholders with actual default values
for
(
String
attributeName
:
attributes
.
keySet
())
{
if
(
valuesAlreadyReplaced
.
contains
(
attributeName
))
{
continue
;
}
Object
value
=
attributes
.
get
(
attributeName
);
if
(
value
==
DEFAULT_VALUE_PLACEHOLDER
)
{
attributes
.
put
(
attributeName
,
adaptValue
(
element
,
getDefaultValue
(
annotationType
,
attributeName
),
classValuesAsString
,
nestedAnnotationsAsMap
));
}
}
}
/**
* <p>If the supplied throwable is an {@link AnnotationConfigurationException},
* it will be cast to an {@code AnnotationConfigurationException} and thrown,
...
...
@@ -2163,4 +2143,14 @@ public abstract class AnnotationUtils {
}
}
private
static
class
DefaultValueHolder
{
final
Object
defaultValue
;
public
DefaultValueHolder
(
Object
defaultValue
)
{
this
.
defaultValue
=
defaultValue
;
}
}
}
spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
浏览文件 @
9683da52
...
...
@@ -94,8 +94,7 @@ public class AnnotatedElementUtilsTests {
public
void
hasMetaAnnotationTypesOnClassWithMetaDepth2
()
{
assertTrue
(
hasMetaAnnotationTypes
(
ComposedTransactionalComponentClass
.
class
,
TX_NAME
));
assertTrue
(
hasMetaAnnotationTypes
(
ComposedTransactionalComponentClass
.
class
,
Component
.
class
.
getName
()));
assertFalse
(
hasMetaAnnotationTypes
(
ComposedTransactionalComponentClass
.
class
,
ComposedTransactionalComponent
.
class
.
getName
()));
assertFalse
(
hasMetaAnnotationTypes
(
ComposedTransactionalComponentClass
.
class
,
ComposedTransactionalComponent
.
class
.
getName
()));
}
@Test
...
...
@@ -111,7 +110,7 @@ public class AnnotatedElementUtilsTests {
@Test
public
void
isAnnotatedOnSubclassWithMetaDepth0
()
{
assertFalse
(
"isAnnotated() does not search the class hierarchy."
,
isAnnotated
(
SubTransactionalComponentClass
.
class
,
TransactionalComponent
.
class
.
getName
()));
isAnnotated
(
SubTransactionalComponentClass
.
class
,
TransactionalComponent
.
class
.
getName
()));
}
@Test
...
...
@@ -124,8 +123,7 @@ public class AnnotatedElementUtilsTests {
public
void
isAnnotatedOnClassWithMetaDepth2
()
{
assertTrue
(
isAnnotated
(
ComposedTransactionalComponentClass
.
class
,
TX_NAME
));
assertTrue
(
isAnnotated
(
ComposedTransactionalComponentClass
.
class
,
Component
.
class
.
getName
()));
assertTrue
(
isAnnotated
(
ComposedTransactionalComponentClass
.
class
,
ComposedTransactionalComponent
.
class
.
getName
()));
assertTrue
(
isAnnotated
(
ComposedTransactionalComponentClass
.
class
,
ComposedTransactionalComponent
.
class
.
getName
()));
}
@Test
...
...
@@ -167,7 +165,6 @@ public class AnnotatedElementUtilsTests {
* type within the class hierarchy. Such undesirable behavior would cause the
* logic in {@link org.springframework.context.annotation.ProfileCondition}
* to fail.
*
* @see org.springframework.core.env.EnvironmentSystemIntegrationTests#mostSpecificDerivedClassDrivesEnvironment_withDevEnvAndDerivedDevConfigClass
*/
@Test
...
...
@@ -179,7 +176,6 @@ public class AnnotatedElementUtilsTests {
/**
* Note: this functionality is required by {@link org.springframework.context.annotation.ProfileCondition}.
*
* @see org.springframework.core.env.EnvironmentSystemIntegrationTests
*/
@Test
...
...
@@ -187,7 +183,7 @@ public class AnnotatedElementUtilsTests {
MultiValueMap
<
String
,
Object
>
attributes
=
getAllAnnotationAttributes
(
TxFromMultipleComposedAnnotations
.
class
,
TX_NAME
);
assertNotNull
(
"Annotation attributes map for @Transactional on TxFromMultipleComposedAnnotations"
,
attributes
);
assertEquals
(
"value for TxFromMultipleComposedAnnotations."
,
asList
(
"TxInheritedComposed"
,
"TxComposed"
),
attributes
.
get
(
"value"
));
attributes
.
get
(
"value"
));
}
@Test
...
...
@@ -419,12 +415,12 @@ public class AnnotatedElementUtilsTests {
public
void
getMergedAnnotationAttributesWithInvalidConventionBasedComposedAnnotation
()
{
Class
<?>
element
=
InvalidConventionBasedComposedContextConfigClass
.
class
;
exception
.
expect
(
AnnotationConfigurationException
.
class
);
exception
.
expectMessage
(
either
(
containsString
(
"attribute
[value] and its alias [locations]
"
)).
or
(
containsString
(
"attribute [locations] and its alias [value]
"
)));
exception
.
expectMessage
(
either
(
containsString
(
"attribute
'value' and its alias 'locations'
"
)).
or
(
containsString
(
"attribute 'locations' and its alias 'value'
"
)));
exception
.
expectMessage
(
either
(
containsString
(
"values of [{duplicateDeclaration}] and [{requiredLocationsDeclaration}]"
)).
or
(
containsString
(
"values of [{requiredLocationsDeclaration}] and [{duplicateDeclaration}]"
)));
exception
.
expectMessage
(
containsString
(
"but only one
declaration
is permitted"
));
containsString
(
"values of [{duplicateDeclaration}] and [{requiredLocationsDeclaration}]"
)).
or
(
containsString
(
"values of [{requiredLocationsDeclaration}] and [{duplicateDeclaration}]"
)));
exception
.
expectMessage
(
containsString
(
"but only one is permitted"
));
getMergedAnnotationAttributes
(
element
,
ContextConfig
.
class
);
}
...
...
@@ -432,11 +428,11 @@ public class AnnotatedElementUtilsTests {
public
void
getMergedAnnotationAttributesWithInvalidAliasedComposedAnnotation
()
{
Class
<?>
element
=
InvalidAliasedComposedContextConfigClass
.
class
;
exception
.
expect
(
AnnotationConfigurationException
.
class
);
exception
.
expectMessage
(
either
(
containsString
(
"attribute
[value] and its alias [locations]
"
)).
or
(
containsString
(
"attribute [locations] and its alias [value]
"
)));
exception
.
expectMessage
(
either
(
containsString
(
"attribute
'value' and its alias 'locations'
"
)).
or
(
containsString
(
"attribute 'locations' and its alias 'value'
"
)));
exception
.
expectMessage
(
either
(
containsString
(
"values of [{duplicateDeclaration}] and [{test.xml}]"
)).
or
(
containsString
(
"values of [{test.xml}] and [{duplicateDeclaration}]"
)));
exception
.
expectMessage
(
containsString
(
"but only one
declaration
is permitted"
));
containsString
(
"values of [{test.xml}] and [{duplicateDeclaration}]"
)));
exception
.
expectMessage
(
containsString
(
"but only one is permitted"
));
getMergedAnnotationAttributes
(
element
,
ContextConfig
.
class
);
}
...
...
@@ -493,11 +489,9 @@ public class AnnotatedElementUtilsTests {
/**
* <p>{@code AbstractClassWithInheritedAnnotation} declares {@code handleParameterized(T)}; whereas,
* {@code ConcreteClassWithInheritedAnnotation} declares {@code handleParameterized(String)}.
*
* <p>As of Spring 4.2 RC1, {@code AnnotatedElementUtils.processWithFindSemantics()} does not resolve an
* <p>As of Spring 4.2, {@code AnnotatedElementUtils.processWithFindSemantics()} does not resolve an
* <em>equivalent</em> method in {@code AbstractClassWithInheritedAnnotation} for the <em>bridged</em>
* {@code handleParameterized(String)} method.
*
* @since 4.2
*/
@Test
...
...
@@ -517,6 +511,7 @@ public class AnnotatedElementUtilsTests {
Method
[]
methods
=
StringGenericParameter
.
class
.
getMethods
();
Method
bridgeMethod
=
null
;
Method
bridgedMethod
=
null
;
for
(
Method
method
:
methods
)
{
if
(
"getFor"
.
equals
(
method
.
getName
())
&&
!
method
.
getParameterTypes
()[
0
].
equals
(
Integer
.
class
))
{
if
(
method
.
getReturnType
().
equals
(
Object
.
class
))
{
...
...
@@ -546,13 +541,13 @@ public class AnnotatedElementUtilsTests {
String
qualifier
=
"aliasForQualifier"
;
// 1) Find and merge AnnotationAttributes from the annotation hierarchy
AnnotationAttributes
attributes
=
findMergedAnnotationAttributes
(
AliasedTransactionalComponentClass
.
class
,
AliasedTransactional
.
class
);
AnnotationAttributes
attributes
=
findMergedAnnotationAttributes
(
AliasedTransactionalComponentClass
.
class
,
AliasedTransactional
.
class
);
assertNotNull
(
"@AliasedTransactional on AliasedTransactionalComponentClass."
,
attributes
);
// 2) Synthesize the AnnotationAttributes back into the target annotation
AliasedTransactional
annotation
=
AnnotationUtils
.
synthesizeAnnotation
(
attributes
,
AliasedTransactional
.
class
,
AliasedTransactionalComponentClass
.
class
);
AliasedTransactional
.
class
,
AliasedTransactionalComponentClass
.
class
);
assertNotNull
(
annotation
);
// 3) Verify that the AnnotationAttributes and synthesized annotation are equivalent
...
...
@@ -573,8 +568,8 @@ public class AnnotatedElementUtilsTests {
@Test
public
void
findMergedAnnotationForMultipleMetaAnnotationsWithClashingAttributeNames
()
{
final
String
[]
xmlLocations
=
asArray
(
"test.xml"
);
final
String
[]
propFiles
=
asArray
(
"test.properties"
);
String
[]
xmlLocations
=
asArray
(
"test.xml"
);
String
[]
propFiles
=
asArray
(
"test.properties"
);
Class
<?>
element
=
AliasedComposedContextConfigAndTestPropSourceClass
.
class
;
...
...
@@ -600,6 +595,7 @@ public class AnnotatedElementUtilsTests {
String
[]
expected
=
asArray
(
"com.example.app.test"
);
Class
<?>
element
=
TestComponentScanClass
.
class
;
AnnotationAttributes
attributes
=
findMergedAnnotationAttributes
(
element
,
ComponentScan
.
class
);
assertNotNull
(
"Should find @ComponentScan on "
+
element
,
attributes
);
assertArrayEquals
(
"basePackages for "
+
element
,
expected
,
attributes
.
getStringArray
(
"basePackages"
));
...
...
@@ -628,9 +624,10 @@ public class AnnotatedElementUtilsTests {
@Test
public
void
findMergedAnnotationWithLocalAliasesThatConflictWithAttributesInMetaAnnotationByConvention
()
{
final
String
[]
EMPTY
=
new
String
[
]
{}
;
final
String
[]
EMPTY
=
new
String
[
0
]
;
Class
<?>
element
=
SpringAppConfigClass
.
class
;
ContextConfig
contextConfig
=
findMergedAnnotation
(
element
,
ContextConfig
.
class
);
assertNotNull
(
"Should find @ContextConfig on "
+
element
,
contextConfig
);
assertArrayEquals
(
"locations for "
+
element
,
EMPTY
,
contextConfig
.
locations
());
// 'value' in @SpringAppConfig should not override 'value' in @ContextConfig
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录