抑郁症健康,内容丰富有趣,生活中的好帮手!
抑郁症健康 > java对象对比工具 自定义注解对象属性对比 支持递归调用 无三方包纯原生工具 简单

java对象对比工具 自定义注解对象属性对比 支持递归调用 无三方包纯原生工具 简单

时间:2018-09-16 12:46:11

相关推荐

文章目录

场景字段对比 自定义注解字典对比枚举类测试对象接口性别实现类对象对比工具类单元对比测试一:简单对象对比单元对比测试二:复杂对象对比使用了字典对比效果亮点细节可扩展性

场景

在很多情况下,尤其是单表的版本控制的时候,需要记录后台人员的操作日志,通常是用到两个java对象去坐对比,告诉后台人员,改了哪些字段,就好比[名字:李四->张三],名字由原来的李四变成了张三。那么不废话了,直接亮出我反射结合注解写的对象对比工具。

字段对比 自定义注解

import java.lang.annotation.*;/*** 字段比较注解* @author liaoqian* @since /8/11*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface FiledCompara {String value() ;FiledComparaTypeEnum type() default FiledComparaTypeEnum.DEFAULT;}

字典对比枚举类

import lombok.Getter;@Getterpublic enum FiledComparaTypeEnum {DEFAULT("default", null),SEX("sex", new SexFiledComparaType());private String type;private IFiledComparaType filedComparaType;FiledComparaTypeEnum(String type, IFiledComparaType filedComparaType) {this.type = type;this.filedComparaType = filedComparaType;}public boolean isDefault() {return DEFAULT.type.equals(type);}}

测试对象

@Data@AllArgsConstructor@NoArgsConstructorpublic class User {@FiledCompara("名字")private String name;@FiledCompara("密码")private String password;@FiledCompara("儿子")private User son;@FiledCompara(value = "性别",type = FiledComparaTypeEnum.SEX)private Integer sex;public User(String name, String password) {this.name = name;this.password = password;}public User(String name, Integer sex) {this.name = name;this.sex= sex;}}

接口

import java.util.Map;public interface IFiledComparaType {Map<String,String> map();}

性别实现类

import java.util.HashMap;import java.util.Map;/*** @author liaoqian* @since /8/24*/public class SexFiledComparaType implements IFiledComparaType {@Overridepublic Map<String, String> map() {Map<String, String> ans = new HashMap<>();ans.put("1","男");ans.put("0","女");return ans;}}

对象对比工具类

package com.example.springboottest.util;import com.example.springboottest.annotation.FiledCompara;import com.example.springboottest.enums.FiledComparaTypeEnum;import com.example.springboottest.enums.IFiledComparaType;import java.lang.reflect.Field;import java.util.*;/*** 对象比较工具** @author liaoqian* @since /8/11*/public class ObjectComparaUtil {private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap(8);static {primitiveWrapperTypeMap.put(Boolean.class, Boolean.TYPE);primitiveWrapperTypeMap.put(Byte.class, Byte.TYPE);primitiveWrapperTypeMap.put(Character.class, Character.TYPE);primitiveWrapperTypeMap.put(Double.class, Double.TYPE);primitiveWrapperTypeMap.put(Float.class, Float.TYPE);primitiveWrapperTypeMap.put(Integer.class, Integer.TYPE);primitiveWrapperTypeMap.put(Long.class, Long.TYPE);primitiveWrapperTypeMap.put(Short.class, Short.TYPE);}public static Map<String, String> comparaObj(Object target, Object source) {return comparaObj(target, source, null);}private static Map<String, String> comparaObj(Object target, Object source, Map<String, String> map) {Map<String, String> ans = new LinkedHashMap<>(1 << 6);if (source == null || target == null) {throw new RuntimeException("比较的两个对象不能为空");}Class clazz = source.getClass();if (!clazz.equals(target.getClass())) {throw new RuntimeException("比较的两个对象类型不同");}Field[] fields = clazz.getDeclaredFields();String format = " %s:%s->%s ";for (Field field : fields) {FiledCompara filedCompara = field.getAnnotation(FiledCompara.class);if (filedCompara != null) {field.setAccessible(true);Object sourceFieldValue = null;Object targetFieldValue = null;try {sourceFieldValue = field.get(source);targetFieldValue = field.get(target);} catch (Exception e) {}boolean notNull = sourceFieldValue != null && targetFieldValue != null;boolean primitive = isPrimitiveType(field.getType());if (!notNull) {continue;}String entityKey = field.getName();String value = filedCompara.value();FiledComparaTypeEnum type = filedCompara.type();value = value == null || "".equals(value.trim()) ? entityKey : value;if (primitive) {String sourceFieldValueStr = sourceFieldValue.toString();String targetFieldValueStr = targetFieldValue.toString();if (!sourceFieldValueStr.equals(targetFieldValueStr)) {Map<String, String> valueDictMap = getValueDictMap(type);String entityValue = String.format(format, value, valueDictMap.getOrDefault(sourceFieldValueStr,sourceFieldValueStr),valueDictMap.getOrDefault(targetFieldValueStr,targetFieldValueStr));ans.put(entityKey, entityValue);}} else {Map<String, String> sonMap = comparaObj(sourceFieldValue, targetFieldValue, ans);if (!sonMap.isEmpty()) {for (Map.Entry<String, String> entry : sonMap.entrySet()) {ans.put(entityKey + "." + entry.getKey(), value + "." + entry.getValue());}}}}}return ans;}private static Map<String, String> getValueDictMap(FiledComparaTypeEnum filedComparaType) {if (filedComparaType.isDefault()) {return new HashMap<>();}IFiledComparaType filedComparaTypeImpl = filedComparaType.getFiledComparaType();return filedComparaTypeImpl.map();}private static boolean isPrimitiveType(Class clazz) {boolean ans = false;if (clazz.isPrimitive()) {return true;}boolean containsKey = primitiveWrapperTypeMap.containsKey(clazz);if (containsKey) {return true;}String simpleName = clazz.getSimpleName();switch (simpleName) {case "String":ans = true;break;default:break;}return ans;}}

单元对比测试一:简单对象对比

测试代码

@Testpublic void tt() {User sourceUser = new User("李四", "qwertyuiop");User targetUser = new User("张三", "qwertyui0p");Map<String, String> map = paraObj(sourceUser, targetUser);for (Map.Entry<String, String> entry : map.entrySet()) {System.out.println(entry.getKey()+" --- "+entry.getValue());}}

测试结果

name --- 名字:李四->张三 password --- 密码:qwertyuiop->qwertyui0p

单元对比测试二:复杂对象对比

测试代码

@Testpublic void tt() {User sourceUser = new User("张三", "qwertyuiop",new User("张三的儿子","123456",new User("张三的孙子女","666666")));User targetUser = new User("张三", "qwertyui0p",new User("张三的儿子","12345678",new User("张三的孙子男","666666")));Map<String, String> map = paraObj(sourceUser, targetUser);for (Map.Entry<String, String> entry : map.entrySet()) {System.out.println(entry.getKey()+" --- "+entry.getValue());}}

测试结果

password --- 密码:qwertyuiop->qwertyui0p son.password --- 儿子.密码:123456->12345678 son.son.name --- 儿子.儿子.名字:张三的孙子女->张三的孙子男

使用了字典对比效果

测试代码

@Testpublic void tt() {User targetUser = new User("王小丫",0);User sourceUser = new User("张三",1);Map<String, String> map = paraObj(sourceUser, targetUser);for (Map.Entry<String, String> entry : map.entrySet()) {System.out.println(entry.getKey()+" --- "+entry.getValue());}}

测试结果

name --- 名字:王小丫->张三 sex --- 性别:女->男

亮点细节

纯原生代码,无三方依赖支持复杂对象的对比效率高,逻辑清晰可扩展性高这里要配合你对象版本的管理,比如同一个user对象v4和v3的对比要保存在表中

可扩展性

对象字段字典上对比有缺陷的地方

java对象对比工具 自定义注解对象属性对比 支持递归调用 无三方包纯原生工具 简单实用 反射来对比对象的差异 增强字典说明

如果觉得《java对象对比工具 自定义注解对象属性对比 支持递归调用 无三方包纯原生工具 简单》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。