feat(Java_ConstractUtil):创建项目、单测,进行第一轮简单的测试
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>SpringBean</groupId>
|
||||
<artifactId>SpringBean</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>7</source>
|
||||
<target>7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<name>SpringBean Maven Webapp</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
|
||||
<!--配置依赖的属性-->
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.jdk.version>1.7</project.build.jdk.version>
|
||||
<javax.version>7.0</javax.version>
|
||||
<junit.version>4.11</junit.version>
|
||||
<javax.servlet.version>3.0</javax.servlet.version>
|
||||
<log4j.version>2.3</log4j.version>
|
||||
<slf4j.version>1.7.12</slf4j.version>
|
||||
<org.aspectj.version>1.6.2</org.aspectj.version>
|
||||
<net.sf.ehcache.version>2.3.2</net.sf.ehcache.version>
|
||||
<org.springframework.version>4.3.1.RELEASE</org.springframework.version>
|
||||
<oracle.jdbc.version>10.2.0.1.0</oracle.jdbc.version>
|
||||
<!--<hibernateVersion>4.wwwwwww.0</hibernateVersion>-->
|
||||
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
|
||||
<powermock.version>1.4.9</powermock.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>28.2-jre</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!--引入reflectASM包-->
|
||||
<dependency>
|
||||
<groupId>com.esotericsoftware</groupId>
|
||||
<artifactId>reflectasm</artifactId>
|
||||
<version>1.11.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.8.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>1.4.9</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -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<String, List<String>> getMethodCache = new ConcurrentHashMap<String, List<String>>();
|
||||
|
||||
//set方法的缓存map
|
||||
private static ConcurrentHashMap<String, List<String>> setMethodCache = new ConcurrentHashMap<String, List<String>>();
|
||||
|
||||
/**
|
||||
* 单对象对比
|
||||
*
|
||||
* @param origin 原始对象
|
||||
* @param target 修改后的对象
|
||||
* @param <T> 对象类型
|
||||
* @return 对比结果
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> ContrastObject<T> 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<T> tClass = (Class<T>) origin.getClass();
|
||||
T originChange = tClass.newInstance();
|
||||
T targetChange = tClass.newInstance();
|
||||
MethodAccess methodAccess = MethodAccess.get(tClass);
|
||||
//获取get方法的值进行比较、正常情况下Field都会声明为private,reflectASM对static和private自动跳过,所以用MethodAccess进行处理
|
||||
List<String> getList = getGetMethod(methodAccess, tClass);
|
||||
List<String> 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 <T> ContrastObject<T> 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 <T> boolean forContrast(List<String> getList, MethodAccess methodAccess, T origin, T target, List<String> 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 <T> ContrastObject<T> setContrastObject(T origin, T target, T originChange, T targetChange) {
|
||||
ContrastObject<T> 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> T
|
||||
* @return 方法名
|
||||
*/
|
||||
private static <T> List<String> getSetMethod(MethodAccess methodAccess, Class<T> tClass) {
|
||||
if (setMethodCache.get(tClass.getName()) != null) {
|
||||
return setMethodCache.get(tClass.getName());
|
||||
}
|
||||
List<String> methodNameList = Lists.newArrayList();
|
||||
List<Method> methods = ClassUtil.getAllMethodWithSuper(tClass);
|
||||
String[] methodNames = methodAccess.getMethodNames();
|
||||
|
||||
return buildMethodList(SET, methodNames, methods, methodNameList, setMethodCache, tClass);
|
||||
}
|
||||
|
||||
private static <T> List<String> buildMethodList(String type, String[] methodNames, List<Method> methods, List<String> methodNameList,
|
||||
ConcurrentHashMap<String, List<String>> methodCache, Class<T> 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> T
|
||||
* @return 方法名
|
||||
*/
|
||||
private static <T> List<String> getGetMethod(MethodAccess methodAccess, Class<T> tClass) {
|
||||
if (getMethodCache.get(tClass.getName()) != null) {
|
||||
return getMethodCache.get(tClass.getName());
|
||||
}
|
||||
List<String> methodNameList = Lists.newArrayList();
|
||||
String[] methodNames = methodAccess.getMethodNames();
|
||||
List<Method> methods = ClassUtil.getAllMethodWithSuper(tClass);
|
||||
|
||||
return buildMethodList(GET, methodNames, methods, methodNameList, getMethodCache, tClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package bean;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 返回的对比对象的包装
|
||||
*
|
||||
*/
|
||||
public class ContrastObject<T> {
|
||||
|
||||
|
||||
/**
|
||||
* 原始的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());
|
||||
}
|
||||
}
|
||||
@@ -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 = "#";
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Map.Entry> originEntry = ((Map) originValue).entrySet();
|
||||
Set<Map.Entry> 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<Map.Entry> originList = SetUtil.findUnLikeValue(originEntry, targetEntry);
|
||||
List<Map.Entry> 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<Object, Object> originMap,
|
||||
Map<Object, Object> targetMap, Object key) {
|
||||
if (originChange.equals(targetChange)) {
|
||||
return false;
|
||||
}
|
||||
originMap.put(key, originChange);
|
||||
targetMap.put(key, targetChange);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* made by 志军
|
||||
*/
|
||||
|
||||
package handler;
|
||||
|
||||
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||
|
||||
/**
|
||||
* 处理自定义的类,必须重写hashCode和equals方法,不然会出现对比偏差.<p>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -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<String> vector = new Vector<>();
|
||||
|
||||
|
||||
/**
|
||||
* 提前检查是否包含了get、set方法
|
||||
* TODO 没有考虑is方法
|
||||
*
|
||||
* @param zClass Class类
|
||||
*/
|
||||
public static void checkGetAndSetMethod(Class zClass) {
|
||||
if (vector.contains(zClass.getName())) {
|
||||
return;
|
||||
}
|
||||
List<Field> fieldList = ClassUtil.getAllFieldWithSuper(zClass);
|
||||
List<Method> methodList = ClassUtil.getAllMethodWithSuper(zClass);
|
||||
List<String> 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<Method> methodList) {
|
||||
for (Method method : methodList) {
|
||||
if (method.getName().equals(setMethodName) && method.getParameterTypes()[0] == field.getType()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<String> getMethodNameList(List<Method> methodList) {
|
||||
List<String> 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 <T> boolean CheckType(T origin, T target) {
|
||||
return origin.getClass() == target.getClass();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
* 其实你不用担心类似 ##<code>fieldCache.get(zClass.getName())</code>这样的代码在一个方法里面写了很多遍会处理多次
|
||||
* <p>可以了解一下##方法内联
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* 类名#方法 - 方法索引 缓存
|
||||
*/
|
||||
private static ConcurrentHashMap<String, Integer> cache = new ConcurrentHashMap<String, Integer>();
|
||||
|
||||
/**
|
||||
* 类 - Field数组 缓存
|
||||
*/
|
||||
private static ConcurrentHashMap<String, List<Field>> fieldCache = new ConcurrentHashMap<String, List<Field>>();
|
||||
|
||||
/**
|
||||
* 类 - method数组 缓存
|
||||
*/
|
||||
private static ConcurrentHashMap<String, List<Method>> methodCache = new ConcurrentHashMap<String, List<Method>>();
|
||||
|
||||
|
||||
/**
|
||||
* 获取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<Field> getAllFieldWithSuper(Class zClass) {
|
||||
if (fieldCache.get(zClass.getName()) != null) {
|
||||
return fieldCache.get(zClass.getName());
|
||||
}
|
||||
|
||||
|
||||
List<Field> 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<Method> getAllMethodWithSuper(Class zClass) {
|
||||
if (methodCache.get(zClass.getName()) != null) {
|
||||
return methodCache.get(zClass.getName());
|
||||
}
|
||||
|
||||
Class tempClass = zClass;
|
||||
List<Method> methodList = Lists.newArrayList();
|
||||
while (tempClass != null) {
|
||||
methodList.addAll(Arrays.asList(tempClass.getDeclaredMethods()));
|
||||
tempClass = tempClass.getSuperclass();
|
||||
}
|
||||
|
||||
methodCache.put(zClass.getName(), methodList);
|
||||
return methodList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Object, Object> map, List<Map.Entry> changeList) {
|
||||
if (CollectionUtils.isEmpty(changeList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (Map.Entry entry : changeList) {
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 <T> Set类型
|
||||
* @return 返回origin中不被包含在target的元素集合
|
||||
*/
|
||||
public static <T> List<T> findUnLikeValue(Set<T> origin, Set<T> target) {
|
||||
List<T> unLikeList = Lists.newArrayList();
|
||||
for (T t : origin) {
|
||||
if (target.contains(t)) {
|
||||
continue;
|
||||
}
|
||||
unLikeList.add(t);
|
||||
}
|
||||
|
||||
return unLikeList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# 工具说明
|
||||
|
||||
# 更新日志
|
||||
2020/4/30: 创建项目、单测,进行第一轮简单的测试
|
||||
@@ -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<SimpleObj> sim = ContrastUtil.contrast(new SimpleObj(), s1);
|
||||
|
||||
|
||||
System.out.print(sim.getTargetChange().m + " " + sim.getTargetChange().x + " " + sim.getTargetChange().y);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user