我在我正在编写的模型中有一个带有签名public void setFoo(int newFoo)
的方法。我正在使用以下代码从我的控制器中调用它:
protected void setModelProperty(String propertyName, Object newValue) {
for (AbstractModel model: registeredModels) {
try {
Method method = model.getClass().
getMethod("set"+propertyName, new Class[] {
newValue.getClass()
}
);
method.invoke(model, newValue);
} catch (Exception ex) {
// Handle exception.
System.err.println(ex.toString());
}
}
}
调用controller.setModelProperty("Foo",5);
这样的方法会导致抛出异常:java.lang.NoSuchMethodException: foo.bar.models.FooModel.setFoo(java.lang.Integer)
- 看起来int
被装箱为Integer
,而不是5
匹配setFoo的签名。
有没有办法说服这个反射代码传递public void setFoo(Integer newFoo)
(或我传入的任何int)作为一个整数,没有拳击?或者我必须在我的模型和unbox中明确创建{{1}},然后调用原始的setFoo?
答案 0 :(得分:4)
您可以将setModelProperty
专门用于您希望使用的任何基元:
protected void setModelProperty(String propertyName, int newValue) { /* ... */ }
或者,您可以在newValue上使用instanceof来检查盒装基元:
Class[] classes;
if (newValue instanceof Integer) {
classes = new Class[] { int.class };
} else if (newValue instanceof Double) {
/* etc...*/
} else {
classes = new Class[] {newValue.getClass() };
}
或者最后,如果您拥有setFoo的源代码,您可以将其更改为使用盒装的Integer而不是int - 开销通常可以忽略不计。
答案 1 :(得分:2)
有没有办法说服这个 反射代码传递5(或 无论我传入什么int)作为整数, 没有拳击?
当您的方法签名显示Object newValue
时,因为int永远不会是Object
。保持方法通用的一种方法是让调用者明确地传入类型,即:
protected void setModelProperty(String propertyName, Object newValue, Class type) {
或者,您可以测试newValue
的类型以查看它是否是原始包装器,并且在这种情况下查找该方法的原语和包装版本。但是,当用户传入null
时,这将无效。实际上,在这种情况下,该方法根本不起作用......
答案 2 :(得分:1)
当调用setModelProperty()时,newValue被装箱为整数。这是它被调用的唯一方式; 'int'不是Object的实例。 newValue.getClass()返回“Integer”,因此对getMethod()的调用失败。
如果你想在这里使用原语,你需要一个特殊版本的setModelProperty。或者,您可以编写方法setFoo(Integer)。
或者更普遍的是你可以写:
if (newValue.getClass()==Integer.class) {
// code to look for a method with an int argument
}
答案 3 :(得分:0)
问题不在于调用,而在于获取方法,因为您使用的Integer.class与int.class不同。
如果第一个方法失败,你可以通过第二次调用get方法来修复它:
protected void setModelProperty(String propertyName, Object newValue) {
for (AbstractModel model: registeredModels) {
Method method = null;
try {
method = model.getClass().
getMethod("set"+propertyName, new Class[] {
newValue.getClass()
}
);
} catch (Exception ex) {
try {
if (canBoxPrimitive(newValue.getClass()) {
method = model.getClass().
getMethod("set"+propertyName, new Class[] {
primitiveClass(newValue.getClass())
}
}
}
catch (Exception ex) {
// handle it
}
}
method.invoke(model, newValue);
}
}
有关编码函数的选项: boolean canBoxPrimitive(Class)和 Class primitiveClass(Class)你可以看看这里:Dynamically find the class that represents a primitive Java type
答案 4 :(得分:0)
将完成Outoboxing,但您正在寻找错误的方法。参数类型数组不正确。对于int,类型将是Integer.TYPE而不是Integer.class。
尝试使用以下内容以使其工作,无论参数类型如何(outoboxing都会这样做):
protected void setModelProperty(String propertyName, Object newValue) {
for (AbstractModel model: registeredModels) {
try {
Method method = findSetter(model.getClass(), propertyName);
method.invoke(model, newValue);
} catch (Exception ex) {
// Handle exception.
System.err.println(ex.toString());
}
}
}
private Method findSetter(Class<?> type, String propertyName) {
for (Method methos : type.getMethods()) {
if (method.getName().equalsIgnoreCase("set" + propertyName) && method.getParameterTypes().length == 1) {
return method;
}
}
throw new NoSuchMethodError("No setter for " + propertyName);
}
答案 5 :(得分:-1)
你试过吗
Integer.valueOf(5)
以整数形式传递5而不是int?