From 52648727f818cf52502839527c51fd433a333d1d Mon Sep 17 00:00:00 2001 From: huangzj Date: Thu, 30 Apr 2020 18:06:49 +0800 Subject: [PATCH] =?UTF-8?q?=20feat(Java=5FConstractUtil):=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E9=A1=B9=E7=9B=AE=E3=80=81=E5=8D=95=E6=B5=8B=EF=BC=8C?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E7=AC=AC=E4=B8=80=E8=BD=AE=E7=AE=80=E5=8D=95?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 141 ++++++++++++ src/main/java/ContrastUtil.java | 215 ++++++++++++++++++ src/main/java/bean/ContrastObject.java | 81 +++++++ src/main/java/constant/Constant.java | 9 + .../java/exception/NoGetMethodException.java | 24 ++ .../java/exception/NoSetMethodException.java | 24 ++ .../java/exception/TypeMisMatchException.java | 24 ++ src/main/java/handler/CollectionHandler.java | 57 +++++ src/main/java/handler/MapHandler.java | 69 ++++++ src/main/java/handler/OriginHandler.java | 47 ++++ src/main/java/handler/SelfHandler.java | 25 ++ src/main/java/util/CheckUtil.java | 81 +++++++ src/main/java/util/ClassUtil.java | 112 +++++++++ src/main/java/util/CollectionUtil.java | 32 +++ src/main/java/util/MapUtil.java | 34 +++ src/main/java/util/SetUtil.java | 37 +++ src/main/readme.md | 4 + src/main/test/ContractTest.java | 15 ++ src/main/test/SimpleObj.java | 43 ++++ 19 files changed, 1074 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/ContrastUtil.java create mode 100644 src/main/java/bean/ContrastObject.java create mode 100644 src/main/java/constant/Constant.java create mode 100644 src/main/java/exception/NoGetMethodException.java create mode 100644 src/main/java/exception/NoSetMethodException.java create mode 100644 src/main/java/exception/TypeMisMatchException.java create mode 100644 src/main/java/handler/CollectionHandler.java create mode 100644 src/main/java/handler/MapHandler.java create mode 100644 src/main/java/handler/OriginHandler.java create mode 100644 src/main/java/handler/SelfHandler.java create mode 100644 src/main/java/util/CheckUtil.java create mode 100644 src/main/java/util/ClassUtil.java create mode 100644 src/main/java/util/CollectionUtil.java create mode 100644 src/main/java/util/MapUtil.java create mode 100644 src/main/java/util/SetUtil.java create mode 100644 src/main/readme.md create mode 100644 src/main/test/ContractTest.java create mode 100644 src/main/test/SimpleObj.java diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..01f770a --- /dev/null +++ b/pom.xml @@ -0,0 +1,141 @@ + + 4.0.0 + SpringBean + SpringBean + war + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 7 + 7 + + + + + SpringBean Maven Webapp + http://maven.apache.org + + + + + UTF-8 + 1.7 + 7.0 + 4.11 + 3.0 + 2.3 + 1.7.12 + 1.6.2 + 2.3.2 + 4.3.1.RELEASE + 10.2.0.1.0 + + yyyyMMddHHmmss + 1.4.9 + + + + + + org.apache.commons + commons-lang3 + 3.9 + + + + + org.apache.commons + commons-collections4 + 4.4 + + + + + com.google.guava + guava + 28.2-jre + + + + + log4j + log4j + 1.2.17 + + + + + + com.esotericsoftware + reflectasm + 1.11.0 + + + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + org.powermock + powermock-api-mockito + ${powermock.version} + test + + + org.mockito + mockito-core + 1.8.5 + test + + + junit + junit + 4.8.2 + test + + + commons-collections + commons-collections + 3.2.2 + + + org.junit.jupiter + junit-jupiter-api + RELEASE + compile + + + org.powermock + powermock-module-junit4 + 1.4.9 + compile + + + junit + junit + 4.12 + compile + + + junit + junit + 4.12 + compile + + + junit + junit + 4.12 + test + + + + \ No newline at end of file diff --git a/src/main/java/ContrastUtil.java b/src/main/java/ContrastUtil.java new file mode 100644 index 0000000..a9c554b --- /dev/null +++ b/src/main/java/ContrastUtil.java @@ -0,0 +1,215 @@ +import bean.ContrastObject; +import com.esotericsoftware.reflectasm.MethodAccess; +import com.google.common.collect.Lists; +import exception.NoSetMethodException; +import exception.TypeMisMatchException; +import handler.CollectionHandler; +import handler.MapHandler; +import handler.OriginHandler; +import handler.SelfHandler; +import util.CheckUtil; +import util.ClassUtil; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static constant.Constant.GET; +import static constant.Constant.SET; + +/** + * @author 志军 + * @date 2020-1-5 16:00:00 + */ +public class ContrastUtil { + + + //get方法的缓存Map + private static ConcurrentHashMap> getMethodCache = new ConcurrentHashMap>(); + + //set方法的缓存map + private static ConcurrentHashMap> setMethodCache = new ConcurrentHashMap>(); + + /** + * 单对象对比 + * + * @param origin 原始对象 + * @param target 修改后的对象 + * @param 对象类型 + * @return 对比结果 + */ + @SuppressWarnings("unchecked") + public static ContrastObject contrast(T origin, T target) throws IllegalAccessException, InstantiationException { + //空的情况的判断 + if (origin == null || target == null) { + return nullProcessor(origin, target); + } + //提前检查 - 接口或者抽象类 + if (!CheckUtil.commonCheck(origin.getClass())) { + return null; + } + //检查类型是否一致 + if (!CheckUtil.CheckType(origin, target)) { + throw new TypeMisMatchException("类型不匹配"); + } + //先检查get、set方法是否存在. + CheckUtil.checkGetAndSetMethod(origin.getClass()); + + //初始所有参数 + Class tClass = (Class) origin.getClass(); + T originChange = tClass.newInstance(); + T targetChange = tClass.newInstance(); + MethodAccess methodAccess = MethodAccess.get(tClass); + //获取get方法的值进行比较、正常情况下Field都会声明为private,reflectASM对static和private自动跳过,所以用MethodAccess进行处理 + List getList = getGetMethod(methodAccess, tClass); + List setList = getSetMethod(methodAccess, tClass); + + //循环所有的MethodAccess判断是否发生变化 + boolean changed = forContrast(getList, methodAccess, origin, target, setList, originChange, targetChange); + + if (!changed) { + return null; + } + + return setContrastObject(origin, target, originChange, targetChange); + } + + private static ContrastObject nullProcessor(T origin, T target) { + if (origin == null && target == null) { + return null; + } + + if (origin == null) { + return setContrastObject(null, target, null, target); + } + + return setContrastObject(origin, null, origin, null); + } + + private static boolean forContrast(List getList, MethodAccess methodAccess, T origin, T target, List setList, + T originChange, T targetChange) throws InstantiationException, + IllegalAccessException { + + boolean changed = false; + for (String methodName : getList) { + //reflectASM会对基本类型进行装箱(比如说int返回Integer),所以这里要考虑的就是自定义类型怎么比较的问题 + Object originValue = methodAccess.invoke(origin, methodName); + Object targetValue = methodAccess.invoke(target, methodName); + String setName = null; + for (String setMethodName : setList) { + if (setMethodName.substring(3).equals(methodName.substring(3))) { + setName = setMethodName; + break; + } + } + if (setName == null) { + throw new NoSetMethodException(); + } + if (originValue == null && targetValue == null) { + continue; + } + //对比 + 设值 + changed = changed || contrastValue(originValue, targetValue, originChange, targetChange, methodAccess, setName); + } + + return changed; + } + + private static ContrastObject setContrastObject(T origin, T target, T originChange, T targetChange) { + ContrastObject contrastObject = new ContrastObject<>(); + contrastObject.setOrigin(origin); + contrastObject.setTarget(target); + contrastObject.setOriginChange(originChange); + contrastObject.setTargetChange(targetChange); + return contrastObject; + } + + /** + * @param originValue get方法拿到的原始的值 + * @param targetValue get方法拿到的变化的值 + * @param originChange 新创建的原始变化对象 + * @param targetChange 新创建的改变变化对象 + * @param methodAccess reflectASM类 + * @param setName set方法名 + * @throws IllegalAccessException 异常 + * @throws InstantiationException 异常 + */ + private static boolean contrastValue(Object originValue, Object targetValue, Object originChange, Object targetChange, + MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException { + //处理Collection + if (originValue instanceof Collection || targetValue instanceof Collection) { + return CollectionHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName); + } + + //Map的处理 + if (originValue instanceof Map || targetValue instanceof Map) { + return MapHandler.putValue(originChange, targetChange, originValue, targetValue, methodAccess, setName); + } + + //非自定义类的处理 + Boolean result = OriginHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName); + if (null != result) { + return result; + } + + //自定义类型的处理 + return SelfHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName); + } + + + /** + * 获取Get方法集合 + * + * @param methodAccess MethodAccess + * @param tClass 类.class + * @param T + * @return 方法名 + */ + private static List getSetMethod(MethodAccess methodAccess, Class tClass) { + if (setMethodCache.get(tClass.getName()) != null) { + return setMethodCache.get(tClass.getName()); + } + List methodNameList = Lists.newArrayList(); + List methods = ClassUtil.getAllMethodWithSuper(tClass); + String[] methodNames = methodAccess.getMethodNames(); + + return buildMethodList(SET, methodNames, methods, methodNameList, setMethodCache, tClass); + } + + private static List buildMethodList(String type, String[] methodNames, List methods, List methodNameList, + ConcurrentHashMap> methodCache, Class tClass) { + for (String methodName : methodNames) { + if (methodName.startsWith(type)) { + for (Method method : methods) { + if (method.getName().equals(methodName)) { + methodNameList.add(methodName); + break; + } + } + } + } + methodCache.put(tClass.getName(), methodNameList); + return methodNameList; + } + + /** + * 获取Set方法集合 + * + * @param methodAccess MethodAccess + * @param tClass 类.class + * @param T + * @return 方法名 + */ + private static List getGetMethod(MethodAccess methodAccess, Class tClass) { + if (getMethodCache.get(tClass.getName()) != null) { + return getMethodCache.get(tClass.getName()); + } + List methodNameList = Lists.newArrayList(); + String[] methodNames = methodAccess.getMethodNames(); + List methods = ClassUtil.getAllMethodWithSuper(tClass); + + return buildMethodList(GET, methodNames, methods, methodNameList, getMethodCache, tClass); + } +} diff --git a/src/main/java/bean/ContrastObject.java b/src/main/java/bean/ContrastObject.java new file mode 100644 index 0000000..c2423e9 --- /dev/null +++ b/src/main/java/bean/ContrastObject.java @@ -0,0 +1,81 @@ +package bean; + +import java.util.Objects; + +/** + * 返回的对比对象的包装 + * + */ +public class ContrastObject { + + + /** + * 原始的java对象 + */ + private T origin; + + /** + * 修改后的java对象 + */ + private T target; + + /** + * 原始的java对象修改的部分 + */ + private T originChange; + + + /** + * 修改后的java对象修改的部分 + */ + private T targetChange; + + + public T getOrigin() { + return origin; + } + + public void setOrigin(T origin) { + this.origin = origin; + } + + public T getTarget() { + return target; + } + + public void setTarget(T target) { + this.target = target; + } + + public T getOriginChange() { + return originChange; + } + + public void setOriginChange(T originChange) { + this.originChange = originChange; + } + + public T getTargetChange() { + return targetChange; + } + + public void setTargetChange(T targetChange) { + this.targetChange = targetChange; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ContrastObject that = (ContrastObject) o; + return getOrigin().equals(that.getOrigin()) && + getTarget().equals(that.getTarget()) && + getOriginChange().equals(that.getOriginChange()) && + getTargetChange().equals(that.getTargetChange()); + } + + @Override + public int hashCode() { + return Objects.hash(getOrigin(), getTarget(), getOriginChange(), getTargetChange()); + } +} diff --git a/src/main/java/constant/Constant.java b/src/main/java/constant/Constant.java new file mode 100644 index 0000000..9b57870 --- /dev/null +++ b/src/main/java/constant/Constant.java @@ -0,0 +1,9 @@ +package constant; + +public class Constant { + + + public static final String GET = "get"; + public static final String SET = "set"; + public static final String WELL_NUMBER = "#"; +} diff --git a/src/main/java/exception/NoGetMethodException.java b/src/main/java/exception/NoGetMethodException.java new file mode 100644 index 0000000..47c33ac --- /dev/null +++ b/src/main/java/exception/NoGetMethodException.java @@ -0,0 +1,24 @@ +package exception; + +public class NoGetMethodException extends RuntimeException{ + + public NoGetMethodException() { + super(); + } + + public NoGetMethodException(String message) { + super(message); + } + + public NoGetMethodException(String message, Throwable cause) { + super(message, cause); + } + + public NoGetMethodException(Throwable cause) { + super(cause); + } + + protected NoGetMethodException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/exception/NoSetMethodException.java b/src/main/java/exception/NoSetMethodException.java new file mode 100644 index 0000000..1ea3ffe --- /dev/null +++ b/src/main/java/exception/NoSetMethodException.java @@ -0,0 +1,24 @@ +package exception; + +public class NoSetMethodException extends RuntimeException { + + public NoSetMethodException() { + super(); + } + + public NoSetMethodException(String message) { + super(message); + } + + public NoSetMethodException(String message, Throwable cause) { + super(message, cause); + } + + public NoSetMethodException(Throwable cause) { + super(cause); + } + + protected NoSetMethodException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/exception/TypeMisMatchException.java b/src/main/java/exception/TypeMisMatchException.java new file mode 100644 index 0000000..174245a --- /dev/null +++ b/src/main/java/exception/TypeMisMatchException.java @@ -0,0 +1,24 @@ +package exception; + +public class TypeMisMatchException extends RuntimeException { + + public TypeMisMatchException() { + super(); + } + + public TypeMisMatchException(String message) { + super(message); + } + + public TypeMisMatchException(String message, Throwable cause) { + super(message, cause); + } + + public TypeMisMatchException(Throwable cause) { + super(cause); + } + + protected TypeMisMatchException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/handler/CollectionHandler.java b/src/main/java/handler/CollectionHandler.java new file mode 100644 index 0000000..4e1acc4 --- /dev/null +++ b/src/main/java/handler/CollectionHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020. + * made by 志军 + */ + +package handler; + +import com.esotericsoftware.reflectasm.MethodAccess; +import org.apache.commons.collections4.CollectionUtils; +import util.CollectionUtil; + +import java.util.Collection; + +/** + * 处理Collection类型的对比,必须重写equals和hashCode方法 + * + * @author 志军 + */ +public class CollectionHandler { + + /** + * 对比组合Collection差异的部分 + * + * @param originChange 原始的变化部分的对象 + * @param targetChange 修改后变化部分的对象 + * @param originValue 原始的对象 + * @param targetValue 修改后的对象 + * @param methodAccess MethodAccess + * @param setName set方法名 + * @return 是否变化 + * @throws IllegalAccessException 异常 + * @throws InstantiationException 异常 + */ + public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue, + MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException { + + boolean changed; + Class returnValue = originValue.getClass(); + + //判断Collection是否相等 + if (CollectionUtils.isEqualCollection((Collection) originValue, (Collection) targetValue)) { + return false; + } + + Object originCollection = CollectionUtil.buildDiffCollection(originValue, targetValue, returnValue); + Object changeCollection = CollectionUtil.buildDiffCollection(targetValue, originValue, returnValue); + + changed = CollectionUtils.isNotEmpty((Collection) originCollection) || CollectionUtils.isNotEmpty((Collection) changeCollection); + + if (changed) { + methodAccess.invoke(originChange, setName, originCollection); + methodAccess.invoke(targetChange, setName, changeCollection); + } + + return changed; + } +} diff --git a/src/main/java/handler/MapHandler.java b/src/main/java/handler/MapHandler.java new file mode 100644 index 0000000..67a2241 --- /dev/null +++ b/src/main/java/handler/MapHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020. + * made by 志军 + */ + +package handler; + +import com.esotericsoftware.reflectasm.MethodAccess; +import org.apache.commons.collections.CollectionUtils; +import util.MapUtil; +import util.SetUtil; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 处理Map对应的对比 + * + * @author 志军 + */ +public class MapHandler { + + @SuppressWarnings("unchecked") + public static boolean putValue(Object originChange, Object targetChange, Object originValue, Object targetValue, + MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException { + //参数前置 + boolean changed = false; + Set originEntry = ((Map) originValue).entrySet(); + Set targetEntry = ((Map) targetValue).entrySet(); + Map originMap = (Map) originValue.getClass().newInstance(); + Map targetMap = (Map) targetValue.getClass().newInstance(); + + //处理key一样的value比较. + for (Map.Entry entry : originEntry) { + Object key = entry.getKey(); + for (Map.Entry tEntry : targetEntry) { + if (tEntry.getKey().equals(key)) { + //每一个key都进行比较,如果key相等则比较对应的value,这个value需要重写hashcode和equals方法 + changed = changed || MapHandler.putValue(originChange, targetChange, originMap, targetMap, key); + break; + } + } + } + + //得到不一致的key的集合. + List originList = SetUtil.findUnLikeValue(originEntry, targetEntry); + List changeList = SetUtil.findUnLikeValue(originEntry, targetEntry); + //计算changed的值 + changed = changed || !CollectionUtils.isEmpty(originList) || CollectionUtils.isEmpty(changeList); + //把不一致的值设置会新的Map中 + MapUtil.putIfNotEmpty(originMap, originList); + MapUtil.putIfNotEmpty(targetMap, changeList); + //对对象进行设值 + methodAccess.invoke(originChange, setName, originValue); + methodAccess.invoke(targetChange, setName, targetValue); + return changed; + } + + private static boolean putValue(Object originChange, Object targetChange, Map originMap, + Map targetMap, Object key) { + if (originChange.equals(targetChange)) { + return false; + } + originMap.put(key, originChange); + targetMap.put(key, targetChange); + return true; + } +} diff --git a/src/main/java/handler/OriginHandler.java b/src/main/java/handler/OriginHandler.java new file mode 100644 index 0000000..5654c49 --- /dev/null +++ b/src/main/java/handler/OriginHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020. + * made by 志军 + */ + +package handler; + +import com.esotericsoftware.reflectasm.MethodAccess; + +/** + * 处理除Iterable和Map之外的原始类型 + * + * @author 志军 + */ +public class OriginHandler { + + + public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue, + MethodAccess methodAccess, String setName) { + Class returnValue = originValue == null ? targetValue.getClass() : originValue.getClass(); + + try { + if (returnValue.getClassLoader() == null) { + return contractValue(originChange, targetChange, originValue, targetValue, methodAccess, setName); + } else { + //用来判断是否进行了比较 + return null; + } + } catch (NullPointerException ex) { + //这边是处理Object类型 + return contractValue(originChange, targetChange, originValue, targetValue, methodAccess, setName); + } + } + + + private static boolean contractValue(Object originChange, Object targetChange, Object originValue, Object targetValue, + MethodAccess methodAccess, String setName) { + boolean result = (originValue == null ? targetValue.equals(originChange) : originValue.equals(targetValue)); + if (originValue == targetValue || result) { + return false; + } else { + methodAccess.invoke(originChange, setName, originValue); + methodAccess.invoke(targetChange, setName, targetValue); + return true; + } + } +} diff --git a/src/main/java/handler/SelfHandler.java b/src/main/java/handler/SelfHandler.java new file mode 100644 index 0000000..b1daa37 --- /dev/null +++ b/src/main/java/handler/SelfHandler.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020. + * made by 志军 + */ + +package handler; + +import com.esotericsoftware.reflectasm.MethodAccess; + +/** + * 处理自定义的类,必须重写hashCode和equals方法,不然会出现对比偏差.

+ * @author 志军 + */ +public class SelfHandler { + public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue, + MethodAccess methodAccess, String setName) { + if (!originChange.equals(targetChange)) { + methodAccess.invoke(originChange, setName, originValue); + methodAccess.invoke(targetChange, setName, targetValue); + return true; + } + + return false; + } +} diff --git a/src/main/java/util/CheckUtil.java b/src/main/java/util/CheckUtil.java new file mode 100644 index 0000000..cf8480d --- /dev/null +++ b/src/main/java/util/CheckUtil.java @@ -0,0 +1,81 @@ +package util; + +import com.google.common.collect.Lists; +import exception.NoGetMethodException; +import exception.NoSetMethodException; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.List; +import java.util.Vector; + +import static constant.Constant.GET; +import static constant.Constant.SET; + +/** + * @author 志军 + * @date 2020-1-5 16:00:00 + */ +public class CheckUtil { + + private static Vector vector = new Vector<>(); + + + /** + * 提前检查是否包含了get、set方法 + * TODO 没有考虑is方法 + * + * @param zClass Class类 + */ + public static void checkGetAndSetMethod(Class zClass) { + if (vector.contains(zClass.getName())) { + return; + } + List fieldList = ClassUtil.getAllFieldWithSuper(zClass); + List methodList = ClassUtil.getAllMethodWithSuper(zClass); + List methodNameList = getMethodNameList(methodList); + for (Field field : fieldList) { + String fieldName = field.getName(); + final String s = String.valueOf(fieldName.charAt(0)).toUpperCase(); + String setMethodName = SET + s + fieldName.substring(1); + String getMethodName = GET + s + fieldName.substring(1); + if (!methodNameList.contains(getMethodName)) { + throw new NoGetMethodException(); + } + //这边加上了set的参数校验 + if (!methodNameList.contains(setMethodName) || !setMethodParamCheck(field, setMethodName, methodList)) { + throw new NoSetMethodException(); + } + } + vector.add(zClass.getName()); + } + + private static boolean setMethodParamCheck(Field field, String setMethodName, List methodList) { + for (Method method : methodList) { + if (method.getName().equals(setMethodName) && method.getParameterTypes()[0] == field.getType()) { + return true; + } + } + return false; + } + + private static List getMethodNameList(List methodList) { + List methodNameList = Lists.newArrayList(); + for (Method method : methodList) { + methodNameList.add(method.getName()); + } + return methodNameList; + } + + /** + * 检查是否为抽象类或者接口 + */ + public static boolean commonCheck(Class aClass) { + return !Modifier.isAbstract(aClass.getModifiers()) && !Modifier.isInterface(aClass.getModifiers()); + } + + public static boolean CheckType(T origin, T target) { + return origin.getClass() == target.getClass(); + } +} diff --git a/src/main/java/util/ClassUtil.java b/src/main/java/util/ClassUtil.java new file mode 100644 index 0000000..fe5c271 --- /dev/null +++ b/src/main/java/util/ClassUtil.java @@ -0,0 +1,112 @@ +package util; + +import com.esotericsoftware.reflectasm.MethodAccess; +import com.google.common.collect.Lists; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import static constant.Constant.*; + +/** + * @author 志军 + * @date 2020-1-5 16:00:00 + * 其实你不用担心类似 ##fieldCache.get(zClass.getName())这样的代码在一个方法里面写了很多遍会处理多次 + *

可以了解一下##方法内联 + */ +public class ClassUtil { + + /** + * 类名#方法 - 方法索引 缓存 + */ + private static ConcurrentHashMap cache = new ConcurrentHashMap(); + + /** + * 类 - Field数组 缓存 + */ + private static ConcurrentHashMap> fieldCache = new ConcurrentHashMap>(); + + /** + * 类 - method数组 缓存 + */ + private static ConcurrentHashMap> methodCache = new ConcurrentHashMap>(); + + + /** + * 获取get方法 + * + * @param fieldName 类属性名称 + * @param zClass 类.class + * @return GetMethod + */ + public static Integer getGetMethod(String fieldName, Class zClass) { + //获取下标的方式非常方便,本质上,如果使用getDeclareMethod方法,还需要考虑继承的问题 + MethodAccess access = MethodAccess.get(zClass); + String getMethodName = GET + String.valueOf(fieldName.charAt(0)).toUpperCase() + fieldName.substring(1); + String keyName = zClass.getName() + WELL_NUMBER + getMethodName; + if (cache.get(keyName) == null) { + cache.put(keyName, access.getIndex(getMethodName)); + return access.getIndex(getMethodName); + } + + return cache.get(keyName); + } + + + /** + * 获取set方法 + * + * @param fieldName 类属性名称 + * @param zClass 类.class + * @return SetMethod + */ + public static Integer getSetMethod(String fieldName, Class zClass) { + String setMethodName = SET + String.valueOf(fieldName.charAt(0)).toUpperCase() + fieldName.substring(1); + String keyName = zClass.getName() + WELL_NUMBER + setMethodName; + MethodAccess access = MethodAccess.get(zClass); + if (cache.get(keyName) != null) { + return cache.get(keyName); + } + cache.put(keyName, access.getIndex(setMethodName)); + return access.getIndex(setMethodName); + } + + + static List getAllFieldWithSuper(Class zClass) { + if (fieldCache.get(zClass.getName()) != null) { + return fieldCache.get(zClass.getName()); + } + + + List fieldList = Lists.newArrayList(); + Class tempClass = zClass; + while (tempClass != null) { + fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields())); + tempClass = tempClass.getSuperclass(); + } + + fieldCache.put(zClass.getName(), fieldList); + return fieldList; + } + + + public static List getAllMethodWithSuper(Class zClass) { + if (methodCache.get(zClass.getName()) != null) { + return methodCache.get(zClass.getName()); + } + + Class tempClass = zClass; + List methodList = Lists.newArrayList(); + while (tempClass != null) { + methodList.addAll(Arrays.asList(tempClass.getDeclaredMethods())); + tempClass = tempClass.getSuperclass(); + } + + methodCache.put(zClass.getName(), methodList); + return methodList; + } + +} diff --git a/src/main/java/util/CollectionUtil.java b/src/main/java/util/CollectionUtil.java new file mode 100644 index 0000000..9b5f223 --- /dev/null +++ b/src/main/java/util/CollectionUtil.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020. + * made by 志军 + */ + +package util; + +import java.util.Collection; + +/** + * Collection类型的处理工具 + * @author 志军 + */ +public class CollectionUtil { + + + @SuppressWarnings("unchecked") + public static Collection buildDiffCollection(Object originValue, Object targetValue, Class returnValue) throws IllegalAccessException, + InstantiationException { + + Object collection = returnValue.newInstance(); + + for (Object value : (Collection) originValue) { + if (((Collection) targetValue).contains(value)) { + continue; + } + ((Collection) collection).add(value); + } + + return (Collection) collection; + } +} diff --git a/src/main/java/util/MapUtil.java b/src/main/java/util/MapUtil.java new file mode 100644 index 0000000..c322809 --- /dev/null +++ b/src/main/java/util/MapUtil.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020. + * made by 志军 + */ + +package util; + +import org.apache.commons.collections.CollectionUtils; + +import java.util.List; +import java.util.Map; + +/** + * Map工具类 + * @author 志军 + */ +public class MapUtil { + + /** + * 把List中Entry对应的key、value设置到新的Map中 + * @param map 新的Map + * @param changeList 变化的List + */ + public static void putIfNotEmpty(Map map, List changeList) { + if (CollectionUtils.isEmpty(changeList)) { + return; + } + + + for (Map.Entry entry : changeList) { + map.put(entry.getKey(), entry.getValue()); + } + } +} diff --git a/src/main/java/util/SetUtil.java b/src/main/java/util/SetUtil.java new file mode 100644 index 0000000..61dc413 --- /dev/null +++ b/src/main/java/util/SetUtil.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020. + * made by 志军 + */ + +package util; + +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.Set; + +/** + * Set工具类 + * @author 志军 + */ +public class SetUtil { + + /** + * + * @param origin 原始Set + * @param target 目标Set + * @param Set类型 + * @return 返回origin中不被包含在target的元素集合 + */ + public static List findUnLikeValue(Set origin, Set target) { + List unLikeList = Lists.newArrayList(); + for (T t : origin) { + if (target.contains(t)) { + continue; + } + unLikeList.add(t); + } + + return unLikeList; + } +} diff --git a/src/main/readme.md b/src/main/readme.md new file mode 100644 index 0000000..70a57ac --- /dev/null +++ b/src/main/readme.md @@ -0,0 +1,4 @@ +# 工具说明 + +# 更新日志 +2020/4/30: 创建项目、单测,进行第一轮简单的测试 \ No newline at end of file diff --git a/src/main/test/ContractTest.java b/src/main/test/ContractTest.java new file mode 100644 index 0000000..6304dd1 --- /dev/null +++ b/src/main/test/ContractTest.java @@ -0,0 +1,15 @@ +import bean.ContrastObject; + +public class ContractTest { + + + public static void main(String[] args) throws InstantiationException, IllegalAccessException { + SimpleObj s1 = new SimpleObj(); + s1.setM((float) 2.2); + s1.setY("55555"); + ContrastObject sim = ContrastUtil.contrast(new SimpleObj(), s1); + + + System.out.print(sim.getTargetChange().m + " " + sim.getTargetChange().x + " " + sim.getTargetChange().y); + } +} diff --git a/src/main/test/SimpleObj.java b/src/main/test/SimpleObj.java new file mode 100644 index 0000000..87613e9 --- /dev/null +++ b/src/main/test/SimpleObj.java @@ -0,0 +1,43 @@ +import java.util.Date; + +public class SimpleObj { + int x; + + String y; + + float m; + + Date date; + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public String getY() { + return y; + } + + public void setY(String y) { + this.y = y; + } + + public float getM() { + return m; + } + + public void setM(float m) { + this.m = m; + } +}