使用 Java 反射找到最匹配的 writeMethod [英] Find best matching writeMethod with Java reflection
问题描述
Commons BeanUtils getMatchingAccessibleMethod 找到匹配,但不是最佳匹配.
Commons BeanUtils getMatchingAccessibleMethod finds a match, but not the best possible match.
考虑这个简单的例子:
public class TestReflection extends TestCase {
public static class BeanA {
private DataX data;
public BeanA setData(DataX x) {
System.out.println("setData x");
return this;
}
public BeanA setData(DataY y) {
System.out.println("setData y");
return this;
}
}
static class DataX {
}
static class DataY extends DataX {
}
static class DataZ extends DataY {
}
public void testPropertyUtils() {
try {
BeanA a = new BeanA();
System.out.println("--- setters:");
a.setData(new DataX());
a.setData(new DataY());
a.setData(new DataZ());
System.out.println("--- invokeMethod");
MethodUtils.invokeMethod(a, "setData", new DataZ());
} catch (Exception e) {
e.printStackTrace();
}
}
}
(提示:invokeMethod 使用 getMatchingAccessibleMethod)
(Hint: invokeMethod uses getMatchingAccessibleMethod)
以上代码输出
--- setters:
setData x
setData y
setData y
--- invokeMethod
setData x
最后一行应该说setData y",因为用 DataZ 对象调用setData"的最佳匹配应该是接口中带有 DataY 的对象(就像 setData(new DataZ()) 一样).
The last line shoud say "setData y" because the best match for calling "setData" with a DataZ object should be the one with DataY in the interface (just like setData(new DataZ()) does).
有没有办法找到可能的最佳匹配,还是我必须自己编码?
Is there a way to find the best possible match or do I have to code that myself?
推荐答案
我只是很好奇它在 MethodUtils.java 中是如何工作的,所以我查看了里面.为了确定应使用哪种方法作为最佳匹配,每种方法都会产生成本.要计算成本,有一种方法(带有一些额外的 dbg 输出):
I was just curious how does it works in MethodUtils.java, so i looked inside. To determine which method should be used as the best match, every method will gain a cost. To calculate the cost there is a method (with some extra dbg-output):
/**
* Gets the number of steps required needed to turn the source class into the
* destination class. This represents the number of steps in the object hierarchy
* graph.
* @param srcClass The source class
* @param destClass The destination class
* @return The cost of transforming an object
*/
private static float getObjectTransformationCost(Class srcClass, Class destClass) {
System.out.println("----------- start calculate cost from " + srcClass + " to " + destClass + "------------");
float cost = 0.0f;
while (destClass != null && !destClass.equals(srcClass)) {
System.out.println(srcClass + " and " + destClass + " are " + (destClass.equals(srcClass)? " equal" : " not equal"));
if (destClass.isInterface() && isAssignmentCompatible(destClass,srcClass)) {
// slight penalty for interface match.
// we still want an exact match to override an interface match, but
// an interface match should override anything where we have to get a
// superclass.
cost += 0.25f;
break;
}
cost++;
destClass = destClass.getSuperclass();
}
/*
* If the destination class is null, we've travelled all the way up to
* an Object match. We'll penalize this by adding 1.5 to the cost.
*/
if (destClass == null) {
cost += 1.5f;
}
System.out.println("COST IS " + cost);
return cost;
}
所以输出是
--- setters:
setData x
setData y
setData y
--- invokeMethod
----------- start calculate cost from class Lolka$DataZ to class Lolka$DataX------------
class Lolka$DataZ and class Lolka$DataX are not equal
class Lolka$DataZ and class java.lang.Object are not equal
COST IS 3.5
----------- start calculate cost from class Lolka$DataZ to class Lolka$DataY------------
class Lolka$DataZ and class Lolka$DataY are not equal
class Lolka$DataZ and class Lolka$DataX are not equal
class Lolka$DataZ and class java.lang.Object are not equal
COST IS 4.5
setData x
所以invokeMethode假设转换DataX只是一个继承级形式的Object,而DataY是2.所以DataX-method更便宜".这就是背后的逻辑.
So invokeMethode assumes that converting DataX is only one inheritance-level form Object, and DataY is 2. So DataX-method is "cheaper". Thats the logic behind that.
UPD:将 dest 更改为 src 工作正常,所以如果我使用
UPD: changing dest to src works fine, so if i use
private static float getObjectTransformationCost(Class srcClass, Class destClass) {
float cost = 0.0f;
while (srcClass != null && !destClass.equals(srcClass)) {
if (destClass.isInterface() && isAssignmentCompatible(destClass,srcClass)) {
cost += 0.25f;
break;
}
cost++;
srcClass = srcClass.getSuperclass();
}
if (srcClass == null) {
cost += 1.5f;
}
return cost;
}
输出是
--- setters:
setData x
setData y
setData y
--- invokeMethod
setData y
这篇关于使用 Java 反射找到最匹配的 writeMethod的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!