我使用反射将getter从一个类映射到另一个类中的setter,即我有stuts1使用的表单类,主要用于显示文本(字符串),我有后端使用的纯Java对象,它保存值在他们的特定类型。我目前在getter和setter之间进行映射工作很容易,但是我遇到了混合类型的问题。我使用setter中的参数类型来查看预期的内容,因此我需要从getter中确定对象的类型,并将其转换为预期的类型。
E.g。
HomePageForm -> HomePageData
Name="Alexei" -> String name; (Maps correctly)
Age="22" -> int age; (Needs casting from string to int and visa-vera in reverse)
以下是我目前的代码
/**
* Map the two given objects by reflecting the methods from the mapTo object and finding its setter methods. Then
* find the corresponding getter method in the mapFrom class and invoke them to obtain each attribute value.
* Finally invoke the setter method for the mapTo class to set the attribute value.
*
* @param mapFrom The object to map attribute values from
* @param mapTo The object to map attribute values to
*/
private void map(Object mapFrom, Object mapTo) {
Method [] methods = mapTo.getClass().getMethods();
for (Method methodTo : methods) {
if (isSetter(methodTo)) {
try {
//The attribute to map to setter from getter
String attName = methodTo.getName().substring(3);
//Find the corresponding getter method to retrieve the attribute value from
Method methodFrom = mapFrom.getClass().getMethod("get" + attName, new Class<?>[0]);
//If the methodFrom is a valid getter, set the attValue
if (isGetter(methodFrom)) {
//Invoke the getter to get the attribute to set
Object attValue = methodFrom.invoke(mapFrom, new Object[0]);
Class<?> fromType = attValue.getClass();
//Need to cast/parse type here
if (fromType != methodTo.getParameterTypes()[0]){
//!!Do something to case/parse type!!
} //if
//Invoke the setter to set the attribute value
methodTo.invoke(mapTo, attValue);
} //if
} catch (Exception e) {
Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: "
+ "IllegalArgumentException" + e.getMessage());
continue;
}
} //if
} //for
} //map
提前致谢, 阿列克谢蓝。
答案 0 :(得分:1)
我不是反射中的英雄,但我的猜测是int
是原始数据类型,attValue
类型为Object
。
您可以尝试将年龄类型更改为Integer
,以便将其转换为Object
答案 1 :(得分:0)
是的,@ Molske是现货。问题是将int
返回值提升为Integer
,然后进行比较:
if (fromType != methodTo.getParameterTypes()[0])
我刚刚对你的代码进行了快速测试,我得到了例外:
java.lang.AssertionError: expected:<class java.lang.Integer> but was:<int>
而不是fromType
,如果您与methodFrom.getReturnType()
进行比较,则代码应该有效:
if (methodFrom.getReturnType() != methodTo.getParameterTypes()[0])
这是我正在进行的测试:
@Test
public void testException() throws Exception {
Foo foo = new Foo();
Bar bar = new Bar();
for (Method methodTo : Bar.class.getMethods()) {
if (methodTo.getName().startsWith("set")) {
String attName = methodTo.getName().substring(3);
Method methodFrom = Foo.class.getMethod("get" + attName);
if (methodFrom != null && methodFrom.getName().startsWith("get")) {
Object attValue = methodFrom.invoke(foo);
// this ignores the auto-boxing issues
assertEquals(methodFrom.getReturnType(),
methodTo.getParameterTypes()[0]);
methodTo.invoke(bar, attValue);
}
}
}
}
private static class Foo {
public int getFoo() { return 1; }
}
private static class Bar {
public void setFoo(int i) { System.out.println("i = " + i); }
}
答案 2 :(得分:0)
我最终实施了一个更好的解决方案:
/**
* Map to given objects taking into account the inclusion and exclusion sets.
*
* @param mapFrom The object to map attribute values from
* @param mapTo The object to map attribute values to
*/
private void map(Object mapFrom, Object mapTo)
{
setMapFilter(mapFrom, mapTo);
for (Method sMethod : filterMap.keySet())
{
try
{
//Find the corresponding getter method to retrieve the attribute value from
Method gMethod = filterMap.get(sMethod);
//Invoke the getter to get the attribute to set
Object attValue = gMethod.invoke(mapFrom, new Object[0]);
//Get the mapping types and check their compatibility, if incompatible convert attValue type to toType
Class<?> fromType = gMethod.getReturnType();
Class<?> toType = sMethod.getParameterTypes()[0];
if(!toType.isAssignableFrom(fromType) && Objects.isNotNull(attValue))
{
attValue = parseType(attValue, toType);
} //if
//Invoke the setter to set the attribute value
sMethod.invoke(mapTo, attValue);
}
catch (IllegalArgumentException e)
{
Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: "
+ "IllegalArgumentException " + e.getMessage());
continue;
}
catch (IllegalAccessException e)
{
Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: "
+ "IllegalAccessException " + e.getMessage());
continue;
}
catch (InvocationTargetException e)
{
Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: "
+ "InvocationTargetException " + e.getMessage());
continue;
}
} //for each
} //map
/**
* Refactored method to parse an object, attValue, from it's unknown type to the type expected.
*
* @param attValue The attribute value to parse
* @param type The type expected/to convert to
* @return The attribute value in the expected type, null otherwise
*/
private Object parseType(Object attValue, Class<?> type)
{
Object newAttValue = null;
if (isLiteral(type))
{
newAttValue = attValue.toString();
}
else if (isByte(type))
{
newAttValue = Byte.valueOf(attValue.toString());
}
else if (isInt(type))
{
newAttValue = Integer.valueOf(attValue.toString());
}
else if (isShort(type))
{
newAttValue = Short.valueOf(attValue.toString());
}
else if (isLong(type))
{
newAttValue = Long.valueOf(attValue.toString());
}
else if (isFloat(type))
{
newAttValue = Float.valueOf(attValue.toString());
}
else if (isDouble(type))
{
newAttValue = Double.valueOf(attValue.toString());
}
else if (isBoolean(type))
{
newAttValue = Boolean.valueOf(attValue.toString());
} //if-else if*
return newAttValue;
} //parseType
它比我原来的解决方案更干净,但基本上在映射时,过滤器是由映射方法构建的,这些方法只需循环遍历然后映射。 parse方法只检查类型并在Object.toString()上使用valueOf方法,该方法适用于标准Java类型。
干杯,
Alexei Blue。