代码优化
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module version="4">
|
||||||
|
<component name="AdditionalModuleElements">
|
||||||
|
<content url="file://$MODULE_DIR$" dumb="true">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/test" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -1,27 +1,150 @@
|
|||||||
# 我的公众号
|
# 我的公众号
|
||||||

|

|
||||||
|
|
||||||
# 工具说明
|
# Java_ConstractUtil
|
||||||
本工程提供ContrastUtil.java作为通用同类型对象处理工具类,处理规则如下(有没有测试到的bug,欢迎指教.qq:851516902):
|
|
||||||
|
|
||||||
1.Collection和Map的处理当前类只会处理一层,也就是说比如List<泛型>:这个泛型类型会直接调用equals进行处理,可能照成结果的不准确(可以通过Abstract类进行重写)
|
|
||||||
2.如果比较的不是结构体而是基本类型,返回兼容结果
|
|
||||||
3.比较的两个对象类型必须一致
|
|
||||||
4.没有处理Collection的入参和Map的入参,后续会加上
|
|
||||||
5.入参可以为空
|
|
||||||
6.自定义类型没有Get、Set方法会进行报错。不会比较
|
|
||||||
7、自定义类型必须重写equals和hashcode方法,否则不会比较值,而是比较对象地址(这边提供一种自处理的方式,可参考lombok的处理,直接修改AST,这样就算用户不重写equals也会直接比较对应值)
|
|
||||||
8、
|
|
||||||
|
|
||||||
本工程提供AbstractContrastUtil.java作为对象对比抽象基类,提供isSpecialType的判断,可以在对象属性比较的时候进行对应类型的拦截处理,并使用者需要实现Collection、Map、基本类型、自定义类型的处理
|
|
||||||
提供最大的自定义性,因为对应的类型太多,ContractUtil没办法一并处理,所以提供对应抽象类。抽象类的继承示例可参考:ContrastUtilExample.java。该类的实现主要参考ContractUtil.java。
|
|
||||||
|
|
||||||
本工程对于一些抽象类的方法没有非常详细的注释,可直接参考Contract.java的实现处理。
|
通用的Java同类型对象对比工具类,用于比较两个同类型对象的属性差异,并返回变化的部分。
|
||||||
|
|
||||||
本工程比较通用而且直接使用反射的方式,在处理速度上面会有一定的限制,后期可修改为内省的方式处理,且处理情况过多,没有覆盖所有的测试场景,希望读者可以提出宝贵的意见和建议。
|
---
|
||||||
|
|
||||||
# 更新日志
|
|
||||||
2020/4/30: 创建项目、单测,进行第一轮简单的测试
|
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
2020/5/9:添加测试方法,修改bug(反射处理null出现空指针的问题比较多),创建抽象类和继承使用示例。添加readme修改记录
|
### Maven依赖
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>Java_ConstractUtil</groupId>
|
||||||
|
<artifactId>Java_ConstractUtil</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 基本使用
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 比较两个同类型对象
|
||||||
|
SimpleObj origin = new SimpleObj();
|
||||||
|
origin.setX(1);
|
||||||
|
origin.setY("hello");
|
||||||
|
|
||||||
|
SimpleObj target = new SimpleObj();
|
||||||
|
target.setX(2);
|
||||||
|
target.setY("hello");
|
||||||
|
|
||||||
|
ContrastObject<SimpleObj> result = ContrastUtil.contrast(origin, target);
|
||||||
|
if (result != null) {
|
||||||
|
// result.getOriginChange() -> 原始对象中发生变化的属性 (x=1)
|
||||||
|
// result.getTargetChange() -> 修改后对象中发生变化的属性 (x=2)
|
||||||
|
System.out.println(result.getOriginChange().getX()); // 1
|
||||||
|
System.out.println(result.getTargetChange().getX()); // 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 工具说明
|
||||||
|
|
||||||
|
### ContrastUtil(通用对比工具)
|
||||||
|
|
||||||
|
`ContrastUtil` 是默认的对象对比实现类,提供静态方法 `contrast(T origin, T target)` 进行对象对比。
|
||||||
|
|
||||||
|
**处理规则:**
|
||||||
|
|
||||||
|
1. **基本类型和包装类型**:直接使用 `equals` 进行比较(如 `int`、`String`、`Date` 等)
|
||||||
|
2. **Collection类型**:比较两个集合的差异,返回差集。仅处理一层,泛型内的元素直接调用 `equals` 比较
|
||||||
|
3. **Map类型**:比较两个Map的差异,包括相同key的value比较和不同key的差异
|
||||||
|
4. **自定义类型**:调用 `equals` 方法进行比较,**要求重写 `equals` 和 `hashCode` 方法**,否则会比较对象地址
|
||||||
|
5. **类型一致性**:比较的两个对象类型必须一致,否则抛出 `TypeMisMatchException`
|
||||||
|
6. **空值处理**:入参可以为 `null`,两者都为 `null` 返回 `null`,其中一个为 `null` 则返回非空一方的结果
|
||||||
|
7. **Getter/Setter检查**:自定义类型必须有完整的 `get`/`set` 方法,否则抛出 `NoGetMethodException` / `NoSetMethodException`
|
||||||
|
8. **抽象类和接口**:不支持抽象类和接口的实例对比,会直接返回 `null`
|
||||||
|
|
||||||
|
**返回值说明:**
|
||||||
|
|
||||||
|
`ContrastObject<T>` 包含四个字段:
|
||||||
|
- `origin`:原始对象(完整)
|
||||||
|
- `target`:修改后的对象(完整)
|
||||||
|
- `originChange`:原始对象中**发生变化**的属性(新实例,仅包含变化的字段)
|
||||||
|
- `targetChange`:修改后对象中**发生变化**的属性(新实例,仅包含变化的字段)
|
||||||
|
|
||||||
|
无变化时返回 `null`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### AbstractContrastUtil(抽象基类)
|
||||||
|
|
||||||
|
`AbstractContrastUtil<T>` 提供最大的自定义性,使用者可以通过继承并实现抽象方法来定制各种类型的对比逻辑。
|
||||||
|
|
||||||
|
**需要实现的抽象方法:**
|
||||||
|
|
||||||
|
| 方法 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `originContract()` | 基本类型和包装类型的对比逻辑 |
|
||||||
|
| `selfContract()` | 自定义类型的对比逻辑 |
|
||||||
|
| `mapContract()` | Map类型的对比逻辑 |
|
||||||
|
| `collectionContract()` | Collection类型的对比逻辑 |
|
||||||
|
| `specialContract()` | 特殊类型的自定义处理逻辑 |
|
||||||
|
| `isSpecialType()` | 判断是否为特殊类型(优先于Collection/Map判断) |
|
||||||
|
| `nullProcessor()` | 入参为null的处理逻辑 |
|
||||||
|
| `originProcessor()` | 基本类型入参的处理逻辑 |
|
||||||
|
| `setContrastObject()` | 组装返回结果对象 |
|
||||||
|
|
||||||
|
**使用示例:** 参考 [ContrastUtilExample.java](src/main/java/ContrastUtilExample.java)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/main/java/
|
||||||
|
├── ContrastUtil.java # 默认对比工具实现
|
||||||
|
├── AbstractContrastUtil.java # 抽象对比基类
|
||||||
|
├── ContrastUtilExample.java # 抽象基类使用示例
|
||||||
|
├── bean/
|
||||||
|
│ └── ContrastObject.java # 对比结果包装类
|
||||||
|
├── constant/
|
||||||
|
│ └── Constant.java # 常量定义
|
||||||
|
├── exception/
|
||||||
|
│ ├── NoGetMethodException.java # 缺少getter方法异常
|
||||||
|
│ ├── NoSetMethodException.java # 缺少setter方法异常
|
||||||
|
│ └── TypeMisMatchException.java # 类型不匹配异常
|
||||||
|
├── handler/
|
||||||
|
│ ├── CollectionHandler.java # Collection类型处理器
|
||||||
|
│ ├── MapHandler.java # Map类型处理器
|
||||||
|
│ ├── OriginHandler.java # 基本类型处理器
|
||||||
|
│ └── SelfHandler.java # 自定义类型处理器
|
||||||
|
└── util/
|
||||||
|
├── CheckUtil.java # 类型检查工具
|
||||||
|
├── ClassUtil.java # 类反射工具
|
||||||
|
├── CollectionUtil.java # 集合差异计算工具
|
||||||
|
├── MapUtil.java # Map工具
|
||||||
|
└── SetUtil.java # Set工具
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 依赖
|
||||||
|
|
||||||
|
| 依赖 | 版本 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| commons-lang3 | 3.9 | 通用工具 |
|
||||||
|
| commons-collections4 | 4.4 | 集合工具 |
|
||||||
|
| guava | 28.2-jre | Google工具库 |
|
||||||
|
| reflectasm | 1.11.0 | 高性能反射 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. Collection和Map仅处理一层,嵌套的泛型类型直接调用 `equals` 比较,可能导致结果不准确。如需深度对比,请使用 `AbstractContrastUtil` 自定义处理逻辑
|
||||||
|
2. 自定义类型**必须重写 `equals` 和 `hashCode` 方法**,否则会比较对象地址而非值
|
||||||
|
3. 当前使用 reflectASM 进行反射调用,性能优于标准反射,但仍有优化空间
|
||||||
|
4. 暂不支持 `is` 前缀的 boolean getter 方法(如 `isActive()`),后续版本会支持
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
- **2020/4/30**:创建项目,完成初始实现和单元测试
|
||||||
|
- **2020/5/9**:添加测试方法,修复反射处理null的空指针问题,创建抽象类和继承使用示例
|
||||||
|
- **2026/5/17**:修复多个bug(MapHandler参数错误、OriginHandler空值比较逻辑、ContrastObject NPE风险等),优化代码实现,补全注释和文档
|
||||||
@@ -121,6 +121,19 @@ public abstract class AbstractContrastUtil<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历所有getter方法,逐一对比属性值,并将差异设入change对象
|
||||||
|
*
|
||||||
|
* @param getList getter方法名列表
|
||||||
|
* @param methodAccess reflectASM方法访问器
|
||||||
|
* @param origin 原始对象
|
||||||
|
* @param target 修改后的对象
|
||||||
|
* @param setList setter方法名列表
|
||||||
|
* @param originChange 原始对象变化部分
|
||||||
|
* @param targetChange 修改后对象变化部分
|
||||||
|
* @param <T> 对象类型
|
||||||
|
* @return 是否有属性发生变化
|
||||||
|
*/
|
||||||
private <T> boolean forContrast(List<String> getList, MethodAccess methodAccess, T origin, T target, List<String> setList,
|
private <T> boolean forContrast(List<String> getList, MethodAccess methodAccess, T origin, T target, List<String> setList,
|
||||||
T originChange, T targetChange) throws Exception {
|
T originChange, T targetChange) throws Exception {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
@@ -151,35 +164,39 @@ public abstract class AbstractContrastUtil<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据属性值类型分发到对应的处理器进行对比
|
||||||
|
* 优先检查特殊类型,然后依次处理Collection、Map、基本类型和自定义类型
|
||||||
|
*/
|
||||||
private boolean contrastValue(Object originValue, Object targetValue, Object originChange, Object targetChange,
|
private boolean contrastValue(Object originValue, Object targetValue, Object originChange, Object targetChange,
|
||||||
MethodAccess methodAccess, String setName) throws Exception {
|
MethodAccess methodAccess, String setName) throws Exception {
|
||||||
//特殊拦截类型的处理
|
|
||||||
if (isSpecialType(originValue, targetValue)) {
|
if (isSpecialType(originValue, targetValue)) {
|
||||||
return specialContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
return specialContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//处理Collection
|
if (originValue instanceof Collection && targetValue instanceof Collection) {
|
||||||
if (originValue instanceof Collection || targetValue instanceof Collection) {
|
|
||||||
return collectionContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
return collectionContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Map的处理
|
if (originValue instanceof Map && targetValue instanceof Map) {
|
||||||
if (originValue instanceof Map || targetValue instanceof Map) {
|
|
||||||
return mapContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
return mapContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//非自定义类的处理
|
if (originValue instanceof Collection || targetValue instanceof Collection
|
||||||
|
|| originValue instanceof Map || targetValue instanceof Map) {
|
||||||
|
return selfContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
}
|
||||||
|
|
||||||
Boolean result = originContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
Boolean result = originContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
if (null != result) {
|
if (null != result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//自定义类型的处理
|
|
||||||
return selfContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
return selfContract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Set方法集合
|
* 获取Get方法集合
|
||||||
*
|
*
|
||||||
* @param methodAccess MethodAccess
|
* @param methodAccess MethodAccess
|
||||||
* @param tClass 类.class
|
* @param tClass 类.class
|
||||||
@@ -199,7 +216,7 @@ public abstract class AbstractContrastUtil<T> {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Get方法集合
|
* 获取Set方法集合
|
||||||
*
|
*
|
||||||
* @param methodAccess MethodAccess
|
* @param methodAccess MethodAccess
|
||||||
* @param tClass 类.class
|
* @param tClass 类.class
|
||||||
@@ -218,6 +235,9 @@ public abstract class AbstractContrastUtil<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建指定类型(get/set)的方法名列表,并缓存
|
||||||
|
*/
|
||||||
private static <T> List<String> buildMethodList(String type, String[] methodNames, List<Method> methods, List<String> methodNameList,
|
private static <T> List<String> buildMethodList(String type, String[] methodNames, List<Method> methods, List<String> methodNameList,
|
||||||
ConcurrentHashMap<String, List<String>> methodCache, Class<T> tClass) {
|
ConcurrentHashMap<String, List<String>> methodCache, Class<T> tClass) {
|
||||||
for (String methodName : methodNames) {
|
for (String methodName : methodNames) {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import static constant.Constant.SET;
|
|||||||
* @description 通用的对象比较基本实现类
|
* @description 通用的对象比较基本实现类
|
||||||
* @date 2020-1-5 16:00:00
|
* @date 2020-1-5 16:00:00
|
||||||
*/
|
*/
|
||||||
class ContrastUtil {
|
public class ContrastUtil {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +46,7 @@ class ContrastUtil {
|
|||||||
* @return 对比结果
|
* @return 对比结果
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <T> ContrastObject<T> contrast(T origin, T target) throws IllegalAccessException, InstantiationException {
|
public static <T> ContrastObject<T> contrast(T origin, T target) throws IllegalAccessException, InstantiationException {
|
||||||
//空的情况的判断
|
//空的情况的判断
|
||||||
if (origin == null || target == null) {
|
if (origin == null || target == null) {
|
||||||
return nullProcessor(origin, target);
|
return nullProcessor(origin, target);
|
||||||
@@ -88,6 +88,14 @@ class ContrastUtil {
|
|||||||
return setContrastObject(origin, target, originChange, targetChange);
|
return setContrastObject(origin, target, originChange, targetChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理基本类型和包装类型的对比(由Bootstrap ClassLoader加载的类)
|
||||||
|
*
|
||||||
|
* @param origin 原始对象
|
||||||
|
* @param target 修改后的对象
|
||||||
|
* @param <T> 对象类型
|
||||||
|
* @return 对比结果,无变化返回null
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static <T> ContrastObject<T> originProcessor(T origin, T target) {
|
private static <T> ContrastObject<T> originProcessor(T origin, T target) {
|
||||||
if (origin == target) {
|
if (origin == target) {
|
||||||
@@ -96,6 +104,14 @@ class ContrastUtil {
|
|||||||
return new ContrastObject(origin, target, origin, target);
|
return new ContrastObject(origin, target, origin, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理入参为null的情况
|
||||||
|
*
|
||||||
|
* @param origin 原始对象
|
||||||
|
* @param target 修改后的对象
|
||||||
|
* @param <T> 对象类型
|
||||||
|
* @return 对比结果,两者都为null返回null,否则返回包含非null一方的结果
|
||||||
|
*/
|
||||||
private static <T> ContrastObject<T> nullProcessor(T origin, T target) {
|
private static <T> ContrastObject<T> nullProcessor(T origin, T target) {
|
||||||
if (origin == null && target == null) {
|
if (origin == null && target == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -108,6 +124,19 @@ class ContrastUtil {
|
|||||||
return setContrastObject(origin, null, origin, null);
|
return setContrastObject(origin, null, origin, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历所有getter方法,逐一对比属性值,并将差异设入change对象
|
||||||
|
*
|
||||||
|
* @param getList getter方法名列表
|
||||||
|
* @param methodAccess reflectASM方法访问器
|
||||||
|
* @param origin 原始对象
|
||||||
|
* @param target 修改后的对象
|
||||||
|
* @param setList setter方法名列表
|
||||||
|
* @param originChange 原始对象变化部分
|
||||||
|
* @param targetChange 修改后对象变化部分
|
||||||
|
* @param <T> 对象类型
|
||||||
|
* @return 是否有属性发生变化
|
||||||
|
*/
|
||||||
private static <T> boolean forContrast(List<String> getList, MethodAccess methodAccess, T origin, T target, List<String> setList,
|
private static <T> boolean forContrast(List<String> getList, MethodAccess methodAccess, T origin, T target, List<String> setList,
|
||||||
T originChange, T targetChange) throws InstantiationException,
|
T originChange, T targetChange) throws InstantiationException,
|
||||||
IllegalAccessException {
|
IllegalAccessException {
|
||||||
@@ -139,6 +168,16 @@ class ContrastUtil {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装对比结果对象
|
||||||
|
*
|
||||||
|
* @param origin 原始对象
|
||||||
|
* @param target 修改后的对象
|
||||||
|
* @param originChange 原始对象中发生变化的部分
|
||||||
|
* @param targetChange 修改后对象中发生变化的部分
|
||||||
|
* @param <T> 对象类型
|
||||||
|
* @return 对比结果
|
||||||
|
*/
|
||||||
private static <T> ContrastObject<T> setContrastObject(T origin, T target, T originChange, T targetChange) {
|
private static <T> ContrastObject<T> setContrastObject(T origin, T target, T originChange, T targetChange) {
|
||||||
ContrastObject<T> contrastObject = new ContrastObject<>();
|
ContrastObject<T> contrastObject = new ContrastObject<>();
|
||||||
contrastObject.setOrigin(origin);
|
contrastObject.setOrigin(origin);
|
||||||
@@ -149,40 +188,45 @@ class ContrastUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 根据属性值类型分发到对应的处理器进行对比
|
||||||
|
* 支持Collection、Map、基本类型和自定义类型的对比
|
||||||
|
*
|
||||||
* @param originValue get方法拿到的原始的值
|
* @param originValue get方法拿到的原始的值
|
||||||
* @param targetValue get方法拿到的变化的值
|
* @param targetValue get方法拿到的变化的值
|
||||||
* @param originChange 新创建的原始变化对象
|
* @param originChange 新创建的原始变化对象
|
||||||
* @param targetChange 新创建的改变变化对象
|
* @param targetChange 新创建的改变变化对象
|
||||||
* @param methodAccess reflectASM类
|
* @param methodAccess reflectASM类
|
||||||
* @param setName set方法名
|
* @param setName set方法名
|
||||||
|
* @return 该属性是否发生变化
|
||||||
* @throws IllegalAccessException 异常
|
* @throws IllegalAccessException 异常
|
||||||
* @throws InstantiationException 异常
|
* @throws InstantiationException 异常
|
||||||
*/
|
*/
|
||||||
private static boolean contrastValue(Object originValue, Object targetValue, Object originChange, Object targetChange,
|
private static boolean contrastValue(Object originValue, Object targetValue, Object originChange, Object targetChange,
|
||||||
MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException {
|
MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException {
|
||||||
//处理Collection
|
if (originValue instanceof Collection && targetValue instanceof Collection) {
|
||||||
if (originValue instanceof Collection || targetValue instanceof Collection) {
|
|
||||||
return CollectionHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
return CollectionHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Map的处理
|
if (originValue instanceof Map && targetValue instanceof Map) {
|
||||||
if (originValue instanceof Map || targetValue instanceof Map) {
|
|
||||||
return MapHandler.putValue(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
return MapHandler.putValue(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//非自定义类的处理
|
if (originValue instanceof Collection || targetValue instanceof Collection
|
||||||
|
|| originValue instanceof Map || targetValue instanceof Map) {
|
||||||
|
return SelfHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
|
}
|
||||||
|
|
||||||
Boolean result = OriginHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
Boolean result = OriginHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
if (null != result) {
|
if (null != result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//自定义类型的处理
|
|
||||||
return SelfHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
return SelfHandler.contract(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Get方法集合
|
* 获取Set方法集合
|
||||||
*
|
*
|
||||||
* @param methodAccess MethodAccess
|
* @param methodAccess MethodAccess
|
||||||
* @param tClass 类.class
|
* @param tClass 类.class
|
||||||
@@ -200,6 +244,18 @@ class ContrastUtil {
|
|||||||
return buildMethodList(SET, methodNames, methods, methodNameList, setMethodCache, tClass);
|
return buildMethodList(SET, methodNames, methods, methodNameList, setMethodCache, tClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建指定类型(get/set)的方法名列表,并缓存
|
||||||
|
*
|
||||||
|
* @param type 方法类型前缀(get或set)
|
||||||
|
* @param methodNames reflectASM返回的所有方法名
|
||||||
|
* @param methods 反射获取的所有Method列表
|
||||||
|
* @param methodNameList 用于收集方法名的列表
|
||||||
|
* @param methodCache 方法名缓存Map
|
||||||
|
* @param tClass 类.class
|
||||||
|
* @param <T> T
|
||||||
|
* @return 过滤后的方法名列表
|
||||||
|
*/
|
||||||
private static <T> List<String> buildMethodList(String type, String[] methodNames, List<Method> methods, List<String> methodNameList,
|
private static <T> List<String> buildMethodList(String type, String[] methodNames, List<Method> methods, List<String> methodNameList,
|
||||||
ConcurrentHashMap<String, List<String>> methodCache, Class<T> tClass) {
|
ConcurrentHashMap<String, List<String>> methodCache, Class<T> tClass) {
|
||||||
for (String methodName : methodNames) {
|
for (String methodName : methodNames) {
|
||||||
@@ -217,7 +273,7 @@ class ContrastUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Set方法集合
|
* 获取Get方法集合
|
||||||
*
|
*
|
||||||
* @param methodAccess MethodAccess
|
* @param methodAccess MethodAccess
|
||||||
* @param tClass 类.class
|
* @param tClass 类.class
|
||||||
|
|||||||
@@ -5,9 +5,17 @@ import handler.MapHandler;
|
|||||||
import handler.OriginHandler;
|
import handler.OriginHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* AbstractContrastUtil的使用示例
|
||||||
|
* 该示例直接复用了ContrastUtil中的CollectionHandler、MapHandler、OriginHandler处理器
|
||||||
|
* 自定义类型(selfContract)和特殊类型(specialContract)的处理返回false,表示不进行深度对比
|
||||||
|
*
|
||||||
* @author 志军
|
* @author 志军
|
||||||
*/
|
*/
|
||||||
public class ContrastUtilExample<T> extends AbstractContrastUtil<T> {
|
public class ContrastUtilExample<T> extends AbstractContrastUtil<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理入参为null的情况:两者都为null返回null,否则返回非null一方的结果
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
<T> ContrastObject<T> nullProcessor(T origin, T target) {
|
<T> ContrastObject<T> nullProcessor(T origin, T target) {
|
||||||
if (origin == null && target == null) {
|
if (origin == null && target == null) {
|
||||||
@@ -21,6 +29,9 @@ public class ContrastUtilExample<T> extends AbstractContrastUtil<T> {
|
|||||||
return setContrastObject(origin, null, origin, null);
|
return setContrastObject(origin, null, origin, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理基本类型和包装类型的对比
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
<T> ContrastObject<T> originProcessor(T origin, T target) {
|
<T> ContrastObject<T> originProcessor(T origin, T target) {
|
||||||
if (origin == target) {
|
if (origin == target) {
|
||||||
|
|||||||
@@ -81,10 +81,10 @@ public class ContrastObject<T> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ContrastObject<?> that = (ContrastObject<?>) o;
|
ContrastObject<?> that = (ContrastObject<?>) o;
|
||||||
return getOrigin().equals(that.getOrigin()) &&
|
return Objects.equals(getOrigin(), that.getOrigin()) &&
|
||||||
getTarget().equals(that.getTarget()) &&
|
Objects.equals(getTarget(), that.getTarget()) &&
|
||||||
getOriginChange().equals(that.getOriginChange()) &&
|
Objects.equals(getOriginChange(), that.getOriginChange()) &&
|
||||||
getTargetChange().equals(that.getTargetChange());
|
Objects.equals(getTargetChange(), that.getTargetChange());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -7,5 +7,4 @@ public class Constant {
|
|||||||
|
|
||||||
public static final String GET = "get";
|
public static final String GET = "get";
|
||||||
public static final String SET = "set";
|
public static final String SET = "set";
|
||||||
public static final String WELL_NUMBER = "#";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ public class CollectionHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class returnValue = originValue == null ? targetValue.getClass() : originValue.getClass();
|
Class<?> clazz = originValue == null ? targetValue.getClass() : originValue.getClass();
|
||||||
|
|
||||||
Object originCollection = CollectionUtil.buildDiffCollection(originValue, targetValue, returnValue);
|
Object originCollection = CollectionUtil.buildDiffCollection(originValue, targetValue, clazz);
|
||||||
Object changeCollection = CollectionUtil.buildDiffCollection(targetValue, originValue, returnValue);
|
Object changeCollection = CollectionUtil.buildDiffCollection(targetValue, originValue, clazz);
|
||||||
|
|
||||||
changed = CollectionUtils.isNotEmpty((Collection) originCollection) || CollectionUtils.isNotEmpty((Collection) changeCollection);
|
changed = CollectionUtils.isNotEmpty((Collection) originCollection) || CollectionUtils.isNotEmpty((Collection) changeCollection);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
package handler;
|
package handler;
|
||||||
|
|
||||||
import com.esotericsoftware.reflectasm.MethodAccess;
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import util.MapUtil;
|
import util.MapUtil;
|
||||||
import util.SetUtil;
|
import util.SetUtil;
|
||||||
|
|
||||||
@@ -25,8 +25,7 @@ public class MapHandler {
|
|||||||
public static boolean putValue(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
public static boolean putValue(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException {
|
MethodAccess methodAccess, String setName) throws IllegalAccessException, InstantiationException {
|
||||||
|
|
||||||
//这边也只处理只有一个map可能为空的情况,全部为空在前面的方法做了处理
|
if (SelfHandler.isOneNull(originChange, targetChange, originValue, targetValue, methodAccess, setName)) {
|
||||||
if (SelfHandler.isOneNull(originChange, originChange, targetValue, originValue, methodAccess, setName)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//参数前置
|
//参数前置
|
||||||
@@ -52,25 +51,31 @@ public class MapHandler {
|
|||||||
|
|
||||||
//得到不一致的key的集合.
|
//得到不一致的key的集合.
|
||||||
List<Map.Entry> originList = SetUtil.findUnLikeValue(originEntry, targetEntry);
|
List<Map.Entry> originList = SetUtil.findUnLikeValue(originEntry, targetEntry);
|
||||||
List<Map.Entry> changeList = SetUtil.findUnLikeValue(originEntry, targetEntry);
|
List<Map.Entry> changeList = SetUtil.findUnLikeValue(targetEntry, originEntry);
|
||||||
//计算changed的值
|
//计算changed的值
|
||||||
changed = changed || !CollectionUtils.isEmpty(originList) || !CollectionUtils.isEmpty(changeList);
|
changed = changed || !CollectionUtils.isEmpty(originList) || !CollectionUtils.isEmpty(changeList);
|
||||||
//把不一致的值设置会新的Map中
|
//把不一致的值设置会新的Map中
|
||||||
MapUtil.putIfNotEmpty(originMap, originList);
|
MapUtil.putIfNotEmpty(originMap, originList);
|
||||||
MapUtil.putIfNotEmpty(targetMap, changeList);
|
MapUtil.putIfNotEmpty(targetMap, changeList);
|
||||||
//对对象进行设值
|
//对对象进行设值
|
||||||
methodAccess.invoke(originChange, setName, originValue);
|
methodAccess.invoke(originChange, setName, originMap);
|
||||||
methodAccess.invoke(targetChange, setName, targetValue);
|
methodAccess.invoke(targetChange, setName, targetMap);
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较Map中同一个key对应的两个value,如果不相等则将差异设入对应的Map
|
||||||
|
*/
|
||||||
private static boolean putValue(Object value, Object tValue, Map<Object, Object> originMap,
|
private static boolean putValue(Object value, Object tValue, Map<Object, Object> originMap,
|
||||||
Map<Object, Object> targetMap, Object key) {
|
Map<Object, Object> targetMap, Object key) {
|
||||||
if (value.equals(tValue)) {
|
if (value == null && tValue == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
originMap.put(key, value);
|
if (value == null || tValue == null || !value.equals(tValue)) {
|
||||||
targetMap.put(key, tValue);
|
originMap.put(key, value);
|
||||||
return true;
|
targetMap.put(key, tValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,31 +17,27 @@ public class OriginHandler {
|
|||||||
|
|
||||||
public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
public static Boolean contract(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
MethodAccess methodAccess, String setName) {
|
MethodAccess methodAccess, String setName) {
|
||||||
Class returnValue = originValue == null ? targetValue.getClass() : originValue.getClass();
|
Class<?> clazz = originValue == null ? targetValue.getClass() : originValue.getClass();
|
||||||
|
|
||||||
try {
|
if (clazz.getClassLoader() == null) {
|
||||||
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);
|
return contractValue(originChange, targetChange, originValue, targetValue, methodAccess, setName);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean contractValue(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
private static boolean contractValue(Object originChange, Object targetChange, Object originValue, Object targetValue,
|
||||||
MethodAccess methodAccess, String setName) {
|
MethodAccess methodAccess, String setName) {
|
||||||
boolean result = (originValue == null ? targetValue.equals(originChange) : originValue.equals(targetValue));
|
if (originValue == null || targetValue == null) {
|
||||||
if (originValue == targetValue || result) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
methodAccess.invoke(originChange, setName, originValue);
|
methodAccess.invoke(originChange, setName, originValue);
|
||||||
methodAccess.invoke(targetChange, setName, targetValue);
|
methodAccess.invoke(targetChange, setName, targetValue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (originValue.equals(targetValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
methodAccess.invoke(originChange, setName, originValue);
|
||||||
|
methodAccess.invoke(targetChange, setName, targetValue);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,17 @@ public class SelfHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断两个值是否其中一个为null(另一个不为null),如果是则将非null值设入对应的change对象
|
||||||
|
*
|
||||||
|
* @param originChange 原始变化对象
|
||||||
|
* @param targetChange 修改后变化对象
|
||||||
|
* @param originValue 原始值
|
||||||
|
* @param targetValue 修改后的值
|
||||||
|
* @param methodAccess reflectASM方法访问器
|
||||||
|
* @param setName set方法名
|
||||||
|
* @return 是否其中一个为null
|
||||||
|
*/
|
||||||
static boolean isOneNull(Object originChange, Object targetChange, Object originValue, Object targetValue, MethodAccess methodAccess, String setName) {
|
static boolean isOneNull(Object originChange, Object targetChange, Object originValue, Object targetValue, MethodAccess methodAccess, String setName) {
|
||||||
if (originValue == null) {
|
if (originValue == null) {
|
||||||
methodAccess.invoke(targetChange, setName, targetValue);
|
methodAccess.invoke(targetChange, setName, targetValue);
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static constant.Constant.GET;
|
import static constant.Constant.GET;
|
||||||
import static constant.Constant.SET;
|
import static constant.Constant.SET;
|
||||||
@@ -19,7 +20,7 @@ import static constant.Constant.SET;
|
|||||||
*/
|
*/
|
||||||
public class CheckUtil {
|
public class CheckUtil {
|
||||||
|
|
||||||
private static Vector<String> vector = new Vector<>();
|
private static Set<String> checkedClassSet = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +30,7 @@ public class CheckUtil {
|
|||||||
* @param zClass Class类
|
* @param zClass Class类
|
||||||
*/
|
*/
|
||||||
public static void checkGetAndSetMethod(Class zClass) {
|
public static void checkGetAndSetMethod(Class zClass) {
|
||||||
if (vector.contains(zClass.getName())) {
|
if (checkedClassSet.contains(zClass.getName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<Field> fieldList = ClassUtil.getAllFieldWithSuper(zClass);
|
List<Field> fieldList = ClassUtil.getAllFieldWithSuper(zClass);
|
||||||
@@ -48,9 +49,12 @@ public class CheckUtil {
|
|||||||
throw new NoSetMethodException();
|
throw new NoSetMethodException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vector.add(zClass.getName());
|
checkedClassSet.add(zClass.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验setter方法的参数类型是否与字段类型匹配
|
||||||
|
*/
|
||||||
private static boolean setMethodParamCheck(Field field, String setMethodName, List<Method> methodList) {
|
private static boolean setMethodParamCheck(Field field, String setMethodName, List<Method> methodList) {
|
||||||
for (Method method : methodList) {
|
for (Method method : methodList) {
|
||||||
if (method.getName().equals(setMethodName) && method.getParameterTypes()[0] == field.getType()) {
|
if (method.getName().equals(setMethodName) && method.getParameterTypes()[0] == field.getType()) {
|
||||||
@@ -60,6 +64,9 @@ public class CheckUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提取方法名列表
|
||||||
|
*/
|
||||||
private static List<String> getMethodNameList(List<Method> methodList) {
|
private static List<String> getMethodNameList(List<Method> methodList) {
|
||||||
List<String> methodNameList = Lists.newArrayList();
|
List<String> methodNameList = Lists.newArrayList();
|
||||||
for (Method method : methodList) {
|
for (Method method : methodList) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package util;
|
package util;
|
||||||
|
|
||||||
import com.esotericsoftware.reflectasm.MethodAccess;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@@ -9,21 +8,12 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static constant.Constant.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 志军
|
* @author 志军
|
||||||
* @date 2020-1-5 16:00:00
|
* @date 2020-1-5 16:00:00
|
||||||
* 其实你不用担心类似 ##<code>fieldCache.get(zClass.getName())</code>这样的代码在一个方法里面写了很多遍会处理多次
|
|
||||||
* <p>可以了解一下##方法内联
|
|
||||||
*/
|
*/
|
||||||
public class ClassUtil {
|
public class ClassUtil {
|
||||||
|
|
||||||
/**
|
|
||||||
* 类名#方法 - 方法索引 缓存
|
|
||||||
*/
|
|
||||||
private static ConcurrentHashMap<String, Integer> cache = new ConcurrentHashMap<String, Integer>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类 - Field数组 缓存
|
* 类 - Field数组 缓存
|
||||||
*/
|
*/
|
||||||
@@ -35,46 +25,6 @@ public class ClassUtil {
|
|||||||
private static ConcurrentHashMap<String, List<Method>> methodCache = new ConcurrentHashMap<String, List<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) {
|
static List<Field> getAllFieldWithSuper(Class zClass) {
|
||||||
if (fieldCache.get(zClass.getName()) != null) {
|
if (fieldCache.get(zClass.getName()) != null) {
|
||||||
return fieldCache.get(zClass.getName());
|
return fieldCache.get(zClass.getName());
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ public class CollectionUtil {
|
|||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Collection buildDiffCollection(Object originValue, Object targetValue, Class returnValue) throws IllegalAccessException,
|
public static Collection buildDiffCollection(Object originValue, Object targetValue, Class collectionClass) throws IllegalAccessException,
|
||||||
InstantiationException {
|
InstantiationException {
|
||||||
//数组为空的判断这边需要考虑的只有一个为空另一个不为空,因为在外面已经进行了其他两种情况的处理了
|
|
||||||
if (null == targetValue) {
|
if (null == targetValue) {
|
||||||
return (Collection) originValue;
|
return (Collection) originValue;
|
||||||
}
|
}
|
||||||
@@ -26,7 +25,7 @@ public class CollectionUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object collection = returnValue.newInstance();
|
Object collection = collectionClass.newInstance();
|
||||||
|
|
||||||
for (Object value : (Collection) originValue) {
|
for (Object value : (Collection) originValue) {
|
||||||
if (((Collection) targetValue).contains(value)) {
|
if (((Collection) targetValue).contains(value)) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package util;
|
package util;
|
||||||
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ public class ContractTest {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
|
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
|
||||||
// testSimple();
|
testSimple();
|
||||||
// testObject();
|
testObject();
|
||||||
// testSimpleMap();
|
testSimpleMap();
|
||||||
// testSimpleList();
|
testSimpleList();
|
||||||
// testListList();
|
testListList();
|
||||||
// testListObject();
|
testListObject();
|
||||||
// testListObjectRewriteEqual();
|
testListObjectRewriteEqual();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testObject() throws InstantiationException, IllegalAccessException {
|
private static void testObject() throws InstantiationException, IllegalAccessException {
|
||||||
|
|||||||
Reference in New Issue
Block a user