Files
codeCheck/src/main/java/com/codechecker/api/parser/NestedDtoFieldParser.java
2026-06-09 17:57:52 +08:00

100 lines
4.1 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.codechecker.api.parser;
import com.codechecker.git.GitChangeScanner;
import com.codechecker.model.FieldInfo;
import com.codechecker.parser.ClassFieldParser;
import com.codechecker.parser.TypeNameUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* 递归展开 Dto/Vo 嵌套字段dot path与类变更字段解析解耦但复用 ClassFieldParser。
*/
public class NestedDtoFieldParser {
private static final Set<String> LEAF_TYPES = Set.of(
"String", "Integer", "int", "Long", "long", "Boolean", "boolean", "Double", "double",
"Float", "float", "Short", "short", "Byte", "byte", "Character", "char",
"BigDecimal", "BigInteger", "Date", "LocalDate", "LocalDateTime", "LocalTime",
"Instant", "Timestamp", "Object", "Void", "void"
);
private final ClassFieldParser classFieldParser = new ClassFieldParser();
private final JavaSourceLocator sourceLocator;
private final GitChangeScanner gitScanner;
private final String oldSha;
private final String newSha;
private final int maxDepth;
public NestedDtoFieldParser(Path repoRoot, List<String> searchDirs,
GitChangeScanner gitScanner, String oldSha, String newSha, int maxDepth) {
this.sourceLocator = new JavaSourceLocator(repoRoot, searchDirs);
this.gitScanner = gitScanner;
this.oldSha = oldSha;
this.newSha = newSha;
this.maxDepth = maxDepth;
}
public List<NestedFieldInfo> parseNestedFieldsAtOldCommit(String dtoClassName) throws IOException {
return parseNestedFields(dtoClassName, oldSha);
}
public List<NestedFieldInfo> parseNestedFieldsAtNewCommit(String dtoClassName) throws IOException {
return parseNestedFields(dtoClassName, newSha);
}
private List<NestedFieldInfo> parseNestedFields(String dtoClassName, String sha) throws IOException {
Set<String> visiting = new HashSet<>();
List<NestedFieldInfo> result = new ArrayList<>();
collectFields(dtoClassName, "", visiting, result, sha, 1);
return result;
}
private void collectFields(String className, String prefix, Set<String> visiting,
List<NestedFieldInfo> out, String sha, int depth) throws IOException {
if (className == null || className.isBlank() || visiting.contains(className) || depth > maxDepth) {
return;
}
visiting.add(className);
Optional<String> source = readSource(className, sha);
if (source.isEmpty()) {
visiting.remove(className);
return;
}
List<FieldInfo> fields = classFieldParser.parseFields(source.get(), className);
for (FieldInfo field : fields) {
String path = prefix.isBlank() ? field.getName() : prefix + "." + field.getName();
Set<String> nestedTypes = TypeNameUtils.peelDirectTypeNames(field.getType());
boolean expanded = false;
for (String nestedType : nestedTypes) {
if (isLeafType(nestedType) || nestedType.equals(className)) {
continue;
}
expanded = true;
// 嵌套字段路径用类型简单类名(如 UserSelfDto.nickName不用成员名userDtos.nickName
collectFields(nestedType, nestedType, visiting, out, sha, depth + 1);
}
if (!expanded) {
out.add(new NestedFieldInfo(path, field.getType(), field.getDescription()));
}
}
visiting.remove(className);
}
private Optional<String> readSource(String className, String sha) throws IOException {
if (sha != null && gitScanner != null) {
return sourceLocator.readSourceAtCommit(gitScanner, sha, className);
}
return sourceLocator.readSourceBySimpleName(className);
}
private boolean isLeafType(String simpleType) {
return LEAF_TYPES.contains(simpleType) || simpleType.endsWith("[]");
}
}