2

我有两个类,如下:

public class Person {
    private String dob;
    private PersonName personName;
}

public class PersonName {
    private String firstName;
    private String lastName;
}

我正在使用 Java 反射动态设置这些值。

首先,我创建一个实例Person并设置dob. 之后,我需要PersonNamePerson. 所以我创建了另一个实例,PersonName并在其中设置了值PersonName。之后,我试图在实体中设置PersonName实例。Person

为此,我使用了这样的代码:

Class componentClass = Class.forName(clazz.getName());
Field field = parentClass.getDeclaredField(Introspector
                        .decapitalize(clazz.getSimpleName()));
field.setAccessible(true);
field.set(parentClass, componentClass);

这里,parentClass是一个Person实例,componentClass是一个PersonName实例。我正在尝试在 中设置PersonNamePerson但出现以下异常:

java.lang.IllegalArgumentException: Can not set com.rise.common.model.PersonName field
com.rise.common.model.Person.personName to java.lang.Class

那么如何动态设置值呢?

谢谢。

我的整个代码:

protected void assignProperties(List<Object[]> argResults,
        List<Class> argAllClassesList, Class argParentClass)
        throws ClassNotFoundException, NoSuchFieldException,
        SecurityException, IllegalArgumentException,
        IllegalAccessException, InvocationTargetException, InstantiationException {
    List<Object[]> results = (List<Object[]>) Precondition.ensureNotEmpty(
            argResults, "Output List");
    List<Class<?>> personClassList = new ArrayList<Class<?>>();
    for (Object[] recordValues : results) {
        Class parentClass = Class.forName(this.getPersistentClass()
                .getName());
        parentClass.newInstance();
        int count = 0;
        count = assignValues(recordValues, parentClass, count);
        for (Class clazz : argAllClassesList) {
            Class componentClass = Class.forName(clazz.getName());
            componentClass.newInstance();
            String decapitalize = Introspector.decapitalize(clazz
                    .getSimpleName());
            Field field = parentClass.getDeclaredField(decapitalize);
            field.setAccessible(true);
            assignValues(recordValues, componentClass, count);
             field.set(parentClass, componentClass);
        }
        personClassList.add(parentClass);
    }

    for (Class<?> class1 : personClassList) {
        Class<Person> person = (Class<Person>) class1;
        System.out.println(person);
    }

}

private int assignValues(Object[] argRecordValues, Class argClass,
        int argCount) {
    String paramName = Introspector.decapitalize(argClass.getSimpleName());
    if (Precondition.checkNotEmpty(paramName)) {
        List<Field> fieldNames = TenantConfigHelper.getInstance()
                .getModelNameVsFieldsMap().get(paramName);
        try {
            for (Field field : fieldNames) {
                BeanUtils.setProperty(argClass, field.getName(),
                        argRecordValues[argCount]);
                ++argCount;
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    return argCount;
}
4

4 回答 4

3

该消息解释了问题所在:componentClass 不是 PersonName 的实例。它是一个类型的对象Class(可能Class<PersonName>)。您可能忘记实例化该类。

编辑:

您的代码可以:

parentClass.newInstance();

componentClass.newInstance();

这相当于做

new Parent();

new ParentName();

所以它创建了一个实例,但没有将它分配给任何变量,因此不会对创建的实例做任何事情,这将立即被垃圾回收。

你要

Object parent = parentClass.newInstance();
Object component = componentClass.newInstance();
field.set(parent, component);
于 2013-08-01T18:35:20.940 回答
1

我一直在寻找同样类型的答案,基本上每个人用 Object 指定的都是正确的。我还创建了一个通用列表,List<Object>而不是实际的类名。下面是一个返回对象类型列表的函数。我传入类名并使用.loadClass 加载它。比使用 .newInstance 使用该新类实例创建一个新对象。dList 加载了每个 objectClass 的所有信息,这是我通过 className 变量传入的类。其余的基本上只是使用结果集中的值动态调用该特定类中的所有“set”方法。

protected List<Object> FillObject(ResultSet rs, String className)
    {
        List<Object> dList = new ArrayList<Object>();

        try
        {
            ClassLoader classLoader = GenericModel.class.getClassLoader();

            while (rs.next())
            {
                Class reflectionClass = classLoader.loadClass("models." + className);

                Object objectClass = reflectionClass.newInstance();

                Method[] methods = reflectionClass.getMethods();

                for(Method method: methods)
                {
                    if (method.getName().indexOf("set") > -1)
                    {
                        Class[] parameterTypes = method.getParameterTypes();

                        for(Class pT: parameterTypes)
                        {
                            Method setMethod = reflectionClass.getMethod(method.getName(), pT);

                            switch(pT.getName())
                            {
                                case "int":
                                    int intValue = rs.getInt(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, intValue);
                                    break;

                                case "java.util.Date":
                                    Date dateValue = rs.getDate(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, dateValue);
                                    break;

                                case "boolean":
                                    boolean boolValue = rs.getBoolean(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, boolValue);
                                    break;

                                default:
                                    String stringValue = rs.getString(method.getName().replace("set", ""));
                                    setMethod.invoke(objectClass, stringValue);
                                    break;
                            }
                        }
                    }
                }

                dList.add(objectClass);
            }
        }
        catch (Exception e)
        {
            this.setConnectionMessage("ERROR: reflection class loading: " + e.getMessage());
        }

        return dList;
    }
于 2014-01-11T03:45:41.427 回答
1

我认为在这里工作的 Java 类定义和实例之间的区别可能有些混淆。您想设置特定实例上的字段值,而不是类本身。像这样的东西可能会起作用:

Object parentClassInstance = parentClass.newInstance();
Class componentClass = Class.forName(clazz.getName());
Object componentClassInstance = componentClass.newInstance();
Field field = parentClass.getDeclaredField(Introspector
                        .decapitalize(clazz.getSimpleName()));
field.setAccessible(true);
field.set(parentClassInstance, componentClassInstance);

但是,查看整个代码示例,有点难以理解。为什么会有一个Listof Classes,名字像personClassList,这似乎表明每个类都应该是同一个类,Person?我觉得它可能应该是 a List<Person>or maybe List<Object>,你会用你的Person实例而不是Class对象本身来填充它。

编辑以在评论中回答以下问题:

我必须返回 List 的 insetad 实例,所以我如何动态地从 Class 到 Person 键入 case ......?

您不能从Classto 转换Person,因为Person它可能不是Class.

相反,将您的列表声明为 aList<Person>而不是 aList<Class<?>>

List<Person> personList = new ArrayList<Person>();

然后将Person对象而不是对象添加到第一个循环Class底部的列表中。for

personList.add((Person)parentClassInstance);

底部的循环也需要更改:

for (Person person : personList) {
    System.out.println(person);
}
于 2013-08-01T19:09:20.550 回答
0

类型系统由编译器验证。虽然在运行时可能有一些额外的安全性,但这种额外的安全性甚至不接近编译器强加的安全性。这就引出了一个问题,为什么?

假设您可以使这些东西正常工作,那么您究竟如何证明将class1以下类型转换为Class<Person>类型是合理的?你宣布它是一个Class<?>

for (Class<?> class1 : personClassList) {
    Class<Person> person = (Class<Person>) class1;
    System.out.println(person);
}
于 2013-08-01T19:04:13.813 回答