Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
2f733bed
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,发现更多精彩内容 >>
提交
2f733bed
编写于
5月 11, 2011
作者:
A
Andy Clement
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
SFW-8224: distance can be used when computing method matches in ReflectiveMethodResolver
上级
5d8de5c4
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
165 addition
and
1 deletion
+165
-1
org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java
...ngframework/expression/spel/support/ReflectionHelper.java
+43
-0
org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java
...ork/expression/spel/support/ReflectiveMethodResolver.java
+32
-1
org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java
...org/springframework/expression/spel/SpringEL300Tests.java
+90
-0
未找到文件。
org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java
浏览文件 @
2f733bed
...
@@ -102,6 +102,49 @@ public class ReflectionHelper {
...
@@ -102,6 +102,49 @@ public class ReflectionHelper {
}
}
}
}
}
}
/**
* Based on {@link MethodInvoker.getTypeDifferenceWeight} but operates on TypeDescriptors.
*/
public
static
int
getTypeDifferenceWeight
(
List
<
TypeDescriptor
>
paramTypes
,
List
<
TypeDescriptor
>
argTypes
)
{
int
result
=
0
;
for
(
int
i
=
0
,
max
=
paramTypes
.
size
();
i
<
max
;
i
++)
{
TypeDescriptor
argType
=
argTypes
.
get
(
i
);
TypeDescriptor
paramType
=
paramTypes
.
get
(
i
);
if
(
argType
==
TypeDescriptor
.
NULL
)
{
if
(
paramType
.
isPrimitive
())
{
return
Integer
.
MAX_VALUE
;
}
}
if
(!
ClassUtils
.
isAssignable
(
paramType
.
getClass
(),
argType
.
getClass
()))
{
return
Integer
.
MAX_VALUE
;
}
if
(
argType
!=
TypeDescriptor
.
NULL
)
{
Class
paramTypeClazz
=
paramType
.
getType
();
if
(
paramTypeClazz
.
isPrimitive
())
{
paramTypeClazz
=
Object
.
class
;
}
Class
superClass
=
argType
.
getClass
().
getSuperclass
();
while
(
superClass
!=
null
)
{
if
(
paramType
.
equals
(
superClass
))
{
result
=
result
+
2
;
superClass
=
null
;
}
else
if
(
ClassUtils
.
isAssignable
(
paramTypeClazz
,
superClass
))
{
result
=
result
+
2
;
superClass
=
superClass
.
getSuperclass
();
}
else
{
superClass
=
null
;
}
}
if
(
paramTypeClazz
.
isInterface
())
{
result
=
result
+
1
;
}
}
}
return
result
;
}
/**
/**
* Compare argument arrays and return information about whether they match. A supplied type converter and
* Compare argument arrays and return information about whether they match. A supplied type converter and
...
...
org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java
浏览文件 @
2f733bed
...
@@ -49,8 +49,29 @@ public class ReflectiveMethodResolver implements MethodResolver {
...
@@ -49,8 +49,29 @@ public class ReflectiveMethodResolver implements MethodResolver {
private
static
Method
[]
NO_METHODS
=
new
Method
[
0
];
private
static
Method
[]
NO_METHODS
=
new
Method
[
0
];
private
Map
<
Class
<?>,
MethodFilter
>
filters
=
null
;
private
Map
<
Class
<?>,
MethodFilter
>
filters
=
null
;
// Using distance will ensure a more accurate match is discovered,
// more closely following the Java rules.
private
boolean
useDistance
=
false
;
public
ReflectiveMethodResolver
()
{
}
/**
* This constructors allows the ReflectiveMethodResolver to be configured such that it will
* use a distance computation to check which is the better of two close matches (when there
* are multiple matches). Using the distance computation is intended to ensure matches
* are more closely representative of what a Java compiler would do when taking into
* account boxing/unboxing and whether the method candidates are declared to handle a
* supertype of the type (of the argument) being passed in.
* @param useDistance true if distance computation should be used when calculating matches
*/
public
ReflectiveMethodResolver
(
boolean
useDistance
)
{
this
.
useDistance
=
useDistance
;
}
/**
/**
* Locate a method on a type. There are three kinds of match that might occur:
* Locate a method on a type. There are three kinds of match that might occur:
* <ol>
* <ol>
...
@@ -93,6 +114,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
...
@@ -93,6 +114,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
});
});
Method
closeMatch
=
null
;
Method
closeMatch
=
null
;
int
closeMatchDistance
=
Integer
.
MAX_VALUE
;
int
[]
argsToConvert
=
null
;
int
[]
argsToConvert
=
null
;
Method
matchRequiringConversion
=
null
;
Method
matchRequiringConversion
=
null
;
boolean
multipleOptions
=
false
;
boolean
multipleOptions
=
false
;
...
@@ -121,7 +143,16 @@ public class ReflectiveMethodResolver implements MethodResolver {
...
@@ -121,7 +143,16 @@ public class ReflectiveMethodResolver implements MethodResolver {
return
new
ReflectiveMethodExecutor
(
method
,
null
);
return
new
ReflectiveMethodExecutor
(
method
,
null
);
}
}
else
if
(
matchInfo
.
kind
==
ReflectionHelper
.
ArgsMatchKind
.
CLOSE
)
{
else
if
(
matchInfo
.
kind
==
ReflectionHelper
.
ArgsMatchKind
.
CLOSE
)
{
closeMatch
=
method
;
if
(!
useDistance
)
{
closeMatch
=
method
;
}
else
{
int
matchDistance
=
ReflectionHelper
.
getTypeDifferenceWeight
(
paramDescriptors
,
argumentTypes
);
if
(
matchDistance
<
closeMatchDistance
)
{
// this is a better match
closeMatchDistance
=
matchDistance
;
closeMatch
=
method
;
}
}
}
}
else
if
(
matchInfo
.
kind
==
ReflectionHelper
.
ArgsMatchKind
.
REQUIRES_CONVERSION
)
{
else
if
(
matchInfo
.
kind
==
ReflectionHelper
.
ArgsMatchKind
.
REQUIRES_CONVERSION
)
{
if
(
matchRequiringConversion
!=
null
)
{
if
(
matchRequiringConversion
!=
null
)
{
...
...
org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java
浏览文件 @
2f733bed
...
@@ -813,6 +813,96 @@ public class SpringEL300Tests extends ExpressionTestCase {
...
@@ -813,6 +813,96 @@ public class SpringEL300Tests extends ExpressionTestCase {
assertEquals
(
"[D(aaa), D(bbb), D(ccc)]"
,
value3
.
toString
());
assertEquals
(
"[D(aaa), D(bbb), D(ccc)]"
,
value3
.
toString
());
}
}
/**
* Test whether {@link ReflectiveMethodResolver} follows Java Method Invocation Conversion order. And more precisely
* that widening reference conversion is 'higher' than a unboxing conversion.
*/
@Test
public
void
testConversionPriority_8224
()
throws
Exception
{
@SuppressWarnings
(
"unused"
)
class
ConversionPriority1
{
public
int
getX
(
Number
i
)
{
return
20
;
}
public
int
getX
(
int
i
)
{
return
10
;
}
}
@SuppressWarnings
(
"unused"
)
class
ConversionPriority2
{
public
int
getX
(
int
i
)
{
return
10
;
}
public
int
getX
(
Number
i
)
{
return
20
;
}
}
final
Integer
INTEGER
=
Integer
.
valueOf
(
7
);
EvaluationContext
emptyEvalContext
=
new
StandardEvaluationContext
();
List
<
TypeDescriptor
>
args
=
new
ArrayList
<
TypeDescriptor
>();
args
.
add
(
TypeDescriptor
.
forObject
(
new
Integer
(
42
)));
ConversionPriority1
target
=
new
ConversionPriority1
();
MethodExecutor
me
=
new
ReflectiveMethodResolver
(
true
).
resolve
(
emptyEvalContext
,
target
,
"getX"
,
args
);
// MethodInvoker chooses getX(int i) when passing Integer
final
int
actual
=
(
Integer
)
me
.
execute
(
emptyEvalContext
,
target
,
new
Integer
(
42
)).
getValue
();
// Compiler chooses getX(Number i) when passing Integer
final
int
compiler
=
target
.
getX
(
INTEGER
);
// Fails!
assertEquals
(
compiler
,
actual
);
ConversionPriority2
target2
=
new
ConversionPriority2
();
MethodExecutor
me2
=
new
ReflectiveMethodResolver
(
true
).
resolve
(
emptyEvalContext
,
target2
,
"getX"
,
args
);
// MethodInvoker chooses getX(int i) when passing Integer
int
actual2
=
(
Integer
)
me2
.
execute
(
emptyEvalContext
,
target2
,
new
Integer
(
42
)).
getValue
();
// Compiler chooses getX(Number i) when passing Integer
int
compiler2
=
target2
.
getX
(
INTEGER
);
// Fails!
assertEquals
(
compiler2
,
actual2
);
}
/**
* Test whether {@link ReflectiveMethodResolver} handles Widening Primitive Conversion. That's passing an 'int' to a
* method accepting 'long' is ok.
*/
@Test
public
void
testWideningPrimitiveConversion_8224
()
throws
Exception
{
class
WideningPrimitiveConversion
{
public
int
getX
(
long
i
)
{
return
10
;
}
}
final
Integer
INTEGER_VALUE
=
Integer
.
valueOf
(
7
);
WideningPrimitiveConversion
target
=
new
WideningPrimitiveConversion
();
EvaluationContext
emptyEvalContext
=
new
StandardEvaluationContext
();
List
<
TypeDescriptor
>
args
=
new
ArrayList
<
TypeDescriptor
>();
args
.
add
(
TypeDescriptor
.
forObject
(
INTEGER_VALUE
));
MethodExecutor
me
=
new
ReflectiveMethodResolver
(
true
).
resolve
(
emptyEvalContext
,
target
,
"getX"
,
args
);
final
int
actual
=
(
Integer
)
me
.
execute
(
emptyEvalContext
,
target
,
INTEGER_VALUE
).
getValue
();
final
int
compiler
=
target
.
getX
(
INTEGER_VALUE
);
assertEquals
(
compiler
,
actual
);
}
@Test
@Test
public
void
varargsAndPrimitives_SPR8174
()
throws
Exception
{
public
void
varargsAndPrimitives_SPR8174
()
throws
Exception
{
EvaluationContext
emptyEvalContext
=
new
StandardEvaluationContext
();
EvaluationContext
emptyEvalContext
=
new
StandardEvaluationContext
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录