`

Hibernate Annotation driven equals and hashCode

阅读更多

The following implementation of equals, hashcode and toString is using the concept of one or more business keys defined by annotations.The annotation @BusinessKey can be applied with an include/exclude filter on field or method level.

Enumeration for include/exclude filter:

public enum Method {
    ALL, NONE, EQUALS, HASH_CODE, TO_STRING
}

Business key annotation:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.FIELD, ElementType.METHOD })
public @interface BusinessKey {
    Method[] include() default Method.ALL;
    Method[] exclude() default Method.NONE;
}

Implementation of equals, hashCode and toString using cached reflection:

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class BeanUtils {
    private static Map<String, List<AccessibleObject>> cache = new Hashtable<String, List<AccessibleObject>>();

    private BeanUtils() {}

    public static boolean equals(Object obj1, Object obj2) {
        if (obj1 == obj2) {
            return true;
        }

        if (obj2 == null || obj2.getClass() != obj1.getClass()) {
            return false;
        }

        EqualsBuilder builder = new EqualsBuilder();

        for (AccessibleObject ao : getAccessibleObjects(obj1, 1)) {
            try {
                if (ao instanceof Field) {
                    builder.append(((Field) ao).get(obj1), ((Field) ao).get(obj2));
                } else {
                    builder.append(((java.lang.reflect.Method) ao).invoke(obj1, (Object[]) null), ((java.lang.reflect.Method) ao).invoke(obj2, (Object[]) null));
                }
            } catch (Exception e) {}
        }

        return builder.isEquals();
    }

    public static int hashCode(Object obj) {
        HashCodeBuilder builder = new HashCodeBuilder();

        for (AccessibleObject ao : getAccessibleObjects(obj, 2)) {
            try {
                if (ao instanceof Field) {
                    builder.append(((Field) ao).get(obj));
                } else {
                    builder.append(((java.lang.reflect.Method) ao).invoke(obj, (Object[]) null));
                }
            } catch (Exception e) {}
        }

        return builder.toHashCode();
    }

    public static String toString(Object obj) {
        ToStringBuilder builder = new ToStringBuilder(obj, ToStringStyle.SHORT_PREFIX_STYLE);

        for (AccessibleObject ao : getAccessibleObjects(obj, 4)) {
            try {
                if (ao instanceof Field) {
                    builder.append(((Field) ao).getName(), ((Field) ao).get(obj));
                } else {
                    builder.append(((java.lang.reflect.Method) ao).getName(), ((java.lang.reflect.Method) ao).invoke(obj, (Object[]) null));
                }
            } catch (Exception e) {}
        }

        return builder.toString();
    }

    private static List<AccessibleObject> getAccessibleObjects(Object obj, int filter) {
        Class<?> clazz = obj.getClass();

        String name = clazz.getName() + filter;

        if (!cache.containsKey(name)) {
            List<AccessibleObject> aos = new ArrayList<AccessibleObject>();

            do {
                Field[] fields = clazz.getDeclaredFields();

                for (Field field : fields) {
                    BusinessKey bk = field.getAnnotation(BusinessKey.class);
                    if (bk != null && (filter(bk) & filter) == filter) {
                        field.setAccessible(true);
                        aos.add(field);
                    }
                }

                java.lang.reflect.Method[] methods = clazz.getDeclaredMethods();

                for (java.lang.reflect.Method method : methods) {
                    BusinessKey bk = method.getAnnotation(BusinessKey.class);
                    if (bk != null && (filter(bk) & filter) == filter) {
                        method.setAccessible(true);
                        aos.add(method);
                    }
                }

                clazz = clazz.getSuperclass();
            } while (clazz != null);

            Collections.sort(aos, new AccessibleObjectComparator());

            cache.put(name, aos);
        }

        return cache.get(name);
    }

    private static int filter(BusinessKey bk) {
        int filter = 0;

        for (Method method : bk.include()) {
            switch (method) {
            case ALL:
                filter = filter | 7;
                break;
            case EQUALS:
                filter = filter | 1;
                break;
            case HASH_CODE:
                filter = filter | 2;
                break;
            case TO_STRING:
                filter = filter | 4;
                break;
            }
        }

        for (Method method : bk.exclude()) {
            switch (method) {
            case ALL:
                filter -= filter & 7;
                break;
            case EQUALS:
                filter -= filter & 1;
                break;
            case HASH_CODE:
                filter -= filter & 2;
                break;
            case TO_STRING:
                filter -= filter & 4;
                break;
            }
        }

        return filter;
    }

    private static class AccessibleObjectComparator implements Comparator<AccessibleObject> {
        public int compare(AccessibleObject o1, AccessibleObject o2) {
            boolean o1IsField = o1 instanceof Field;
            boolean o2IsField = o2 instanceof Field;

            if (!o1IsField && o2IsField) {
                return 1;
            } else if (o1IsField && !o2IsField) {
                return -1;
            }

            if (o1IsField) {
                return ((Field) o1).getName().compareTo(((Field) o2).getName());
            } else {
                return ((java.lang.reflect.Method) o1).getName().compareTo(((java.lang.reflect.Method) o2).getName());
            }
        }
    }
}

 

Example of usage in a JPA annotated bean:

@Entity
public class User {
    private Long id;
    private String username;
    private byte[] password;
    private Set<Role> roles = new TreeSet<Role>();

    protected User() {}

    public User(String username, String password) {
        this.username = username;
        setPassword(password);
    }

    @BusinessKey(include = Method.TO_STRING)
    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    protected void setId(Long id) {
        this.id = id;
    }

    @BusinessKey
    @Column(nullable = false, unique = true)
    public String getUsername() {
        return username;
    }

    public User setUsername(String username) {
        this.username = username;
        return this;
    }

    @BusinessKey
    @Column(length = 32, nullable = false)
    public byte[] getPassword() {
        return password;
    }

    public void setPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            this.password = md.digest(password.getBytes());
        } catch (NoSuchAlgorithmException e) {}
    }

    @ManyToMany
    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
    
    @Override
    public boolean equals(Object obj) {
        return BeanUtils.equals(this, obj);
    }

    @Override
    public int hashCode() {
        return BeanUtils.hashCode(this);
    }

    @Override
    public String toString() {
        return BeanUtils.toString(this);
    }    
}

If you don't mind to use a superclass in your beans the following superclass can be added as a convenience:

public abstract class Bean {
    @Override
    public boolean equals(Object obj) {
        return BeanUtils.equals(this, obj);
    }

    @Override
    public int hashCode() {
        return BeanUtils.hashCode(this);
    }

    @Override
    public String toString() {
        return BeanUtils.toString(this);
    }
}
分享到:
评论

相关推荐

    JAVA面试题总览[整理].pdf

    5. Spring通过AOP管理事务,基于代理模式实现,关键XML元素如tx:annotation-driven、等。 6. Spring的生命周期管理包括初始化、使用、销毁等阶段,非单例注入使用Prototype scope,循环注入通过依赖注入和集合类...

    避开10大常见坑:DeepSeekAPI集成中的错误处理与调试指南.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    前端分析-2023071100789

    前端分析-2023071100789

    基于kinect的3D人体建模C++完整代码.cpp

    基于kinect的3D人体建模C++完整代码.cpp

    搞机工具箱10.1.0.7z

    搞机工具箱10.1.0.7z

    GRU+informer时间序列预测(Python完整源码和数据)

    GRU+informer时间序列预测(Python完整源码和数据),python代码,pytorch架构,适合各种时间序列直接预测。 适合小白,注释清楚,都能看懂。功能如下: 代码基于数据集划分为训练集测试集。 1.多变量输入,单变量输出/可改多输出 2.多时间步预测,单时间步预测 3.评价指标:R方 RMSE MAE MAPE,对比图 4.数据从excel/csv文件中读取,直接替换即可。 5.结果保存到文本中,可以后续处理。 代码带数据,注释清晰,直接一键运行即可,适合新手小白。

    性价比革命:DeepSeekAPI成本仅为GPT-4的3%的技术揭秘.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    基于ANSYS LSDyna的DEM-SPH-FEM耦合模拟滑坡入水动态行为研究,基于ANSYS LSDyna的DEM-SPH-FEM耦合的滑坡入水模拟分析研究,基于ansys lsdyna的滑坡入水

    基于ANSYS LSDyna的DEM-SPH-FEM耦合模拟滑坡入水动态行为研究,基于ANSYS LSDyna的DEM-SPH-FEM耦合的滑坡入水模拟分析研究,基于ansys lsdyna的滑坡入水模拟dem-sph-fem耦合 ,基于ANSYS LSDyna; 滑坡入水模拟; DEM-SPH-FEM 耦合,基于DEM-SPH-FEM耦合的ANSYS LSDyna滑坡入水模拟

    auto_gptq-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

    auto_gptq-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

    复件 复件 建设工程可行性研究合同[示范文本].doc

    复件 复件 建设工程可行性研究合同[示范文本].doc

    13考试真题最近的t64.txt

    13考试真题最近的t64.txt

    Microsoft Visual C++ 2005 SP1 Redistributable PackageX86

    好用我已经解决报错问题

    嵌入式开发入门:用C语言点亮LED灯的全栈开发指南.pdf

    # 踏入C语言的奇妙编程世界 在编程的广阔宇宙中,C语言宛如一颗璀璨恒星,以其独特魅力与强大功能,始终占据着不可替代的地位。无论你是编程小白,还是有一定基础想进一步提升的开发者,C语言都值得深入探索。 C语言的高效性与可移植性令人瞩目。它能直接操控硬件,执行速度快,是系统软件、嵌入式开发的首选。同时,代码可在不同操作系统和硬件平台间轻松移植,极大节省开发成本。 学习C语言,能让你深入理解计算机底层原理,培养逻辑思维和问题解决能力。掌握C语言后,再学习其他编程语言也会事半功倍。 现在,让我们一起开启C语言学习之旅。这里有丰富教程、实用案例、详细代码解析,助你逐步掌握C语言核心知识和编程技巧。别再犹豫,加入我们,在C语言的海洋中尽情遨游,挖掘无限可能,为未来的编程之路打下坚实基础!

    auto_gptq-0.4.2-cp38-cp38-win_amd64.whl

    auto_gptq-0.4.2-cp38-cp38-win_amd64.whl

    自动立体库设计方案.pptx

    自动立体库设计方案.pptx

    手把手教你用C语言实现贪吃蛇游戏:从算法设计到图形渲染.pdf

    # 踏入C语言的奇妙编程世界 在编程的广阔宇宙中,C语言宛如一颗璀璨恒星,以其独特魅力与强大功能,始终占据着不可替代的地位。无论你是编程小白,还是有一定基础想进一步提升的开发者,C语言都值得深入探索。 C语言的高效性与可移植性令人瞩目。它能直接操控硬件,执行速度快,是系统软件、嵌入式开发的首选。同时,代码可在不同操作系统和硬件平台间轻松移植,极大节省开发成本。 学习C语言,能让你深入理解计算机底层原理,培养逻辑思维和问题解决能力。掌握C语言后,再学习其他编程语言也会事半功倍。 现在,让我们一起开启C语言学习之旅。这里有丰富教程、实用案例、详细代码解析,助你逐步掌握C语言核心知识和编程技巧。别再犹豫,加入我们,在C语言的海洋中尽情遨游,挖掘无限可能,为未来的编程之路打下坚实基础!

    性能对决:DeepSeek-V3与ChatGPTAPI在数学推理场景的基准测试.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    从零到一:手把手教你用Python调用DeepSeekAPI的完整指南.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    为什么你的switch总出bug?90%新手不知道的break语句隐藏规则.pdf

    # 踏入C语言的奇妙编程世界 在编程的广阔宇宙中,C语言宛如一颗璀璨恒星,以其独特魅力与强大功能,始终占据着不可替代的地位。无论你是编程小白,还是有一定基础想进一步提升的开发者,C语言都值得深入探索。 C语言的高效性与可移植性令人瞩目。它能直接操控硬件,执行速度快,是系统软件、嵌入式开发的首选。同时,代码可在不同操作系统和硬件平台间轻松移植,极大节省开发成本。 学习C语言,能让你深入理解计算机底层原理,培养逻辑思维和问题解决能力。掌握C语言后,再学习其他编程语言也会事半功倍。 现在,让我们一起开启C语言学习之旅。这里有丰富教程、实用案例、详细代码解析,助你逐步掌握C语言核心知识和编程技巧。别再犹豫,加入我们,在C语言的海洋中尽情遨游,挖掘无限可能,为未来的编程之路打下坚实基础!

    用deepseek变现实操流程

    用deepseek变现实操流程,小白必看。

Global site tag (gtag.js) - Google Analytics