十字军骑士免安装绿色中文版
5.4G · 2025-09-16
通过本篇教程,你将学会:
graph TB
subgraph "故障分类"
A1[编译时错误] --> A2[注解处理器错误]
A1 --> A3[代码生成错误]
A1 --> A4[依赖冲突错误]
B1[运行时错误] --> B2[映射执行错误]
B1 --> B3[类型转换错误]
B1 --> B4[空值处理错误]
C1[性能问题] --> C2[映射速度慢]
C1 --> C3[内存泄漏]
C1 --> C4[CPU占用高]
end
subgraph "诊断流程"
D1[问题发现] --> D2[信息收集]
D2 --> D3[问题分析]
D3 --> D4[解决方案]
D4 --> D5[验证修复]
D5 --> D6[预防措施]
end
A1 --> D1
B1 --> D1
C1 --> D1
style A1 fill:#ffebee
style B1 fill:#fff3e0
style C1 fill:#e8f5e8
style D1 fill:#e3f2fd
flowchart LR
subgraph "开发阶段"
A1[IDE调试器] --> A2[断点调试]
A3[编译日志] --> A4[注解处理器输出]
A5[单元测试] --> A6[集成测试]
end
subgraph "运行阶段"
B1[应用日志] --> B2[映射执行日志]
B3[性能监控] --> B4[JVM监控]
B5[链路追踪] --> B6[分布式追踪]
end
subgraph "生产阶段"
C1[APM工具] --> C2[性能分析]
C3[错误监控] --> C4[告警系统]
C5[日志聚合] --> C6[问题定位]
end
A1 --> B1
B1 --> C1
style A1 fill:#e8f5e8
style B1 fill:#e3f2fd
style C1 fill:#fff3e0
/**
* 调试增强的注解处理器
*/
@SupportedAnnotationTypes("io.github.nemoob.atlas.mapper.*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class DebuggableAtlasMapperProcessor extends AbstractProcessor {
private static final String DEBUG_OPTION = "atlas.mapper.debug";
private static final String VERBOSE_OPTION = "atlas.mapper.verbose";
private boolean debugMode;
private boolean verboseMode;
private ProcessingEnvironment processingEnv;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.processingEnv = processingEnv;
// 读取调试选项
this.debugMode = Boolean.parseBoolean(
processingEnv.getOptions().getOrDefault(DEBUG_OPTION, "false"));
this.verboseMode = Boolean.parseBoolean(
processingEnv.getOptions().getOrDefault(VERBOSE_OPTION, "false"));
if (debugMode) {
printDebugInfo("Atlas Mapper 调试模式已启用");
}
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return false;
}
try {
// 调试信息收集
DebugContext debugContext = new DebugContext();
debugContext.setProcessingRound(getCurrentRound());
debugContext.setAnnotations(annotations);
debugContext.setRoundEnvironment(roundEnv);
// 处理 @Mapper 注解
Set<? extends Element> mapperElements = roundEnv.getElementsAnnotatedWith(Mapper.class);
for (Element element : mapperElements) {
if (element.getKind() != ElementKind.INTERFACE) {
continue;
}
TypeElement mapperInterface = (TypeElement) element;
try {
// 详细的处理日志
debugLog("开始处理 Mapper: " + mapperInterface.getQualifiedName());
// 分析 Mapper 接口
MapperAnalysisResult analysis = analyzeMapperInterface(mapperInterface, debugContext);
// 生成实现类
String generatedCode = generateMapperImplementation(analysis, debugContext);
// 写入生成的代码
writeGeneratedClass(analysis.getImplementationClassName(), generatedCode);
debugLog("完成处理 Mapper: " + mapperInterface.getQualifiedName());
} catch (Exception e) {
// 详细的错误信息
handleProcessingError(mapperInterface, e, debugContext);
}
}
// 输出调试报告
if (debugMode) {
generateDebugReport(debugContext);
}
return true;
} catch (Exception e) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR,
"Atlas Mapper 处理器发生未预期错误: " + e.getMessage()
);
if (debugMode) {
e.printStackTrace();
}
return false;
}
}
/**
* 详细的 Mapper 分析
*/
private MapperAnalysisResult analyzeMapperInterface(TypeElement mapperInterface, DebugContext debugContext) {
MapperAnalysisResult result = new MapperAnalysisResult();
result.setMapperInterface(mapperInterface);
// 分析 Mapper 配置
Mapper mapperAnnotation = mapperInterface.getAnnotation(Mapper.class);
result.setMapperConfig(mapperAnnotation);
debugLog("Mapper 配置: " + mapperAnnotation);
// 分析映射方法
List<ExecutableElement> methods = ElementFilter.methodsIn(mapperInterface.getEnclosedElements());
List<MappingMethodAnalysis> methodAnalyses = new ArrayList<>();
for (ExecutableElement method : methods) {
if (method.getModifiers().contains(Modifier.DEFAULT) ||
method.getModifiers().contains(Modifier.STATIC)) {
continue;
}
try {
MappingMethodAnalysis methodAnalysis = analyzeMappingMethod(method, debugContext);
methodAnalyses.add(methodAnalysis);
debugLog("分析映射方法: " + method.getSimpleName() +
" (" + methodAnalysis.getSourceType() + " -> " + methodAnalysis.getTargetType() + ")");
} catch (Exception e) {
String errorMsg = String.format("分析映射方法失败 %s.%s: %s",
mapperInterface.getQualifiedName(), method.getSimpleName(), e.getMessage());
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR, errorMsg, method);
debugContext.addError(errorMsg, method, e);
}
}
result.setMappingMethods(methodAnalyses);
// 验证 Mapper 完整性
validateMapperCompleteness(result, debugContext);
return result;
}
/**
* 映射方法详细分析
*/
private MappingMethodAnalysis analyzeMappingMethod(ExecutableElement method, DebugContext debugContext) {
MappingMethodAnalysis analysis = new MappingMethodAnalysis();
analysis.setMethod(method);
// 分析参数类型
List<? extends VariableElement> parameters = method.getParameters();
if (parameters.size() != 1) {
throw new ProcessingException("映射方法必须有且仅有一个参数: " + method.getSimpleName());
}
TypeMirror sourceType = parameters.get(0).asType();
TypeMirror targetType = method.getReturnType();
analysis.setSourceType(sourceType);
analysis.setTargetType(targetType);
// 分析 @Mapping 注解
List<Mapping> mappingAnnotations = Arrays.asList(method.getAnnotationsByType(Mapping.class));
analysis.setMappingAnnotations(mappingAnnotations);
debugLog("映射注解数量: " + mappingAnnotations.size());
// 分析字段映射关系
FieldMappingAnalysis fieldAnalysis = analyzeFieldMappings(sourceType, targetType, mappingAnnotations, debugContext);
analysis.setFieldMappings(fieldAnalysis);
// 检查类型兼容性
TypeCompatibilityCheck compatibilityCheck = checkTypeCompatibility(sourceType, targetType, debugContext);
analysis.setCompatibilityCheck(compatibilityCheck);
return analysis;
}
/**
* 字段映射分析
*/
private FieldMappingAnalysis analyzeFieldMappings(TypeMirror sourceType, TypeMirror targetType,
List<Mapping> mappingAnnotations, DebugContext debugContext) {
FieldMappingAnalysis analysis = new FieldMappingAnalysis();
// 获取源类型和目标类型的字段
Map<String, TypeMirror> sourceFields = getTypeFields(sourceType);
Map<String, TypeMirror> targetFields = getTypeFields(targetType);
debugLog("源类型字段: " + sourceFields.keySet());
debugLog("目标类型字段: " + targetFields.keySet());
// 分析显式映射
Map<String, String> explicitMappings = new HashMap<>();
for (Mapping mapping : mappingAnnotations) {
explicitMappings.put(mapping.target(), mapping.source());
}
// 分析自动映射
Map<String, String> autoMappings = new HashMap<>();
for (String targetField : targetFields.keySet()) {
if (!explicitMappings.containsKey(targetField) && sourceFields.containsKey(targetField)) {
autoMappings.put(targetField, targetField);
}
}
// 检查未映射字段
Set<String> unmappedTargetFields = new HashSet<>(targetFields.keySet());
unmappedTargetFields.removeAll(explicitMappings.keySet());
unmappedTargetFields.removeAll(autoMappings.keySet());
// 检查类型兼容性
Map<String, TypeCompatibilityIssue> compatibilityIssues = new HashMap<>();
// 检查显式映射的类型兼容性
for (Map.Entry<String, String> entry : explicitMappings.entrySet()) {
String targetField = entry.getKey();
String sourceField = entry.getValue();
TypeMirror sourceFieldType = sourceFields.get(sourceField);
TypeMirror targetFieldType = targetFields.get(targetField);
if (sourceFieldType != null && targetFieldType != null) {
if (!isTypeCompatible(sourceFieldType, targetFieldType)) {
compatibilityIssues.put(targetField,
new TypeCompatibilityIssue(sourceFieldType, targetFieldType, "类型不兼容"));
}
}
}
// 检查自动映射的类型兼容性
for (Map.Entry<String, String> entry : autoMappings.entrySet()) {
String targetField = entry.getKey();
String sourceField = entry.getValue();
TypeMirror sourceFieldType = sourceFields.get(sourceField);
TypeMirror targetFieldType = targetFields.get(targetField);
if (!isTypeCompatible(sourceFieldType, targetFieldType)) {
compatibilityIssues.put(targetField,
new TypeCompatibilityIssue(sourceFieldType, targetFieldType, "自动映射类型不兼容"));
}
}
analysis.setExplicitMappings(explicitMappings);
analysis.setAutoMappings(autoMappings);
analysis.setUnmappedTargetFields(unmappedTargetFields);
analysis.setCompatibilityIssues(compatibilityIssues);
// 输出分析结果
debugLog("显式映射: " + explicitMappings);
debugLog("自动映射: " + autoMappings);
debugLog("未映射字段: " + unmappedTargetFields);
debugLog("兼容性问题: " + compatibilityIssues.size() + " 个");
return analysis;
}
/**
* 错误处理和诊断
*/
private void handleProcessingError(TypeElement mapperInterface, Exception error, DebugContext debugContext) {
String errorMessage = String.format("处理 Mapper %s 时发生错误: %s",
mapperInterface.getQualifiedName(), error.getMessage());
// 记录错误
debugContext.addError(errorMessage, mapperInterface, error);
// 生成详细的错误报告
if (debugMode) {
generateErrorReport(mapperInterface, error, debugContext);
}
// 输出编译错误
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR, errorMessage, mapperInterface);
// 如果是已知错误类型,提供解决建议
String suggestion = generateErrorSuggestion(error);
if (suggestion != null) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.NOTE, "建议: " + suggestion, mapperInterface);
}
}
/**
* 生成错误解决建议
*/
private String generateErrorSuggestion(Exception error) {
String errorMsg = error.getMessage().toLowerCase();
if (errorMsg.contains("cannot find symbol")) {
return "检查导入语句和类路径配置";
} else if (errorMsg.contains("incompatible types")) {
return "检查字段类型兼容性,可能需要自定义类型转换器";
} else if (errorMsg.contains("unmapped target property")) {
return "使用 @Mapping 注解指定字段映射关系,或设置 unmappedTargetPolicy = ReportingPolicy.IGNORE";
} else if (errorMsg.contains("no property named")) {
return "检查源对象是否包含指定的属性名";
} else if (errorMsg.contains("ambiguous mapping methods")) {
return "存在多个匹配的映射方法,请使用 @Named 注解或更具体的方法签名";
}
return null;
}
/**
* 生成调试报告
*/
private void generateDebugReport(DebugContext debugContext) {
StringBuilder report = new StringBuilder();
report.append("n=== Atlas Mapper 调试报告 ===n");
report.append("处理轮次: ").append(debugContext.getProcessingRound()).append("n");
report.append("处理的注解: ").append(debugContext.getAnnotations().size()).append(" 个n");
report.append("发现的错误: ").append(debugContext.getErrors().size()).append(" 个n");
report.append("发现的警告: ").append(debugContext.getWarnings().size()).append(" 个n");
// 输出错误详情
if (!debugContext.getErrors().isEmpty()) {
report.append("n--- 错误详情 ---n");
for (DebugContext.ErrorInfo error : debugContext.getErrors()) {
report.append("错误: ").append(error.getMessage()).append("n");
report.append("位置: ").append(error.getElement()).append("n");
if (error.getException() != null) {
report.append("异常: ").append(error.getException().getClass().getSimpleName()).append("n");
}
report.append("n");
}
}
// 输出警告详情
if (!debugContext.getWarnings().isEmpty()) {
report.append("n--- 警告详情 ---n");
for (DebugContext.WarningInfo warning : debugContext.getWarnings()) {
report.append("警告: ").append(warning.getMessage()).append("n");
report.append("位置: ").append(warning.getElement()).append("n");
report.append("n");
}
}
report.append("=== 调试报告结束 ===n");
// 输出到编译日志
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, report.toString());
// 写入调试文件
try {
writeDebugFile("atlas-mapper-debug.log", report.toString());
} catch (IOException e) {
debugLog("写入调试文件失败: " + e.getMessage());
}
}
// 辅助方法
private void debugLog(String message) {
if (debugMode) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "[DEBUG] " + message);
}
}
private void printDebugInfo(String message) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "[INFO] " + message);
}
private int getCurrentRound() {
// 实现获取当前处理轮次的逻辑
return 1;
}
// 其他辅助方法...
}
<!-- pom.xml 中的调试配置 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<annotationProcessorPaths>
<path>
<groupId>io.github.nemoob</groupId>
<artifactId>atlas-mapper-processor</artifactId>
<version>1.0.0</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<!-- 启用调试模式 -->
<arg>-Aatlas.mapper.debug=true</arg>
<arg>-Aatlas.mapper.verbose=true</arg>
<!-- 输出详细编译信息 -->
<arg>-verbose</arg>
<arg>-Xlint:all</arg>
<!-- 保留生成的源文件 -->
<arg>-s</arg>
<arg>${project.build.directory}/generated-sources/annotations</arg>
</compilerArgs>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<!-- 生成源码插件 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/annotations</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
/**
* 运行时映射监控和调试工具
*/
@Component
public class MappingRuntimeDebugger {
private static final Logger log = LoggerFactory.getLogger(MappingRuntimeDebugger.class);
// 映射执行追踪
private final ThreadLocal<MappingExecutionContext> executionContext = new ThreadLocal<>();
// 错误收集器
private final List<MappingError> recentErrors = Collections.synchronizedList(new ArrayList<>());
// 性能统计
private final Map<String, MappingStats> mappingStats = new ConcurrentHashMap<>();
/**
* 开始映射追踪
*/
public void startMappingTrace(String mapperName, String methodName, Object source) {
MappingExecutionContext context = new MappingExecutionContext();
context.setMapperName(mapperName);
context.setMethodName(methodName);
context.setSourceObject(source);
context.setStartTime(System.nanoTime());
context.setThreadName(Thread.currentThread().getName());
context.setTraceId(generateTraceId());
executionContext.set(context);
log.debug("开始映射追踪 [{}] {}.{} - 源对象类型: {}",
context.getTraceId(), mapperName, methodName,
source != null ? source.getClass().getSimpleName() : "null");
}
/**
* 结束映射追踪
*/
public void endMappingTrace(Object result) {
MappingExecutionContext context = executionContext.get();
if (context == null) {
return;
}
try {
long executionTime = System.nanoTime() - context.getStartTime();
context.setExecutionTime(executionTime);
context.setResultObject(result);
// 更新统计信息
updateMappingStats(context);
log.debug("完成映射追踪 [{}] {}.{} - 执行时间: {:.2f}ms, 结果类型: {}",
context.getTraceId(), context.getMapperName(), context.getMethodName(),
executionTime / 1_000_000.0,
result != null ? result.getClass().getSimpleName() : "null");
} finally {
executionContext.remove();
}
}
/**
* 记录映射错误
*/
public void recordMappingError(Exception error) {
MappingExecutionContext context = executionContext.get();
if (context == null) {
return;
}
MappingError mappingError = new MappingError();
mappingError.setTraceId(context.getTraceId());
mappingError.setMapperName(context.getMapperName());
mappingError.setMethodName(context.getMethodName());
mappingError.setSourceObject(context.getSourceObject());
mappingError.setError(error);
mappingError.setTimestamp(Instant.now());
mappingError.setThreadName(context.getThreadName());
// 添加到错误列表
recentErrors.add(mappingError);
// 保持错误列表大小
if (recentErrors.size() > 1000) {
recentErrors.remove(0);
}
// 记录详细错误日志
log.error("映射执行错误 [{}] {}.{} - 错误: {}",
context.getTraceId(), context.getMapperName(), context.getMethodName(),
error.getMessage(), error);
// 生成错误诊断报告
generateErrorDiagnostics(mappingError);
}
/**
* 字段映射调试
*/
public void debugFieldMapping(String sourceField, Object sourceValue,
String targetField, Object targetValue) {
MappingExecutionContext context = executionContext.get();
if (context == null) {
return;
}
FieldMappingDebugInfo debugInfo = new FieldMappingDebugInfo();
debugInfo.setSourceField(sourceField);
debugInfo.setSourceValue(sourceValue);
debugInfo.setTargetField(targetField);
debugInfo.setTargetValue(targetValue);
debugInfo.setSourceType(sourceValue != null ? sourceValue.getClass() : null);
debugInfo.setTargetType(targetValue != null ? targetValue.getClass() : null);
context.addFieldMapping(debugInfo);
log.trace("字段映射 [{}] {} ({}) -> {} ({}): {} -> {}",
context.getTraceId(), sourceField,
debugInfo.getSourceType() != null ? debugInfo.getSourceType().getSimpleName() : "null",
targetField,
debugInfo.getTargetType() != null ? debugInfo.getTargetType().getSimpleName() : "null",
sourceValue, targetValue);
}
/**
* 类型转换调试
*/
public void debugTypeConversion(Object sourceValue, Object targetValue, String converterName) {
MappingExecutionContext context = executionContext.get();
if (context == null) {
return;
}
TypeConversionDebugInfo debugInfo = new TypeConversionDebugInfo();
debugInfo.setSourceValue(sourceValue);
debugInfo.setTargetValue(targetValue);
debugInfo.setSourceType(sourceValue != null ? sourceValue.getClass() : null);
debugInfo.setTargetType(targetValue != null ? targetValue.getClass() : null);
debugInfo.setConverterName(converterName);
context.addTypeConversion(debugInfo);
log.trace("类型转换 [{}] {} -> {} 使用转换器: {}",
context.getTraceId(),
debugInfo.getSourceType() != null ? debugInfo.getSourceType().getSimpleName() : "null",
debugInfo.getTargetType() != null ? debugInfo.getTargetType().getSimpleName() : "null",
converterName);
}
/**
* 生成映射执行报告
*/
public MappingExecutionReport generateExecutionReport(String traceId) {
// 从执行历史中查找
MappingExecutionContext context = findExecutionContext(traceId);
if (context == null) {
return null;
}
MappingExecutionReport report = new MappingExecutionReport();
report.setTraceId(traceId);
report.setMapperName(context.getMapperName());
report.setMethodName(context.getMethodName());
report.setExecutionTime(context.getExecutionTime());
report.setSourceObject(context.getSourceObject());
report.setResultObject(context.getResultObject());
report.setFieldMappings(context.getFieldMappings());
report.setTypeConversions(context.getTypeConversions());
return report;
}
/**
* 生成错误诊断报告
*/
private void generateErrorDiagnostics(MappingError mappingError) {
StringBuilder diagnostics = new StringBuilder();
diagnostics.append("n=== 映射错误诊断报告 ===n");
diagnostics.append("追踪ID: ").append(mappingError.getTraceId()).append("n");
diagnostics.append("映射器: ").append(mappingError.getMapperName()).append("n");
diagnostics.append("方法: ").append(mappingError.getMethodName()).append("n");
diagnostics.append("线程: ").append(mappingError.getThreadName()).append("n");
diagnostics.append("时间: ").append(mappingError.getTimestamp()).append("n");
// 源对象信息
if (mappingError.getSourceObject() != null) {
diagnostics.append("源对象类型: ").append(mappingError.getSourceObject().getClass().getName()).append("n");
diagnostics.append("源对象内容: ").append(objectToString(mappingError.getSourceObject())).append("n");
}
// 错误信息
Exception error = mappingError.getError();
diagnostics.append("错误类型: ").append(error.getClass().getName()).append("n");
diagnostics.append("错误消息: ").append(error.getMessage()).append("n");
// 错误分析和建议
String analysis = analyzeError(error);
if (analysis != null) {
diagnostics.append("错误分析: ").append(analysis).append("n");
}
String suggestion = suggestErrorSolution(error);
if (suggestion != null) {
diagnostics.append("解决建议: ").append(suggestion).append("n");
}
diagnostics.append("=== 诊断报告结束 ===n");
log.warn(diagnostics.toString());
}
/**
* 错误分析
*/
private String analyzeError(Exception error) {
String errorMsg = error.getMessage();
String errorType = error.getClass().getSimpleName();
if (error instanceof NullPointerException) {
return "空指针异常,可能是源对象或其某个属性为 null";
} else if (error instanceof ClassCastException) {
return "类型转换异常,源类型和目标类型不兼容";
} else if (error instanceof IllegalArgumentException) {
return "非法参数异常,传入的参数不符合预期";
} else if (errorMsg != null && errorMsg.contains("Cannot map")) {
return "映射失败,可能是缺少对应的映射方法或类型转换器";
} else if (errorMsg != null && errorMsg.contains("Ambiguous")) {
return "映射方法模糊,存在多个匹配的映射方法";
}
return "未知错误类型: " + errorType;
}
/**
* 错误解决建议
*/
private String suggestErrorSolution(Exception error) {
String errorMsg = error.getMessage();
if (error instanceof NullPointerException) {
return "1. 检查源对象是否为 nulln2. 使用 @Mapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT) 处理 null 值n3. 在映射前进行 null 检查";
} else if (error instanceof ClassCastException) {
return "1. 检查字段类型是否匹配n2. 添加自定义类型转换器n3. 使用 @Mapping(qualifiedByName = "customConverter") 指定转换方法";
} else if (errorMsg != null && errorMsg.contains("Cannot map")) {
return "1. 检查是否缺少映射方法n2. 添加 @Mapping 注解指定字段映射n3. 实现自定义映射逻辑";
} else if (errorMsg != null && errorMsg.contains("Ambiguous")) {
return "1. 使用 @Named 注解区分映射方法n2. 使用更具体的方法签名n3. 指定 qualifiedByName 属性";
}
return "请查看完整的堆栈跟踪信息,并参考 Atlas Mapper 文档";
}
// 辅助方法
private void updateMappingStats(MappingExecutionContext context) {
String key = context.getMapperName() + "." + context.getMethodName();
mappingStats.compute(key, (k, stats) -> {
if (stats == null) {
stats = new MappingStats();
stats.setMapperName(context.getMapperName());
stats.setMethodName(context.getMethodName());
}
stats.incrementExecutionCount();
stats.addExecutionTime(context.getExecutionTime());
stats.updateLastExecutionTime(Instant.now());
return stats;
});
}
private String generateTraceId() {
return UUID.randomUUID().toString().substring(0, 8);
}
private MappingExecutionContext findExecutionContext(String traceId) {
// 实现从执行历史中查找上下文的逻辑
return null;
}
private String objectToString(Object obj) {
try {
return obj.toString();
} catch (Exception e) {
return obj.getClass().getName() + "@" + Integer.toHexString(obj.hashCode());
}
}
/**
* 映射执行上下文
*/
@Data
public static class MappingExecutionContext {
private String traceId;
private String mapperName;
private String methodName;
private Object sourceObject;
private Object resultObject;
private long startTime;
private long executionTime;
private String threadName;
private List<FieldMappingDebugInfo> fieldMappings = new ArrayList<>();
private List<TypeConversionDebugInfo> typeConversions = new ArrayList<>();
public void addFieldMapping(FieldMappingDebugInfo debugInfo) {
fieldMappings.add(debugInfo);
}
public void addTypeConversion(TypeConversionDebugInfo debugInfo) {
typeConversions.add(debugInfo);
}
}
/**
* 字段映射调试信息
*/
@Data
public static class FieldMappingDebugInfo {
private String sourceField;
private Object sourceValue;
private Class<?> sourceType;
private String targetField;
private Object targetValue;
private Class<?> targetType;
}
/**
* 类型转换调试信息
*/
@Data
public static class TypeConversionDebugInfo {
private Object sourceValue;
private Object targetValue;
private Class<?> sourceType;
private Class<?> targetType;
private String converterName;
}
/**
* 映射错误信息
*/
@Data
public static class MappingError {
private String traceId;
private String mapperName;
private String methodName;
private Object sourceObject;
private Exception error;
private Instant timestamp;
private String threadName;
}
/**
* 映射统计信息
*/
@Data
public static class MappingStats {
private String mapperName;
private String methodName;
private long executionCount;
private long totalExecutionTime;
private long minExecutionTime = Long.MAX_VALUE;
private long maxExecutionTime = Long.MIN_VALUE;
private Instant lastExecutionTime;
public void incrementExecutionCount() {
executionCount++;
}
public void addExecutionTime(long time) {
totalExecutionTime += time;
minExecutionTime = Math.min(minExecutionTime, time);
maxExecutionTime = Math.max(maxExecutionTime, time);
}
public void updateLastExecutionTime(Instant time) {
lastExecutionTime = time;
}
public double getAverageExecutionTime() {
return executionCount > 0 ? (double) totalExecutionTime / executionCount : 0;
}
}
/**
* 映射执行报告
*/
@Data
public static class MappingExecutionReport {
private String traceId;
private String mapperName;
private String methodName;
private long executionTime;
private Object sourceObject;
private Object resultObject;
private List<FieldMappingDebugInfo> fieldMappings;
private List<TypeConversionDebugInfo> typeConversions;
}
}
/**
* 映射调试切面
*/
@Aspect
@Component
@ConditionalOnProperty(name = "atlas.mapper.debug.enabled", havingValue = "true")
public class MappingDebugAspect {
private static final Logger log = LoggerFactory.getLogger(MappingDebugAspect.class);
private final MappingRuntimeDebugger debugger;
public MappingDebugAspect(MappingRuntimeDebugger debugger) {
this.debugger = debugger;
}
/**
* 拦截所有映射方法调用
*/
@Around("execution(* *..*.*(..)) && @within(io.github.nemoob.atlas.mapper.Mapper)")
public Object debugMappingExecution(ProceedingJoinPoint joinPoint) throws Throwable {
String mapperName = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
Object source = args.length > 0 ? args[0] : null;
// 开始追踪
debugger.startMappingTrace(mapperName, methodName, source);
try {
// 执行映射
Object result = joinPoint.proceed();
// 结束追踪
debugger.endMappingTrace(result);
return result;
} catch (Exception e) {
// 记录错误
debugger.recordMappingError(e);
throw e;
}
}
/**
* 拦截字段访问(需要编译时织入)
*/
@Around("get(* *.*) && within(@io.github.nemoob.atlas.mapper.Mapper *)")
public Object debugFieldAccess(ProceedingJoinPoint joinPoint) throws Throwable {
String fieldName = joinPoint.getSignature().getName();
Object result = joinPoint.proceed();
log.trace("字段访问: {} = {}", fieldName, result);
return result;
}
/**
* 拦截方法调用异常
*/
@AfterThrowing(pointcut = "execution(* *..*.*(..)) && @within(io.github.nemoob.atlas.mapper.Mapper)",
throwing = "exception")
public void handleMappingException(JoinPoint joinPoint, Exception exception) {
String mapperName = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
log.error("映射方法异常 {}.{}: {}", mapperName, methodName, exception.getMessage(), exception);
// 生成异常分析报告
generateExceptionAnalysis(joinPoint, exception);
}
/**
* 生成异常分析报告
*/
private void generateExceptionAnalysis(JoinPoint joinPoint, Exception exception) {
StringBuilder analysis = new StringBuilder();
analysis.append("n=== 映射异常分析 ===n");
analysis.append("映射器: ").append(joinPoint.getTarget().getClass().getName()).append("n");
analysis.append("方法: ").append(joinPoint.getSignature().getName()).append("n");
analysis.append("参数: ");
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
if (i > 0) analysis.append(", ");
analysis.append("arg").append(i).append("=");
if (args[i] != null) {
analysis.append(args[i].getClass().getSimpleName()).append("@")
.append(Integer.toHexString(args[i].hashCode()));
} else {
analysis.append("null");
}
}
analysis.append("n");
analysis.append("异常类型: ").append(exception.getClass().getName()).append("n");
analysis.append("异常消息: ").append(exception.getMessage()).append("n");
// 堆栈跟踪分析
StackTraceElement[] stackTrace = exception.getStackTrace();
if (stackTrace.length > 0) {
analysis.append("异常位置: ").append(stackTrace[0]).append("n");
}
analysis.append("=== 分析结束 ===n");
log.error(analysis.toString());
}
}
/**
* 编译时问题诊断工具
*/
public class CompileTimeDiagnostics {
/**
* 诊断注解处理器问题
*/
public static void diagnoseAnnotationProcessor() {
System.out.println("=== 注解处理器诊断 ===");
// 检查注解处理器是否在类路径中
try {
Class.forName("io.github.nemoob.atlas.mapper.processor.AtlasMapperProcessor");
System.out.println(" 注解处理器类已找到");
} catch (ClassNotFoundException e) {
System.out.println(" 注解处理器类未找到,请检查依赖配置");
System.out.println(" 解决方案:添加 atlas-mapper-processor 依赖");
}
// 检查 META-INF/services 配置
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL serviceFile = classLoader.getResource("META-INF/services/javax.annotation.processing.Processor");
if (serviceFile != null) {
System.out.println(" 注解处理器服务配置已找到");
// 读取配置内容
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(serviceFile.openStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(" 处理器: " + line);
}
}
} else {
System.out.println(" 注解处理器服务配置未找到");
System.out.println(" 解决方案:检查 META-INF/services/javax.annotation.processing.Processor 文件");
}
} catch (IOException e) {
System.out.println(" 读取服务配置失败: " + e.getMessage());
}
// 检查编译器参数
String javaVersion = System.getProperty("java.version");
System.out.println("Java 版本: " + javaVersion);
if (javaVersion.startsWith("1.8") || javaVersion.startsWith("8")) {
System.out.println(" Java 版本兼容");
} else {
System.out.println(" Java 版本可能不兼容,推荐使用 Java 8");
}
}
/**
* 诊断依赖冲突
*/
public static void diagnoseDependencyConflicts() {
System.out.println("n=== 依赖冲突诊断 ===");
// 检查关键依赖
String[] criticalDependencies = {
"io.github.nemoob.atlas.mapper.Mapper",
"io.github.nemoob.atlas.mapper.Mapping",
"org.springframework.stereotype.Component",
"org.freemarker.template.Template"
};
for (String className : criticalDependencies) {
try {
Class<?> clazz = Class.forName(className);
URL location = clazz.getProtectionDomain().getCodeSource().getLocation();
System.out.println(" " + className + " -> " + location);
} catch (ClassNotFoundException e) {
System.out.println(" " + className + " 未找到");
}
}
// 检查版本冲突
checkVersionConflicts();
}
/**
* 检查版本冲突
*/
private static void checkVersionConflicts() {
System.out.println("n--- 版本冲突检查 ---");
// 检查 Spring 版本
try {
Class<?> springVersion = Class.forName("org.springframework.core.SpringVersion");
Method getVersionMethod = springVersion.getMethod("getVersion");
String version = (String) getVersionMethod.invoke(null);
System.out.println("Spring 版本: " + version);
if (version != null && version.startsWith("5.2")) {
System.out.println(" Spring 版本兼容");
} else {
System.out.println(" Spring 版本可能不兼容,推荐使用 5.2.x");
}
} catch (Exception e) {
System.out.println("无法检测 Spring 版本");
}
// 检查 Spring Boot 版本
try {
Class<?> springBootVersion = Class.forName("org.springframework.boot.SpringBootVersion");
Method getVersionMethod = springBootVersion.getMethod("getVersion");
String version = (String) getVersionMethod.invoke(null);
System.out.println("Spring Boot 版本: " + version);
if (version != null && version.startsWith("2.2")) {
System.out.println(" Spring Boot 版本兼容");
} else {
System.out.println(" Spring Boot 版本可能不兼容,推荐使用 2.2.x");
}
} catch (Exception e) {
System.out.println("无法检测 Spring Boot 版本");
}
}
/**
* 生成诊断报告
*/
public static void generateDiagnosticReport() {
System.out.println("n=== 完整诊断报告 ===");
diagnoseAnnotationProcessor();
diagnoseDependencyConflicts();
System.out.println("n=== 系统信息 ===");
System.out.println("操作系统: " + System.getProperty("os.name"));
System.out.println("Java 版本: " + System.getProperty("java.version"));
System.out.println("Java 厂商: " + System.getProperty("java.vendor"));
System.out.println("类路径: " + System.getProperty("java.class.path"));
System.out.println("n=== 诊断完成 ===");
}
}
/**
* 运行时问题排查工具
*/
@Component
public class RuntimeTroubleshooter {
private static final Logger log = LoggerFactory.getLogger(RuntimeTroubleshooter.class);
private final ApplicationContext applicationContext;
private final MappingRuntimeDebugger debugger;
public RuntimeTroubleshooter(ApplicationContext applicationContext,
MappingRuntimeDebugger debugger) {
this.applicationContext = applicationContext;
this.debugger = debugger;
}
/**
* 检查 Mapper Bean 注册
*/
public void checkMapperBeans() {
log.info("=== Mapper Bean 检查 ===");
// 获取所有 Mapper Bean
Map<String, Object> mapperBeans = applicationContext.getBeansWithAnnotation(Mapper.class);
if (mapperBeans.isEmpty()) {
log.warn("未找到任何 Mapper Bean");
log.info("可能的原因:");
log.info("1. 注解处理器未正确执行");
log.info("2. 生成的实现类未被 Spring 扫描到");
log.info("3. @ComponentScan 配置不正确");
return;
}
log.info("找到 {} 个 Mapper Bean:", mapperBeans.size());
for (Map.Entry<String, Object> entry : mapperBeans.entrySet()) {
String beanName = entry.getKey();
Object bean = entry.getValue();
Class<?> beanClass = bean.getClass();
log.info("- {}: {} ({})", beanName, beanClass.getName(),
beanClass.isInterface() ? "接口" : "实现类");
// 检查是否是代理对象
if (AopUtils.isAopProxy(bean)) {
log.info(" └─ 这是一个 AOP 代理对象");
Class<?> targetClass = AopUtils.getTargetClass(bean);
log.info(" └─ 目标类: {}", targetClass.getName());
}
// 检查方法
Method[] methods = beanClass.getDeclaredMethods();
log.info(" └─ 方法数量: {}", methods.length);
for (Method method : methods) {
if (!method.isSynthetic() && !method.isBridge()) {
log.debug(" └─ {}", method.getName());
}
}
}
}
/**
* 测试映射功能
*/
public void testMappingFunctionality() {
log.info("=== 映射功能测试 ===");
try {
// 获取 UserMapper Bean
UserMapper userMapper = applicationContext.getBean(UserMapper.class);
log.info(" UserMapper Bean 获取成功");
// 创建测试数据
User testUser = createTestUser();
log.info(" 测试用户创建成功: {}", testUser);
// 执行映射
UserDto userDto = userMapper.toDto(testUser);
log.info(" 映射执行成功: {}", userDto);
// 验证映射结果
validateMappingResult(testUser, userDto);
} catch (NoSuchBeanDefinitionException e) {
log.error(" UserMapper Bean 未找到: {}", e.getMessage());
log.info("解决方案:");
log.info("1. 检查 @Mapper 注解是否正确");
log.info("2. 检查注解处理器是否正确执行");
log.info("3. 检查生成的实现类是否存在");
} catch (Exception e) {
log.error(" 映射执行失败: {}", e.getMessage(), e);
// 分析错误原因
analyzeRuntimeError(e);
}
}
/**
* 分析运行时错误
*/
private void analyzeRuntimeError(Exception error) {
log.info("=== 运行时错误分析 ===");
String errorType = error.getClass().getSimpleName();
String errorMessage = error.getMessage();
log.info("错误类型: {}", errorType);
log.info("错误消息: {}", errorMessage);
// 根据错误类型提供解决方案
switch (errorType) {
case "NullPointerException":
log.info("可能原因:");
log.info("1. 源对象为 null");
log.info("2. 源对象的某个属性为 null");
log.info("3. 映射过程中访问了 null 对象的方法");
log.info("解决方案:");
log.info("1. 在映射前检查源对象是否为 null");
log.info("2. 使用 @Mapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)");
log.info("3. 在源对象的 getter 方法中添加 null 检查");
break;
case "ClassCastException":
log.info("可能原因:");
log.info("1. 字段类型不匹配");
log.info("2. 缺少类型转换器");
log.info("3. 泛型类型擦除导致的问题");
log.info("解决方案:");
log.info("1. 检查源字段和目标字段的类型");
log.info("2. 添加自定义类型转换器");
log.info("3. 使用 @Mapping(qualifiedByName = "customConverter")");
break;
case "IllegalArgumentException":
log.info("可能原因:");
log.info("1. 传入的参数不符合预期");
log.info("2. 枚举值转换失败");
log.info("3. 日期格式转换失败");
log.info("解决方案:");
log.info("1. 检查传入参数的有效性");
log.info("2. 添加参数验证");
log.info("3. 使用自定义转换器处理特殊情况");
break;
default:
log.info("未知错误类型,请查看完整的堆栈跟踪信息");
break;
}
// 输出堆栈跟踪的关键部分
StackTraceElement[] stackTrace = error.getStackTrace();
log.info("关键堆栈信息:");
for (int i = 0; i < Math.min(5, stackTrace.length); i++) {
StackTraceElement element = stackTrace[i];
if (element.getClassName().contains("atlas.mapper") ||
element.getClassName().contains("Mapper")) {
log.info(" at {}.{}({}:{})",
element.getClassName(), element.getMethodName(),
element.getFileName(), element.getLineNumber());
}
}
}
/**
* 验证映射结果
*/
private void validateMappingResult(User source, UserDto target) {
log.info("=== 映射结果验证 ===");
boolean valid = true;
// 验证基本字段
if (!Objects.equals(source.getId(), target.getId())) {
log.warn(" ID 字段映射不正确: {} -> {}", source.getId(), target.getId());
valid = false;
} else {
log.info(" ID 字段映射正确");
}
if (!Objects.equals(source.getName(), target.getName())) {
log.warn(" Name 字段映射不正确: {} -> {}", source.getName(), target.getName());
valid = false;
} else {
log.info(" Name 字段映射正确");
}
if (!Objects.equals(source.getEmail(), target.getEmail())) {
log.warn(" Email 字段映射不正确: {} -> {}", source.getEmail(), target.getEmail());
valid = false;
} else {
log.info(" Email 字段映射正确");
}
// 验证日期字段
if (source.getCreatedAt() != null && target.getCreatedAt() != null) {
String expectedDateStr = source.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
if (!expectedDateStr.equals(target.getCreatedAt())) {
log.warn(" CreatedAt 字段映射不正确: {} -> {}", expectedDateStr, target.getCreatedAt());
valid = false;
} else {
log.info(" CreatedAt 字段映射正确");
}
}
if (valid) {
log.info(" 所有字段映射验证通过");
} else {
log.warn(" 存在字段映射问题,请检查映射配置");
}
}
/**
* 性能问题诊断
*/
public void diagnosePerformanceIssues() {
log.info("=== 性能问题诊断 ===");
// 检查 JVM 内存使用
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory;
log.info("JVM 内存使用情况:");
log.info("- 最大内存: {} MB", maxMemory / 1024 / 1024);
log.info("- 总内存: {} MB", totalMemory / 1024 / 1024);
log.info("- 已使用: {} MB ({:.1f}%)", usedMemory / 1024 / 1024,
(double) usedMemory / totalMemory * 100);
log.info("- 空闲内存: {} MB", freeMemory / 1024 / 1024);
if ((double) usedMemory / totalMemory > 0.8) {
log.warn(" 内存使用率过高,可能影响映射性能");
log.info("建议:");
log.info("1. 增加 JVM 堆内存大小 (-Xmx)");
log.info("2. 优化映射逻辑,减少对象创建");
log.info("3. 使用对象池或缓存策略");
}
// 检查 GC 情况
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
log.info("垃圾收集器信息:");
for (GarbageCollectorMXBean gcBean : gcBeans) {
log.info("- {}: 收集次数={}, 收集时间={}ms",
gcBean.getName(), gcBean.getCollectionCount(), gcBean.getCollectionTime());
}
// 检查线程情况
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
log.info("线程信息:");
log.info("- 活跃线程数: {}", threadBean.getThreadCount());
log.info("- 守护线程数: {}", threadBean.getDaemonThreadCount());
log.info("- 峰值线程数: {}", threadBean.getPeakThreadCount());
}
/**
* 生成完整的故障排查报告
*/
public void generateTroubleshootingReport() {
log.info("=== Atlas Mapper 故障排查报告 ===");
checkMapperBeans();
testMappingFunctionality();
diagnosePerformanceIssues();
log.info("=== 故障排查完成 ===");
}
// 辅助方法
private User createTestUser() {
User user = new User();
user.setId(1L);
user.setName("测试用户");
user.setEmail("[email protected]");
user.setCreatedAt(LocalDateTime.now());
user.setUpdatedAt(LocalDateTime.now());
return user;
}
}
/**
* 调试和故障排查 REST API
*/
@RestController
@RequestMapping("/api/debug")
@ConditionalOnProperty(name = "atlas.mapper.debug.api.enabled", havingValue = "true")
public class MappingDebugController {
private final RuntimeTroubleshooter troubleshooter;
private final MappingRuntimeDebugger debugger;
private final CompileTimeDiagnostics diagnostics;
public MappingDebugController(RuntimeTroubleshooter troubleshooter,
MappingRuntimeDebugger debugger) {
this.troubleshooter = troubleshooter;
this.debugger = debugger;
this.diagnostics = new CompileTimeDiagnostics();
}
/**
* 执行完整的故障排查
*/
@GetMapping("/troubleshoot")
public ResponseEntity<Map<String, Object>> troubleshoot() {
Map<String, Object> result = new HashMap<>();
try {
// 执行故障排查
troubleshooter.generateTroubleshootingReport();
result.put("status", "success");
result.put("message", "故障排查完成,请查看日志获取详细信息");
result.put("timestamp", Instant.now());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("status", "error");
result.put("message", "故障排查失败: " + e.getMessage());
result.put("timestamp", Instant.now());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
/**
* 检查 Mapper Bean 状态
*/
@GetMapping("/mappers")
public ResponseEntity<Map<String, Object>> checkMappers() {
Map<String, Object> result = new HashMap<>();
try {
troubleshooter.checkMapperBeans();
result.put("status", "success");
result.put("message", "Mapper Bean 检查完成");
result.put("timestamp", Instant.now());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("status", "error");
result.put("message", "Mapper Bean 检查失败: " + e.getMessage());
result.put("timestamp", Instant.now());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
/**
* 测试映射功能
*/
@PostMapping("/test-mapping")
public ResponseEntity<Map<String, Object>> testMapping() {
Map<String, Object> result = new HashMap<>();
try {
troubleshooter.testMappingFunctionality();
result.put("status", "success");
result.put("message", "映射功能测试完成");
result.put("timestamp", Instant.now());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("status", "error");
result.put("message", "映射功能测试失败: " + e.getMessage());
result.put("timestamp", Instant.now());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
/**
* 获取映射执行报告
*/
@GetMapping("/execution-report/{traceId}")
public ResponseEntity<MappingRuntimeDebugger.MappingExecutionReport> getExecutionReport(
@PathVariable String traceId) {
MappingRuntimeDebugger.MappingExecutionReport report = debugger.generateExecutionReport(traceId);
if (report != null) {
return ResponseEntity.ok(report);
} else {
return ResponseEntity.notFound().build();
}
}
/**
* 获取最近的映射错误
*/
@GetMapping("/recent-errors")
public ResponseEntity<List<MappingRuntimeDebugger.MappingError>> getRecentErrors(
@RequestParam(defaultValue = "10") int limit) {
// 这里需要在 MappingRuntimeDebugger 中添加获取最近错误的方法
List<MappingRuntimeDebugger.MappingError> recentErrors = getRecentMappingErrors(limit);
return ResponseEntity.ok(recentErrors);
}
/**
* 性能诊断
*/
@GetMapping("/performance")
public ResponseEntity<Map<String, Object>> diagnosePerformance() {
Map<String, Object> result = new HashMap<>();
try {
troubleshooter.diagnosePerformanceIssues();
// 收集性能指标
Runtime runtime = Runtime.getRuntime();
Map<String, Object> memoryInfo = new HashMap<>();
memoryInfo.put("maxMemory", runtime.maxMemory());
memoryInfo.put("totalMemory", runtime.totalMemory());
memoryInfo.put("freeMemory", runtime.freeMemory());
memoryInfo.put("usedMemory", runtime.totalMemory() - runtime.freeMemory());
result.put("status", "success");
result.put("message", "性能诊断完成");
result.put("memoryInfo", memoryInfo);
result.put("timestamp", Instant.now());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("status", "error");
result.put("message", "性能诊断失败: " + e.getMessage());
result.put("timestamp", Instant.now());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
/**
* 编译时诊断
*/
@GetMapping("/compile-diagnostics")
public ResponseEntity<Map<String, Object>> compileTimeDiagnostics() {
Map<String, Object> result = new HashMap<>();
try {
// 重定向系统输出到字符串
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream originalOut = System.out;
System.setOut(new PrintStream(baos));
try {
CompileTimeDiagnostics.generateDiagnosticReport();
} finally {
System.setOut(originalOut);
}
String diagnosticOutput = baos.toString();
result.put("status", "success");
result.put("message", "编译时诊断完成");
result.put("diagnosticOutput", diagnosticOutput);
result.put("timestamp", Instant.now());
return ResponseEntity.ok(result);
} catch (Exception e) {
result.put("status", "error");
result.put("message", "编译时诊断失败: " + e.getMessage());
result.put("timestamp", Instant.now());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
}
}
// 辅助方法
private List<MappingRuntimeDebugger.MappingError> getRecentMappingErrors(int limit) {
// 这里需要实现获取最近错误的逻辑
return Collections.emptyList();
}
}
# 1. 编译时调试
mvn clean compile -Datlas.mapper.debug=true -Datlas.mapper.verbose=true
# 2. 运行时调试
java -jar your-app.jar --atlas.mapper.debug.enabled=true --atlas.mapper.debug.api.enabled=true
# 3. 查看生成的源码
ls -la target/generated-sources/annotations/
# 4. 查看调试日志
tail -f logs/application.log | grep "atlas.mapper"
# 执行完整故障排查
curl http://localhost:8080/api/debug/troubleshoot
# 检查 Mapper Bean
curl http://localhost:8080/api/debug/mappers
# 测试映射功能
curl -X POST http://localhost:8080/api/debug/test-mapping
# 性能诊断
curl http://localhost:8080/api/debug/performance
# 编译时诊断
curl http://localhost:8080/api/debug/compile-diagnostics
# 获取最近错误
curl http://localhost:8080/api/debug/recent-errors?limit=5
=== Atlas Mapper 调试报告 ===
处理轮次: 1
处理的注解: 2 个
发现的错误: 0 个
发现的警告: 1 个
--- 警告详情 ---
警告: 字段 'status' 未映射到目标对象
位置: UserMapper.toDto()
=== 调试报告结束 ===
=== Mapper Bean 检查 ===
找到 2 个 Mapper Bean:
- userMapper: UserMapperImpl (实现类)
└─ 方法数量: 3
└─ toDto
└─ toDtoList
└─ fromDto
=== 映射功能测试 ===
UserMapper Bean 获取成功
测试用户创建成功: User{id=1, name='测试用户', email='[email protected]'}
映射执行成功: UserDto{id=1, name='测试用户', email='[email protected]'}
所有字段映射验证通过
A: 检查以下几个方面:
# 1. 检查依赖配置
mvn dependency:tree | grep atlas-mapper-processor
# 2. 检查编译器配置
mvn help:effective-pom | grep -A 20 maven-compiler-plugin
# 3. 强制重新编译
mvn clean compile -X
# 4. 检查生成的文件
find target -name "*MapperImpl.java"
A: 调试步骤:
// 1. 检查接口定义
@Mapper(componentModel = "spring")
public interface UserMapper {
UserDto toDto(User user); // 确保方法签名正确
}
// 2. 检查生成的实现类
// target/generated-sources/annotations/.../UserMapperImpl.java
// 3. 检查 Spring Bean 注册
@Autowired
private ApplicationContext context;
public void checkBean() {
try {
UserMapper mapper = context.getBean(UserMapper.class);
System.out.println("Bean found: " + mapper.getClass().getName());
} catch (NoSuchBeanDefinitionException e) {
System.out.println("Bean not found: " + e.getMessage());
}
}
A: 类型转换调试技巧:
// 1. 启用详细日志
logging.level.io.github.nemoob.atlas.mapper=DEBUG
// 2. 添加调试断点
@Mapper
public interface UserMapper {
@Mapping(target = "createdAt", source = "createdAt", qualifiedByName = "formatDateTime")
UserDto toDto(User user);
@Named("formatDateTime")
default String formatDateTime(LocalDateTime dateTime) {
System.out.println("Converting: " + dateTime); // 调试输出
return dateTime != null ? dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null;
}
}
// 3. 使用类型转换调试器
debugger.debugTypeConversion(sourceValue, targetValue, "formatDateTime");
A: 性能问题定位方法:
// 1. 使用性能监控
@Around("@within(io.github.nemoob.atlas.mapper.Mapper)")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.nanoTime();
try {
return joinPoint.proceed();
} finally {
long duration = System.nanoTime() - start;
if (duration > 10_000_000) { // 超过 10ms
log.warn("慢映射: {}.{} 耗时 {:.2f}ms",
joinPoint.getTarget().getClass().getSimpleName(),
joinPoint.getSignature().getName(),
duration / 1_000_000.0);
}
}
}
// 2. 使用 JProfiler 或 VisualVM 进行性能分析
// 3. 检查内存使用
Runtime runtime = Runtime.getRuntime();
long before = runtime.totalMemory() - runtime.freeMemory();
// 执行映射
long after = runtime.totalMemory() - runtime.freeMemory();
System.out.println("内存使用: " + (after - before) + " bytes");
通过本章学习,你应该掌握了:
在下一篇教程中,我们将学习: