Windows和Linux中继承方法上的Java反射是否不同?
在设置Hudson进行持续集成测试(在JeOS服务器上)时,我遇到了一些奇怪的行为,我希望SO的优秀人员能向我解释 我们的单元测试严重依赖于域对象的使用,必须设置许多属性(由于数据库中的空约束)。为了保持测试的可读性,我们创建了一个类InstantiationUtils,它可以实例化一个对象并通过反射设置一系列属性:Windows和Linux中继承方法上的Java反射是否不同?,java,windows,linux,reflection,Java,Windows,Linux,Reflection,在设置Hudson进行持续集成测试(在JeOS服务器上)时,我遇到了一些奇怪的行为,我希望SO的优秀人员能向我解释 我们的单元测试严重依赖于域对象的使用,必须设置许多属性(由于数据库中的空约束)。为了保持测试的可读性,我们创建了一个类InstantiationUtils,它可以实例化一个对象并通过反射设置一系列属性: public static <T> T newInstance(final Class<T> type, final KeyValuePair<?&g
public static <T> T newInstance(final Class<T> type, final KeyValuePair<?>... propertyValues) {
return ReflectionUtils.reflectionOperation(new ReflectionOperation<T>() {
@Override
public T perform() throws Exception {
T object = type.newInstance();
for (KeyValuePair<?> propertyValue : propertyValues) {
String propertyName = propertyValue.getKey();
Object value = propertyValue.getValue();
String setterName = "set" + StringUtils.capitalize(propertyName);
ReflectionUtils.invoke(object, setterName, value);
}
return object;
}
});
}
public static void invoke(final Object target, final String methodName, final Object... params) {
List<Class<?>> parameterTypes = ListUtils.map(asList(params), "class");
Class<?> targetClass = target.getClass();
Method method = MethodUtils.getMatchingAccessibleMethod(targetClass, methodName,
parameterTypes.toArray(new Class<?>[] {}));
invoke(target, method, params);
}
public class Foo {
private String foo;
public void setFoo(final String foo) {
this.foo = foo;
}
}
public class Bar extends Foo {
private String bar;
public void setBar(final String bar) {
this.bar = bar;
}
}
publicstatict newInstance(最终类类型、最终键值对…属性值){
返回ReflectionUtils.reflectionOperation(新的reflectionOperation(){
@凌驾
public T perform()引发异常{
T object=type.newInstance();
for(KeyValuePair propertyValue:propertyValue){
字符串propertyName=propertyValue.getKey();
对象值=propertyValue.getValue();
String setterName=“set”+StringUtils.capitalize(propertyName);
invoke(对象、setterName、值);
}
返回对象;
}
});
}
公共静态void调用(最终对象目标、最终字符串methodName、最终对象…参数){
List targetClass=target.getClass();
Method=MethodUtils.getMatchingAccessibleMethod(targetClass,methodName,
toArray(新类[]{});
调用(目标、方法、参数);
}
公开课Foo{
私人字符串foo;
公共void setFoo(最终字符串foo){
this.foo=foo;
}
}
公共类Bar扩展了Foo{
私人弦杆;
公共空心立根杆(最终弦杆){
这个.bar=bar;
}
}
不幸的是,编写这段代码的人已经不再为我们工作了,但据我所知,这段代码没有什么问题。对于Windows也是如此-我们在整个单元测试中使用实例化utils,没有任何问题
然而,Linux则不同。事实证明,在Linux中,newInstance()方法只适用于我们要实例化的类的直接(即非继承)成员 实例化utils.newInstance(Bar.class,“Bar”,“12345”);将在实例化utils.newInstance(Bar.class,“foo”,“98765”)时工作;将在Linux上失败,但以下情况除外: xxx.xxx.xxx.ReflectionUtils$ReflectionException:java.lang.NoSuchMethodException:属性“foo”没有setter方法 在Windows上,这两个调用都可以工作(我知道newInstance签名不匹配;我们有几个重载的newInstance()方法将参数转换为KeyValuePairs) 我很难接受继承的公共方法会受到不同的对待,所以我已经用我能想到的所有方法对此进行了测试。最后总是得出结论,在Linux下,至少在上面使用反射的情况下,我们无法访问公共继承方法 在Windows上,我使用Sun的JRE 1.6.0.11,在Linux上也是Sun,但版本是1.6.0.7 有人能确认这是否正确吗?或者反射使用是否存在某种缺陷?可能是不同Java运行时之间的设置不同吗 当然,我怀疑这是一个平台问题——几乎可以肯定这与两个环境之间的JRE版本/设置有关
您确实需要将源代码发布到MethodUtils.getMatchingAccessibleMethod您在Linux、Sun、GCJ等上使用哪种JVM?如果您使用的不是Sun的JVM,您可以尝试安装它,看看这是否有区别。您有不同的地区吗
StringUtils.capitalize(propertyName)
可能会产生不同的输出。您使用的是MethodUtils,它有一些:
已知的限制
在默认访问超类中访问公共方法
调用默认访问超类中包含的公共方法时会出现问题。反射可以很好地定位这些方法,并正确地将它们指定为公共。但是,如果调用该方法,则会引发IllegalAccessException
要检查的另一件事是,如果setFoo()方法重载,这也可能会导致问题…是否检查了
类路径?您是否根据所处的平台选择要实例化的类的不同版本?(例如,到处都是旧的代码库等?)有几件事需要尝试
在Linux上,尝试在没有对getFoo()的反射调用的情况下编译代码-如果它无法编译,那么反射就没有工作的希望(这取决于yoiu在运行时如何设置CLASSAPTH…)
尝试添加下面的代码,并在Linux和Windows上运行
final Properties properties;
properties = System.getProperties();
for(final Entry<Object, Object> entry : properties.entrySet())
{
System.out.println(entry.getKey() + " " + entry.getValue());
}
最终属性;
properties=System.getProperties();
for(最终条目:properties.entrySet())
{
System.out.println(entry.getKey()+“”+entry.getValue());
}
检查输出以确保您使用的是smae JDK/JRE。还要检查以确保类路径正确,以便实际加载您认为正在加载的内容。谜团部分解决:
getMatchingAccessibleMethod()显然在Linux和Windows上的工作方式不同
通过改为使用MethodUtils.getAccessibleMethod(),它可以正常工作。为什么,我不知道,但我猜MethodUtils在计算方法应该具有什么签名时,以某种方式误解了参数列表
我想花更多的时间来研究这一点,但总是有事情要做,有项目要交付,所以我必须接受getAccessibleMethod的工作原理,然后继续:-)
感谢大家的投入 您是否在两个操作系统上使用相同版本的JRE?这听起来比操作系统更可能导致差异。还有,如果你能浓缩