This commit is contained in:
@@ -81,6 +81,12 @@ public class DtoNestIndex {
|
||||
return names;
|
||||
}
|
||||
|
||||
/** 是否被其他 Dto/Vo 嵌套引用(存在至少一个祖先容器) */
|
||||
public boolean hasAncestors(String className) {
|
||||
Set<String> ancestors = ancestorsOf.get(className);
|
||||
return ancestors != null && !ancestors.isEmpty();
|
||||
}
|
||||
|
||||
/** 嵌套类型的 @RequestBody 根 Dto 祖先(仅 Dto 后缀) */
|
||||
public Set<String> findRequestBodyRoots(String className) {
|
||||
Set<String> roots = new LinkedHashSet<>();
|
||||
|
||||
@@ -35,6 +35,8 @@ public class ImpactAnalyzer {
|
||||
matchEndpoints(report, endpointIndex, matchNames);
|
||||
}
|
||||
|
||||
report.setObjectRoleLabels(NestedObjectRoleResolver.resolve(report, nestIndex, endpointIndex));
|
||||
|
||||
if (!config.isDtoEntityConversionEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.codechecker.analyzer;
|
||||
|
||||
import com.codechecker.model.ApiEndpoint;
|
||||
import com.codechecker.model.ClassChangeReport;
|
||||
import com.codechecker.model.ClassType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 判定 Dto/Vo 在类变更通知中的对象角色标签(方案 B:嵌套 + 可选顶层)。
|
||||
* <p>
|
||||
* 仅当存在嵌套祖先时标注;纯顶层不标注;既嵌套又直接作接口根类型时同时标注。
|
||||
*/
|
||||
public final class NestedObjectRoleResolver {
|
||||
|
||||
private NestedObjectRoleResolver() {
|
||||
}
|
||||
|
||||
public static List<String> resolve(ClassChangeReport report, DtoNestIndex nestIndex,
|
||||
Map<String, ApiEndpoint> endpointIndex) {
|
||||
if (report.getClassType() != ClassType.DTO && report.getClassType() != ClassType.VO) {
|
||||
return List.of();
|
||||
}
|
||||
if (nestIndex == null) {
|
||||
return List.of();
|
||||
}
|
||||
String className = report.getClassName();
|
||||
if (!nestIndex.hasAncestors(className)) {
|
||||
return List.of();
|
||||
}
|
||||
List<String> labels = new ArrayList<>();
|
||||
labels.add("嵌套对象");
|
||||
if (isDirectEndpointType(className, endpointIndex)) {
|
||||
labels.add("顶层对象");
|
||||
}
|
||||
return List.copyOf(labels);
|
||||
}
|
||||
|
||||
/** 是否直接出现在接口入参或返回值类型(非仅经祖先传播) */
|
||||
private static boolean isDirectEndpointType(String className, Map<String, ApiEndpoint> endpointIndex) {
|
||||
if (className == null || className.isBlank() || endpointIndex == null) {
|
||||
return false;
|
||||
}
|
||||
for (ApiEndpoint endpoint : endpointIndex.values()) {
|
||||
if (endpoint.getParamTypes().contains(className)
|
||||
|| endpoint.getReturnTypes().contains(className)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public class ClassChangeReport {
|
||||
private final List<String> conversionEntities = new ArrayList<>();
|
||||
private final List<ApiEndpoint> frontendImpactEndpoints = new ArrayList<>();
|
||||
private final boolean conversionCheckEnabled;
|
||||
private List<String> objectRoleLabels = List.of();
|
||||
|
||||
public ClassChangeReport(String className, String oldClassName, ClassType classType,
|
||||
ClassChangeKind changeKind, String sourceFile,
|
||||
@@ -98,6 +99,15 @@ public class ClassChangeReport {
|
||||
return conversionCheckEnabled;
|
||||
}
|
||||
|
||||
/** 对象角色标签(如「嵌套对象」「顶层对象」),仅 Dto/Vo 且存在嵌套时非空 */
|
||||
public List<String> getObjectRoleLabels() {
|
||||
return objectRoleLabels;
|
||||
}
|
||||
|
||||
public void setObjectRoleLabels(List<String> labels) {
|
||||
this.objectRoleLabels = labels == null || labels.isEmpty() ? List.of() : List.copyOf(labels);
|
||||
}
|
||||
|
||||
/** 追加一条字段变更 */
|
||||
public void addFieldChange(FieldChange change) {
|
||||
fieldChanges.add(change);
|
||||
|
||||
@@ -82,14 +82,17 @@ public class WeComNotifier {
|
||||
return truncate(sb.toString());
|
||||
}
|
||||
|
||||
/** 变更对象行:类名(绿)+ 可选中文说明(灰,整行加粗) */
|
||||
/** 变更对象行:类名(绿)+ 可选中文说明 + 嵌套角色标签(灰,整行加粗) */
|
||||
private String formatChangeTarget(ClassChangeReport report) {
|
||||
String name = colorInfo(safe(report.getClassName()));
|
||||
StringBuilder line = new StringBuilder(colorInfo(safe(report.getClassName())));
|
||||
String description = report.getClassDescription();
|
||||
if (description == null || description.isBlank()) {
|
||||
return name;
|
||||
if (description != null && !description.isBlank()) {
|
||||
line.append("(").append(colorComment(description)).append(")");
|
||||
}
|
||||
return name + "(" + colorComment(description) + ")";
|
||||
for (String role : report.getObjectRoleLabels()) {
|
||||
line.append("(").append(colorComment(role)).append(")");
|
||||
}
|
||||
return line.toString();
|
||||
}
|
||||
|
||||
/** 头部元信息,每项一行引用(加粗) */
|
||||
@@ -139,14 +142,12 @@ public class WeComNotifier {
|
||||
appendImpactByType(sb, report);
|
||||
}
|
||||
|
||||
/** Dto/Vo/Entity/Model 各展示不同的 request/response/转换段落 */
|
||||
/** Dto/Vo 均展示 request + response(二者可能交叉);Entity/Model 仅类转换 */
|
||||
private void appendImpactByType(StringBuilder sb, ClassChangeReport report) {
|
||||
switch (report.getClassType()) {
|
||||
case DTO:
|
||||
appendSectionIfNeeded(sb, report, true, false, true);
|
||||
break;
|
||||
case VO:
|
||||
appendSectionIfNeeded(sb, report, false, true, true);
|
||||
appendSectionIfNeeded(sb, report, true, true, true);
|
||||
break;
|
||||
case ENTITY:
|
||||
case MODEL:
|
||||
@@ -170,7 +171,7 @@ public class WeComNotifier {
|
||||
appendEndpointList(sb, report.getFrontendImpactEndpoints());
|
||||
sb.append("\n");
|
||||
}
|
||||
if (showConversion) {
|
||||
if (showConversion && report.isConversionCheckEnabled()) {
|
||||
sb.append("### 类转换影响").append("\n");
|
||||
appendConversionList(sb, report);
|
||||
}
|
||||
@@ -178,10 +179,6 @@ public class WeComNotifier {
|
||||
|
||||
/** 渲染关联 Entity,每项一行 */
|
||||
private void appendConversionList(StringBuilder sb, ClassChangeReport report) {
|
||||
if (!report.isConversionCheckEnabled()) {
|
||||
sb.append(quoteLine(colorComment("未开启检测"))).append("\n");
|
||||
return;
|
||||
}
|
||||
if (report.getConversionEntities().isEmpty()) {
|
||||
sb.append(quoteLine(colorComment("无"))).append("\n");
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user