From 9f16fa8d6c52c6a4e199d9988a4a48a7568b6bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=AE=B6=E8=AE=AD?= Date: Thu, 9 Jul 2026 18:08:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biz/apidoc/parser/JavaSourceParser.java | 86 +++++++++++++++---- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/example/workutils/biz/apidoc/parser/JavaSourceParser.java b/src/main/java/com/example/workutils/biz/apidoc/parser/JavaSourceParser.java index e3b647d..6bbe807 100644 --- a/src/main/java/com/example/workutils/biz/apidoc/parser/JavaSourceParser.java +++ b/src/main/java/com/example/workutils/biz/apidoc/parser/JavaSourceParser.java @@ -824,22 +824,31 @@ public class JavaSourceParser { // --- 类开始 / 结束 --- if (!inClass) { - if (tl.contains(" class ") || tl.contains(" interface ") || tl.contains(" enum ")) { + if (isTypeDeclarationLine(tl)) { inClass = true; if (tl.contains("{")) braceDepth = countChar(tl, '{') - countChar(tl, '}'); } continue; } - braceDepth += countChar(tl, '{') - countChar(tl, '}'); + // 记录当前行大括号变化,在判断内部类前保存旧深度 + int lineBraces = countChar(tl, '{') - countChar(tl, '}'); + int depthBefore = braceDepth; + braceDepth += lineBraces; if (braceDepth <= 0) break; // 类结束 // --- 内部类/接口/枚举体:跳过其所有字段,由 extractInnerClasses 单独处理 --- - if (braceDepth == 1 && (tl.contains(" class ") || tl.contains(" interface ") || tl.contains(" enum ")) - && !FIELD_PATTERN.matcher(tl).matches() && !tl.startsWith("//")) { - // 进入内部类体,跳过直到 braceDepth 回到 1 - while (braceDepth > 1 && i + 1 < lines.length) { + // 兼容「声明与 { 不同行」的写法:以 braceDepth 回到进入前层级为结束条件 + if (depthBefore == 1 && !tl.startsWith("//") + && isTypeDeclarationLine(tl) + && !FIELD_PATTERN.matcher(tl).matches()) { + int skipDepth = braceDepth - depthBefore; // 声明行自身带来的深度(0 或 1) + boolean entered = skipDepth > 0; // 是否已真正进入内部类体 + while (i + 1 < lines.length) { i++; braceDepth += countChar(lines[i].trim(), '{') - countChar(lines[i].trim(), '}'); + skipDepth = braceDepth - depthBefore; + if (skipDepth > 0) entered = true; + if (entered && skipDepth <= 0) break; // 回到外部类层级,内部类结束 } pendingJavadoc = null; pendingAnnotations.clear(); @@ -896,10 +905,21 @@ public class JavaSourceParser { } /** - * 提取源文件中的内部类(static class / class)及其字段 + * 提取源文件中的内部类(static class / class)及其字段。 + * 递归提取任意层级的内部类(如 A.B.C),使多级嵌套实体也能按短名展开。 */ private Map> extractInnerClasses(String content, String sourceFile) { Map> result = new LinkedHashMap<>(); + extractInnerClassesRecursive(content, sourceFile, result); + return result; + } + + /** + * 递归提取内容中的内部类(任意层级),key 为内部类短名,value 为其字段列表。 + * 这样多层级嵌套的内部类(如 CompensatoryContractRule.CompensatoryContractRuleSubject.PayConfig) + * 也会被注册到 innerClassCache,供 resolveNestedFields 按短名查找并展开子字段。 + */ + private void extractInnerClassesRecursive(String content, String sourceFile, Map> out) { String[] lines = content.split("\\r?\\n"); boolean inOuterClass = false; int outerBraceDepth = 0; @@ -909,19 +929,23 @@ public class JavaSourceParser { if (tl.isEmpty()) continue; if (!inOuterClass) { - if (tl.contains(" class ") || tl.contains(" interface ")) { + if (isTypeDeclarationLine(tl)) { inOuterClass = true; if (tl.contains("{")) outerBraceDepth = countChar(tl, '{') - countChar(tl, '}'); } continue; } - outerBraceDepth += countChar(tl, '{') - countChar(tl, '}'); + // 记录当前行大括号变化,在判断内部类前保存旧深度 + int lineBraces = countChar(tl, '{') - countChar(tl, '}'); + int depthBefore = outerBraceDepth; + outerBraceDepth += lineBraces; if (outerBraceDepth <= 0) break; - // 检测内部类定义(在外部类的第一层大括号内) - if (outerBraceDepth == 1 && (tl.contains(" class ") || tl.contains(" interface ")) - && !FIELD_PATTERN.matcher(tl).matches() && !tl.startsWith("//")) { + // 检测内部类定义(任意层级,不再限制为第一层) + if (!tl.startsWith("//") + && isTypeDeclarationLine(tl) + && !FIELD_PATTERN.matcher(tl).matches()) { // 提取内部类名 String innerClassName = null; Matcher cm = Pattern.compile("(?:class|interface)\\s+(\\w+)").matcher(tl); @@ -929,23 +953,30 @@ public class JavaSourceParser { if (innerClassName == null) continue; // 收集内部类的完整内容(按大括号深度跟踪) + // 兼容「声明与 { 不同行」的写法:以相对当前外层类层级的深度为基准 StringBuilder innerContent = new StringBuilder(); innerContent.append("class ").append(innerClassName).append(" {\n"); - int innerDepth = countChar(tl, '{') - countChar(tl, '}'); - while (innerDepth > 0 && i + 1 < lines.length) { + int innerDepth = outerBraceDepth - depthBefore; // 相对当前外层类层级的深度(0 或 1) + boolean entered = innerDepth > 0; + while (i + 1 < lines.length) { i++; String il = lines[i].trim(); - innerDepth += countChar(il, '{') - countChar(il, '}'); + outerBraceDepth += countChar(il, '{') - countChar(il, '}'); + innerDepth = outerBraceDepth - depthBefore; + if (innerDepth > 0) entered = true; + if (entered && innerDepth <= 0) break; // 回到当前外层类层级,内部类结束 if (innerDepth > 0) innerContent.append(il).append("\n"); } innerContent.append("}\n"); - // 解析内部类字段 + // 解析内部类字段并注册 List innerFields = parseFields(innerContent.toString(), sourceFile + "$" + innerClassName); - result.put(innerClassName, innerFields); + out.put(innerClassName, innerFields); + + // 递归提取更深层级的内部类(多级嵌套) + extractInnerClassesRecursive(innerContent.toString(), sourceFile + "$" + innerClassName, out); } } - return result; } /** 从内容中提取 extends 的父类短名(去除泛型) */ @@ -1020,6 +1051,25 @@ public class JavaSourceParser { return false; } + /** + * 判断某行是否为 class / interface / enum 声明。 + * 兼容多种写法: + * - 普通声明:public class Xxx、class Xxx + * - 合成头:extractInnerClasses 生成的 "class Xxx {"(无前导空格) + * - 注解前缀:@Data public static class Xxx + * 仅匹配小写关键字,避免误伤字段(如 private MyClass x;)。 + */ + private static boolean isTypeDeclarationLine(String tl) { + String t = tl; + while (t.startsWith("@")) { + int idx = t.indexOf(' '); + if (idx < 0) return false; + t = t.substring(idx + 1).trim(); + } + return t.startsWith("class ") || t.startsWith("interface ") || t.startsWith("enum ") + || t.contains(" class ") || t.contains(" interface ") || t.contains(" enum "); + } + private int countChar(String s, char c) { int cnt = 0; for (int i = 0; i < s.length(); i++) {