Files
AI-Check-Test/.gitea/checker/src/main/java/com/autoCheck/analyzer/FieldDiffEngine.java
dongzi e367d4257f
All checks were successful
类变更检测 / class-change-check (push) Successful in 14s
字段修改匹配规则优化
2026-06-08 16:16:39 +08:00

167 lines
6.2 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.aicheck.analyzer;
import com.aicheck.model.FieldChange;
import com.aicheck.model.FieldInfo;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 对比新旧字段列表,产出新增/删除/类型修改/重命名(纯注释变更忽略)。
*/
public class FieldDiffEngine {
/**
* 按字段名对比;删除+新增且说明匹配时合并为重命名。
* 输出顺序:按新字段声明顺序,未配对的删除字段置于末尾。
*/
public List<FieldChange> diff(List<FieldInfo> oldFields, List<FieldInfo> newFields) {
Map<String, FieldInfo> oldMap = toMap(oldFields);
Map<String, FieldInfo> newMap = toMap(newFields);
List<FieldChange> modified = new ArrayList<>();
List<FieldInfo> added = new ArrayList<>();
List<FieldInfo> removed = new ArrayList<>();
for (FieldInfo newField : newFields) {
FieldInfo oldField = oldMap.get(newField.getName());
if (oldField == null) {
added.add(newField);
} else if (!oldField.getType().equals(newField.getType())) {
modified.add(FieldChange.modified(oldField, newField, buildTypeDetail(oldField, newField)));
}
// 仅 @Schema / 注释文案变化:不纳入字段变更
}
for (FieldInfo oldField : oldFields) {
if (!newMap.containsKey(oldField.getName())) {
removed.add(oldField);
}
}
List<FieldChange> renamed = pairRenames(removed, added);
return mergeInOrder(newFields, renamed, modified, added, removed);
}
/**
* 将删除+新增配对为字段重命名。
* 优先:说明相同且类型相同;其次:说明相同但类型不同(重命名+改类型)。
*/
private List<FieldChange> pairRenames(List<FieldInfo> removed, List<FieldInfo> added) {
List<FieldChange> renames = new ArrayList<>();
Set<FieldInfo> matchedRemoved = new LinkedHashSet<>();
Set<FieldInfo> matchedAdded = new LinkedHashSet<>();
for (FieldInfo oldField : removed) {
FieldInfo pair = findRenamePair(oldField, added, matchedAdded, true);
if (pair == null) {
pair = findRenamePair(oldField, added, matchedAdded, false);
}
if (pair != null) {
renames.add(FieldChange.renamed(oldField, pair));
matchedRemoved.add(oldField);
matchedAdded.add(pair);
}
}
removed.removeIf(matchedRemoved::contains);
added.removeIf(matchedAdded::contains);
return renames;
}
private FieldInfo findRenamePair(FieldInfo removed, List<FieldInfo> added,
Set<FieldInfo> excluded, boolean requireSameType) {
for (FieldInfo candidate : added) {
if (excluded.contains(candidate)) {
continue;
}
if (!descriptionsMatch(removed, candidate)) {
continue;
}
if (requireSameType && !removed.getType().equals(candidate.getType())) {
continue;
}
if (!requireSameType && removed.getType().equals(candidate.getType())) {
continue;
}
return candidate;
}
return null;
}
/** 说明相同(非空)或双方均为空时视为匹配 */
private boolean descriptionsMatch(FieldInfo oldField, FieldInfo newField) {
String oldDesc = normalizeDescription(oldField.getDescription());
String newDesc = normalizeDescription(newField.getDescription());
if (oldDesc.isEmpty() && newDesc.isEmpty()) {
return true;
}
if (oldDesc.isEmpty() || newDesc.isEmpty()) {
return false;
}
return oldDesc.equals(newDesc);
}
private String normalizeDescription(String description) {
return description == null ? "" : description.trim();
}
/** 按新字段声明顺序合并各变更类型 */
private List<FieldChange> mergeInOrder(List<FieldInfo> newFields, List<FieldChange> renamed,
List<FieldChange> modified, List<FieldInfo> added,
List<FieldInfo> removed) {
Map<String, FieldChange> renamedByNewName = new LinkedHashMap<>();
for (FieldChange change : renamed) {
renamedByNewName.put(change.getFieldName(), change);
}
Map<String, FieldChange> modifiedByName = new LinkedHashMap<>();
for (FieldChange change : modified) {
modifiedByName.put(change.getFieldName(), change);
}
Set<String> emitted = new LinkedHashSet<>();
List<FieldChange> result = new ArrayList<>();
for (FieldInfo newField : newFields) {
String name = newField.getName();
if (renamedByNewName.containsKey(name)) {
result.add(renamedByNewName.get(name));
emitted.add(name);
} else if (modifiedByName.containsKey(name)) {
result.add(modifiedByName.get(name));
emitted.add(name);
} else if (added.stream().anyMatch(f -> f.getName().equals(name))) {
result.add(FieldChange.added(newField));
emitted.add(name);
}
}
for (FieldInfo oldField : removed) {
result.add(FieldChange.removed(oldField));
}
return result;
}
/** 字段列表转 LinkedHashMap保持声明顺序 */
private Map<String, FieldInfo> toMap(List<FieldInfo> fields) {
Map<String, FieldInfo> map = new LinkedHashMap<>();
for (FieldInfo field : fields) {
map.put(field.getName(), field);
}
return map;
}
/** 构造类型变化描述,如 Integer → String */
private String buildTypeDetail(FieldInfo oldField, FieldInfo newField) {
if (oldField.getType().equals(newField.getType())) {
return "";
}
return oldField.getType() + "" + newField.getType();
}
}