From cf45b0062a73596230cbdb1e7f06b77c809007a0 Mon Sep 17 00:00:00 2001 From: "chen.ma" Date: Fri, 29 Jul 2022 23:45:02 +0800 Subject: [PATCH] Remove Equator --- README.md | 2 +- .../logrecord/compare/AbstractEquator.java | 202 ------------------ .../tools/logrecord/compare/Equator.java | 48 ----- .../tools/logrecord/compare/FieldInfo.java | 96 --------- .../logrecord/compare/GetterBaseEquator.java | 161 -------------- 5 files changed, 1 insertion(+), 508 deletions(-) delete mode 100644 hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/AbstractEquator.java delete mode 100644 hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/Equator.java delete mode 100644 hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/FieldInfo.java delete mode 100644 hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/GetterBaseEquator.java diff --git a/README.md b/README.md index 6266b571..64178847 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Hippo-4J 获得了一些宝贵的荣誉,这属于每一位对 Hippo-4J 做出 ## 鸣谢 -Hippo-4J 项目基于或参考以下项目:[nacos](https://github.com/alibaba/nacos)、[eureka](https://github.com/Netflix/Eureka)、[mzt-biz-log](https://github.com/mouzt/mzt-biz-log)、[equator](https://github.com/dadiyang/equator)。 +Hippo-4J 项目基于或参考以下项目:[nacos](https://github.com/alibaba/nacos)、[eureka](https://github.com/Netflix/Eureka)、[mzt-biz-log](https://github.com/mouzt/mzt-biz-log)。 感谢 JetBrains 提供的免费开源 License: diff --git a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/AbstractEquator.java b/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/AbstractEquator.java deleted file mode 100644 index 9c17b7ff..00000000 --- a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/AbstractEquator.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cn.hippo4j.tools.logrecord.compare; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * 比对器抽象类. - * - * @author chen.ma - * @date 2021/10/24 20:25 - */ -public class AbstractEquator implements Equator { - - private static final List> WRAPPER = - Arrays - .asList( - Byte.class, - Short.class, - Integer.class, - Long.class, - Float.class, - Double.class, - Character.class, - Boolean.class, - String.class); - - private List includeFields; - - private List excludeFields; - - private boolean bothExistFieldOnly = true; - - public AbstractEquator() { - includeFields = Collections.emptyList(); - excludeFields = Collections.emptyList(); - } - - /** - * @param bothExistFieldOnly 是否仅比对两个类都包含的字段 - */ - public AbstractEquator(boolean bothExistFieldOnly) { - includeFields = Collections.emptyList(); - excludeFields = Collections.emptyList(); - this.bothExistFieldOnly = bothExistFieldOnly; - } - - /** - * 指定包含或排除某些字段. - * - * @param includeFields 包含字段, 若为 null 或空集则不指定 - * @param excludeFields 排除字段, 若为 null 或空集则不指定 - */ - public AbstractEquator(List includeFields, List excludeFields) { - this.includeFields = includeFields; - this.excludeFields = excludeFields; - } - - /** - * 指定包含或排除某些字段. - * - * @param includeFields 包含字段, 若为 null 或空集则不指定 - * @param excludeFields 排除字段, 若为 null 或空集则不指定 - * @param bothExistFieldOnly 是否只对比两个类都包含的字段, 默认为 true - */ - public AbstractEquator(List includeFields, List excludeFields, boolean bothExistFieldOnly) { - this.includeFields = includeFields; - this.excludeFields = excludeFields; - this.bothExistFieldOnly = bothExistFieldOnly; - } - - @Override - public boolean isEquals(Object first, Object second) { - List diff = getDiffFields(first, second); - return diff == null || diff.isEmpty(); - } - - @Override - public List getDiffFields(Object first, Object second) { - return null; - } - - /** - * 对比两个对象的指定属性是否相等, 默认为两个对象是否 equals. - *

- * 子类可以通过覆盖此方法对某些特殊属性进行比对. - * - * @param fieldInfo - * @return - */ - protected boolean isFieldEquals(FieldInfo fieldInfo) { - // 先判断排除, 如果需要排除, 则无论在不在包含范围, 都一律不比对 - if (isExclude(fieldInfo)) { - return true; - } - // 如果有指定需要包含的字段而且当前字段不在需要包含的字段中则不比对 - if (!isInclude(fieldInfo)) { - return true; - } - return nullableEquals(fieldInfo.getFirstVal(), fieldInfo.getSecondVal()); - } - - /** - * 确定是否需要需要排除这个字段, 子类可以扩展这个方法, 自定义判断方式. - * - * @param fieldInfo - * @return - */ - protected boolean isExclude(FieldInfo fieldInfo) { - // 如果有指定需要排除的字段,而且当前字段是需要排除字段,则直接返回 true - return excludeFields != null && !excludeFields.isEmpty() && excludeFields.contains(fieldInfo.getFieldName()); - } - - /** - * 确定是否需要比较这个字段, 子类可以扩展这个方法, 自定义判断方式. - * - * @param fieldInfo - * @return - */ - protected boolean isInclude(FieldInfo fieldInfo) { - // 没有指定需要包含的字段,则全部都包含 - if (includeFields == null || includeFields.isEmpty()) { - return true; - } - return includeFields.contains(fieldInfo.getFieldName()); - } - - /** - * 如果简单数据类型的对象则直接进行比对. - * - * @param first - * @param second - * @return - */ - protected List compareSimpleField(Object first, Object second) { - boolean eq = Objects.equals(first, second); - if (eq) { - return Collections.emptyList(); - } else { - Object obj = first == null ? second : first; - Class clazz = obj.getClass(); - // 不等的字段名称使用类的名称 - return Collections.singletonList(new FieldInfo(clazz.getSimpleName(), clazz, first, second)); - } - } - - /** - * 判断是否为原始数据类型. - * - * @param first - * @param second - * @return - */ - protected boolean isSimpleField(Object first, Object second) { - Object obj = first == null ? second : first; - Class clazz = obj.getClass(); - return clazz.isPrimitive() || WRAPPER.contains(clazz); - } - - protected boolean nullableEquals(Object first, Object second) { - if (first instanceof Collection && second instanceof Collection) { - // 如果两个都是集合类型,尝试转换为数组再进行深度比较 - return Objects.deepEquals(((Collection) first).toArray(), ((Collection) second).toArray()); - } - return Objects.deepEquals(first, second); - } - - protected Set getAllFieldNames(Set firstFields, Set secondFields) { - Set allFields; - // 只取交集 - if (isBothExistFieldOnly()) { - allFields = firstFields.stream().filter(secondFields::contains).collect(Collectors.toSet()); - } else { - // 否则取并集 - allFields = new HashSet<>(firstFields); - allFields.addAll(secondFields); - } - - return allFields; - } - - public boolean isBothExistFieldOnly() { - return bothExistFieldOnly; - } - -} diff --git a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/Equator.java b/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/Equator.java deleted file mode 100644 index d8345e12..00000000 --- a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/Equator.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cn.hippo4j.tools.logrecord.compare; - -import java.util.List; - -/** - * 对象比对器. - * - * @author chen.ma - * @date 2021/10/24 20:27 - */ -public interface Equator { - - /** - * 判断两个对象是否相等. - * - * @param first - * @param second - * @return - */ - boolean isEquals(Object first, Object second); - - /** - * 获取两个对象不想等的属性. - * - * @param first - * @param second - * @return - */ - List getDiffFields(Object first, Object second); - -} diff --git a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/FieldInfo.java b/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/FieldInfo.java deleted file mode 100644 index 89624745..00000000 --- a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/FieldInfo.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cn.hippo4j.tools.logrecord.compare; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.Objects; - -/** - * 对象比较中不同的字段. - * - * @author chen.ma - * @date 2021/10/24 20:03 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class FieldInfo { - - /** - * 字段名称 - */ - private String fieldName; - - /** - * 第一个字段的类型 - */ - private Class firstFieldType; - - /** - * 第二个字段的类型 - */ - private Class secondFieldType; - - /** - * 第一个对象的值 - */ - private Object firstVal; - - /** - * 第二个对象的值 - */ - private Object secondVal; - - public FieldInfo(String fieldName, Class firstFieldType, Class secondFieldType) { - this.fieldName = fieldName; - this.firstFieldType = firstFieldType; - this.secondFieldType = secondFieldType; - } - - public FieldInfo(String fieldName, Class fieldType, Object firstVal, Object secondVal) { - this.fieldName = fieldName; - this.firstFieldType = fieldType; - this.secondFieldType = fieldType; - this.firstVal = firstVal; - this.secondVal = secondVal; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (o == null || getClass() != o.getClass()) { - return false; - } - FieldInfo fieldInfo = (FieldInfo) o; - return Objects.equals(fieldName, fieldInfo.fieldName) && - Objects.equals(firstFieldType, fieldInfo.firstFieldType) && - Objects.equals(secondFieldType, fieldInfo.secondFieldType) && - Objects.equals(firstVal, fieldInfo.firstVal) && - Objects.equals(secondVal, fieldInfo.secondVal); - } - - @Override - public int hashCode() { - return Objects.hash(fieldName, firstFieldType, secondFieldType, firstVal, secondVal); - } - -} diff --git a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/GetterBaseEquator.java b/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/GetterBaseEquator.java deleted file mode 100644 index c218e87d..00000000 --- a/hippo4j-tool/log-record-tool/src/main/java/cn/hippo4j/tools/logrecord/compare/GetterBaseEquator.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cn.hippo4j.tools.logrecord.compare; - -import lombok.NoArgsConstructor; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 基于 getter 方法比对两个对象 - *

- * 所有无参的 get 和 is 方法都认为是对象的属性 - * - * @author chen.ma - * @date 2021/10/24 20:36 - */ -@NoArgsConstructor -public class GetterBaseEquator extends AbstractEquator { - - private static final String GET = "get"; - - private static final String IS = "is"; - - private static final String GET_IS = "get|is"; - - private static final String GET_CLASS = "getClass"; - - private static final Map, Map> CACHE = new ConcurrentHashMap<>(); - - public GetterBaseEquator(boolean bothExistFieldOnly) { - super(bothExistFieldOnly); - } - - public GetterBaseEquator(List includeFields, List excludeFields) { - super(includeFields, excludeFields); - } - - public GetterBaseEquator(List includeFields, List excludeFields, boolean bothExistFieldOnly) { - super(includeFields, excludeFields, bothExistFieldOnly); - } - - @Override - public List getDiffFields(Object first, Object second) { - if (first == null && second == null) { - return Collections.emptyList(); - } - // 先尝试判断是否为普通数据类型 - if (isSimpleField(first, second)) { - return compareSimpleField(first, second); - } - Set allFieldNames; - // 获取所有字段 - Map firstGetters = getAllGetters(first); - Map secondGetters = getAllGetters(second); - if (first == null) { - allFieldNames = secondGetters.keySet(); - } else if (second == null) { - allFieldNames = firstGetters.keySet(); - } else { - allFieldNames = getAllFieldNames(firstGetters.keySet(), secondGetters.keySet()); - } - List diffFields = new LinkedList<>(); - for (String fieldName : allFieldNames) { - try { - Method firstGetterMethod = firstGetters.getOrDefault(fieldName, null); - Method secondGetterMethod = secondGetters.getOrDefault(fieldName, null); - Object firstVal = firstGetterMethod != null ? firstGetterMethod.invoke(first) : null; - Object secondVal = secondGetterMethod != null ? secondGetterMethod.invoke(second) : null; - FieldInfo fieldInfo = new FieldInfo(fieldName, getReturnType(firstGetterMethod), getReturnType(secondGetterMethod)); - fieldInfo.setFirstVal(firstVal); - fieldInfo.setSecondVal(secondVal); - if (!isFieldEquals(fieldInfo)) { - diffFields.add(fieldInfo); - } - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException("获取属性进行比对发生异常: " + fieldName, e); - } - } - return diffFields; - } - - private Class getReturnType(Method method) { - return method == null ? null : method.getReturnType(); - } - - private Map getAllGetters(Object obj) { - if (obj == null) { - return Collections.emptyMap(); - } - return CACHE.computeIfAbsent(obj.getClass(), k -> { - Class clazz = obj.getClass(); - Map getters = new LinkedHashMap<>(8); - while (clazz != Object.class) { - Method[] methods = clazz.getDeclaredMethods(); - for (Method m : methods) { - // getter 方法必须是 public 且没有参数的 - if (!Modifier.isPublic(m.getModifiers()) || m.getParameterTypes().length > 0) { - continue; - } - if (m.getReturnType() == Boolean.class || m.getReturnType() == boolean.class) { - // 如果返回值是 boolean 则兼容 isXxx 的写法 - if (m.getName().startsWith(IS)) { - String fieldName = uncapitalize(m.getName().substring(2)); - getters.put(fieldName, m); - continue; - } - } - // 以 get 开头但排除 getClass() 方法 - if (m.getName().startsWith(GET) && !GET_CLASS.equals(m.getName())) { - String fieldName = uncapitalize(m.getName().replaceFirst(GET_IS, "")); - getters.put(fieldName, m); - } - } - // 得到父类, 然后赋给自己 - clazz = clazz.getSuperclass(); - } - return getters; - }); - } - - private String uncapitalize(final String str) { - int strLen; - if (str == null || (strLen = str.length()) == 0) { - return str; - } - final int firstCodepoint = str.codePointAt(0); - final int newCodePoint = Character.toLowerCase(firstCodepoint); - if (firstCodepoint == newCodePoint) { - return str; - } - final int[] newCodePoints = new int[strLen]; - int outOffset = 0; - newCodePoints[outOffset++] = newCodePoint; - for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen;) { - final int codepoint = str.codePointAt(inOffset); - newCodePoints[outOffset++] = codepoint; - inOffset += Character.charCount(codepoint); - } - return new String(newCodePoints, 0, outOffset); - } - -}