Java 是否可以通过反射处理类元数据以确保采用干式方法?

Java 是否可以通过反射处理类元数据以确保采用干式方法?,java,reflection,metadata,Java,Reflection,Metadata,这个标题似乎令人不安,但让我解释一下 我面临着一个有趣的挑战,我有一个类的层次结构,这些类关联了一个对象,该对象存储了与其每个属性相关的元数据(一个具有编辑标志(如UPDATED或NO_UPDATE)的int值枚举) 合并两个对象时会出现问题,因为我不想检查类上的每个字段,看它是否已更新并跳过或应用更改 我的想法是:反思 所有对象都在一个接口后面,因此我可以使用IObject.class.getMethods()并以这种方式迭代该数组: IClass class = //Instance of

这个标题似乎令人不安,但让我解释一下

我面临着一个有趣的挑战,我有一个类的层次结构,这些类关联了一个对象,该对象存储了与其每个属性相关的元数据(一个具有编辑标志(如UPDATED或NO_UPDATE)的int值枚举)

合并两个对象时会出现问题,因为我不想检查类上的每个字段,看它是否已更新并跳过或应用更改

我的想法是:反思

所有对象都在一个接口后面,因此我可以使用IObject.class.getMethods()并以这种方式迭代该数组:

IClass class = //Instance of the first class;
IAnotherClass anotherClass = //Instance of the second class;
for(Method m  : IObject.class.getMethods()) {
    if(m.getName().startsWith("get")) {
        try {
            //Under this method (which is a getter) I cast it on 
            //both classes who implement interfaces that extend an
            //interface that defines the getters to make them
            //consistent and ensure I'll invoke the same methods.
            String propertyClass = (String)m.invoke(class);
            String propertyAnotherClass = (String)m.invoke(anotherClass);
            if(propertyClass != propertyAnotherClass) {
                //Update attribute and attribute status.
            }
        } catch (Exception e) {

        }
    }
}
有没有其他方法来实现这一点,或者我应该坚持使用冗长的方法来调用每个属性的属性并执行类似的检查?。对象不会有太大的变化,体系结构是非常模块化的,因此如果字段发生变化,就不会有太多的更新,但是必须改变这样的方法让我有点担心

编辑1:我正在发布一个到目前为止我得到的工作代码。这段代码对我来说是一个解决方案,但是,它很难工作,我把它作为最后的资源使用,不是因为我有时间花,而是因为我不想重新发现轮子。如果我使用它,我将使用这些方法创建一个静态列表,因此考虑到AlexR指出的事实,我只需要获取该列表一次

private static void merge(IClazz from, IClazz to) {
        Method methods[] = from.getClass().getDeclaredMethods();
        for(Method m : methods) {
            if(m.getName().startsWith("get") && !m.getName().equals("getMetadata")) {
                try {                   
                    String commonMethodAnchor = m.getName().split("get")[1];
                    if(!m.getReturnType().cast(m.invoke(from)).equals(m.getReturnType().cast(m.invoke(to)))) {
                        String setterMethodName = "set" + commonMethodAnchor;
                        Method setter = IClazz.class.getDeclaredMethod(setterMethodName, m.getReturnType());
                        setter.invoke(to, m.getReturnType().cast(m.invoke(from)));
                        //Updating metadata
                        String metadataMethodName = "set" + commonMethodAnchor + "Status";
                        Method metadataUpdater = IClazzMetadata.class.getDeclaredMethod(metadataMethodName, int.class);
                        metadataUpdater.invoke(to.getMetadata(), 1);
                    }

                } catch (Exception e) {

                }
            }
        }
    }
metadataUpdater将该值设置为1,只是为了模拟我在实际场景中使用的“UPDATED”标志

编辑3:感谢Juan、David和AlexR的建议和指导!他们真的让我考虑了我起初没有考虑的事情(我把所有的答案都推翻了,因为他们都帮了我的忙)。p>
在添加了AlexR sugegsted并检查了jDTO和Apache Commons之后(发现最终的一般概念非常相似),我决定坚持使用我的代码,而不是使用其他工具,因为在给定解决方案的对象层次结构和元数据结构的情况下,它是有效的,并且到目前为止没有出现异常。代码是第二次编辑的代码,我将其放在了一个帮助器类上,该类最终实现了这一点。

Apache Commons Bean UTIL可能会解决您的问题:

如果要复制所有属性,请尝试使用copyProperties:

请看以下示例:


我认为最好的方法是使用代理对象,动态代理或cglib增强器或类似的东西,因此您可以修饰getter和setter,并且可以跟踪那里的更改


希望有帮助。

您的方法还可以,但请记住
getMethod()
invoke()
慢得多,因此如果您的代码对性能至关重要,您可能需要缓存
方法
对象

您可以使用对象到对象的映射框架,例如jDTO Binder来处理属性的副本。谢谢!我来看看。我想你真正想要的是cglib增强器,只需少量代码,你就可以实现你想要的。我设法让一个例子工作起来,而不必引入cglib。如果我能定义某种标准,我就能在我的应用程序中使用它。我仍然在研究jDTO和BeanUtils,因为我想使用一个现有的(并且调试过的:)选项。谢谢我不是要复制所有属性,而是要根据一组标志复制某些属性,这些标志决定值是否应该更新。我还在BeanUtils下寻找一种更具体的方法。你可以使用注解+BeanUtils代码。查看BeanUtils.copyProperty中的代码,并在添加到属性/方法的注释中添加一个IF子句以表示存在。如果注释已呈现,则将流程流保留为copyProperty中的流程,否则停止并使用下一个属性继续流程。元数据动态存储在容器中(也称为另一个包含一组标志的对象),因此,每次我处理对象时,使用注释可能需要某种变通方法将现有元数据转换为注释。@Gamb,我认为无论是否使用注释,您都无法避免IF子句。如果注释不起作用,可能使用AOP-AspectJ,您可以验证类/对象的某些方面,并在不更改代码的情况下解决它。但我不是100%确定。事实上,我的代码对性能至关重要,所以我会考虑你的建议。谢谢
    FromBean fromBean = new FromBean("fromBean", "fromBeanAProp", "fromBeanBProp");
    ToBean toBean = new ToBean("toBean", "toBeanBProp", "toBeanCProp");
    System.out.println(ToStringBuilder.reflectionToString(fromBean));
    System.out.println(ToStringBuilder.reflectionToString(toBean));
    try {
        System.out.println("Copying properties from fromBean to toBean");
        BeanUtils.copyProperties(toBean, fromBean);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    System.out.println(ToStringBuilder.reflectionToString(fromBean));
    System.out.println(ToStringBuilder.reflectionToString(toBean));