购买模板做网站手机网站快速排名 软件

张小明 2026/1/10 18:20:05
购买模板做网站,手机网站快速排名 软件,微网站 一键拨号,wordpress 禁止注册JaCoCo 离线解析.exec文件#xff1a;生成与获取详细覆盖率数据全指南 一、概述 在JaCoCo覆盖率统计场景中#xff0c;jacoco支持cli通过命令行的方式生成覆盖率报告#xff0c;但是这样无法很好和其他系统集成#xff0c;本文演示通过jacoco提供的API的方式生成覆盖率报…JaCoCo 离线解析.exec文件生成与获取详细覆盖率数据全指南一、概述在JaCoCo覆盖率统计场景中jacoco支持cli通过命令行的方式生成覆盖率报告但是这样无法很好和其他系统集成本文演示通过jacoco提供的API的方式生成覆盖率报告和获取覆盖率的具体详情数据。二、通过调用API的方式解析.exec文件获取详细覆盖率数据生成.exec文件后通过JaCoCo API的ExecFileLoader加载文件结合Analyzer和CoverageBuilder解析原始字节码可获取类、方法、行、分支级别的详细覆盖率数据。以下是完整实现方案。3.1 核心依赖确认确保项目已引入解析所需的核心依赖若已引入可跳过!-- JaCoCo 核心依赖解析基础 -- dependency groupIdorg.jacoco/groupId artifactIdjacoco-core/artifactId version0.8.11/version /dependency !-- JaCoCo 报告依赖提供ExecFileLoader等解析工具 -- dependency groupIdorg.jacoco/groupId artifactIdjacoco-report/artifactId version0.8.11/version /dependency3.2 完整解析代码实现以下代码实现了“加载.exec文件 → 解析指定类/全量类 → 提取详细覆盖率数据”的完整流程包含类、方法、行、分支级数据的获取。import org.jacoco.core.analysis.Analyzer; import org.jacoco.core.analysis.CoverageBuilder; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.IMethodCoverage; import org.jacoco.core.analysis.ILineCoverage; import org.jacoco.core.analysis.IBranchCoverage; import org.jacoco.core.data.ExecFileLoader; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.data.SessionInfoStore; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Collection; public class JacocoExecParser { // 核心方法解析.exec文件获取指定类的详细覆盖率数据 public static void parseExecForSingleClass(String execPath, Class? targetClass) throws IOException { // 1. 加载.exec文件 ExecFileLoader execFileLoader loadExecFile(execPath); // 2. 提取执行数据和会话信息 ExecutionDataStore executionDataStore execFileLoader.getExecutionDataStore(); SessionInfoStore sessionInfoStore execFileLoader.getSessionInfoStore(); // 3. 打印会话信息可选用于日志跟踪 printSessionInfo(sessionInfoStore.getInfos()); // 4. 创建CoverageBuilder用于构建覆盖率数据和Analyzer解析器 CoverageBuilder coverageBuilder new CoverageBuilder(); Analyzer analyzer new Analyzer(executionDataStore, coverageBuilder); // 5. 解析目标类的原始字节码Analyzer会自动匹配.exec中的执行数据 byte[] originalBytes getClassBytes(targetClass); analyzer.analyzeClass(new ByteArrayInputStream(originalBytes), targetClass.getName()); // 6. 提取并打印详细覆盖率数据 extractAndPrintCoverageData(coverageBuilder.getClasses()); } // 扩展方法解析.exec文件获取指定目录下所有类的覆盖率数据全量解析 public static void parseExecForAllClasses(String execPath, String classDirPath) throws IOException { // 1. 加载.exec文件 ExecFileLoader execFileLoader loadExecFile(execPath); // 2. 创建解析器 CoverageBuilder coverageBuilder new CoverageBuilder(); Analyzer analyzer new Analyzer(execFileLoader.getExecutionDataStore(), coverageBuilder); // 3. 批量解析指定目录下的所有.class文件如target/classes File classDir new File(classDirPath); if (!classDir.exists() || !classDir.isDirectory()) { throw new IllegalArgumentException(无效的类文件目录 classDirPath); } analyzer.analyzeAll(classDir); // 4. 提取并打印全量覆盖率数据 extractAndPrintCoverageData(coverageBuilder.getClasses()); } // 辅助方法加载.exec文件 private static ExecFileLoader loadExecFile(String execPath) throws IOException { ExecFileLoader execFileLoader new ExecFileLoader(); File execFile new File(execPath); if (!execFile.exists()) { throw new IOException(.exec文件不存在 execPath); } execFileLoader.load(execFile); System.out.println(.exec文件加载成功 execPath); return execFileLoader; } // 辅助方法打印会话信息 private static void printSessionInfo(CollectionSessionInfo sessionInfos) { System.out.println(\n 会话信息 ); for (SessionInfo sessionInfo : sessionInfos) { System.out.println(会话ID sessionInfo.getId()); System.out.println(开始时间 sessionInfo.getStartTime()); System.out.println(结束时间 sessionInfo.getDumpTime()); } } // 辅助方法从类路径读取类的字节码 private static byte[] getClassBytes(Class? clazz) throws IOException { String className clazz.getName().replace(., /) .class; try (InputStream is clazz.getClassLoader().getResourceAsStream(className)) { if (is null) { throw new IOException(Class file not found: className); } return is.readAllBytes(); } } // 核心方法提取并打印类、方法、行、分支级覆盖率数据 private static void extractAndPrintCoverageData(CollectionIClassCoverage classCoverages) { System.out.println(\n 详细覆盖率数据 ); for (IClassCoverage classCoverage : classCoverages) { // 1. 类级覆盖率数据 System.out.println(\n【类信息】); System.out.println(类名 classCoverage.getName()); System.out.println(类全限定名 classCoverage.getPackageName() . classCoverage.getName()); System.out.println(类行覆盖率 String.format(%.2f%%, classCoverage.getLineCoverage() * 100)); System.out.println(类分支覆盖率 String.format(%.2f%%, classCoverage.getBranchCoverage() * 100)); System.out.println(类方法覆盖率 String.format(%.2f%%, classCoverage.getMethodCoverage() * 100)); System.out.println(覆盖的行数量 classCoverage.getCoveredLines()); System.out.println(总行了数量 classCoverage.getLines()); // 2. 方法级覆盖率数据遍历类中所有方法 for (IMethodCoverage methodCoverage : classCoverage.getMethods()) { System.out.println(\n 【方法信息】); System.out.println( 方法名 methodCoverage.getName()); System.out.println( 方法描述符参数返回值类型 methodCoverage.getDesc()); System.out.println( 方法行覆盖率 String.format(%.2f%%, methodCoverage.getLineCoverage() * 100)); System.out.println( 方法分支覆盖率 String.format(%.2f%%, methodCoverage.getBranchCoverage() * 100)); System.out.println( 方法开始行号 methodCoverage.getFirstLine()); System.out.println( 方法结束行号 methodCoverage.getLastLine()); // 3. 行级覆盖率数据遍历方法中所有行 for (int lineNum methodCoverage.getFirstLine(); lineNum methodCoverage.getLastLine(); lineNum) { ILineCoverage lineCoverage methodCoverage.getLine(lineNum); if (lineCoverage ! null) { String lineStatus getLineStatusDesc(lineCoverage.getStatus()); System.out.println(\n 行号 lineNum lineStatus); // 4. 分支级覆盖率数据仅分支行有分支信息 if (lineCoverage.getBranchCoverage() ! null) { IBranchCoverage branchCoverage lineCoverage.getBranchCoverage(); System.out.println( 分支覆盖数量 branchCoverage.getCoveredBranches()); System.out.println( 分支总数量 branchCoverage.getTotalBranches()); System.out.println( 分支覆盖率 String.format(%.2f%%, branchCoverage.getCoverageRatio() * 100)); } } } } } } // 辅助方法将行覆盖状态码转换为描述文本 private static String getLineStatusDesc(int status) { return switch (status) { case 0 - 未覆盖该行代码未执行; case 1 - 部分覆盖分支行仅部分分支执行; case 2 - 完全覆盖该行代码/所有分支均执行; default - 未知状态; }; } // 测试解析指定类的覆盖率数据 public static void main(String[] args) throws IOException { // 1. 解析单个类 parseExecForSingleClass(target/jacoco.exec, com.example.TargetService.class); // 2. 解析全量类注释掉上面打开下面测试 // parseExecForAllClasses(target/jacoco.exec, target/classes); } }3.3 核心API说明ExecFileLoader核心加载工具通过load(File)方法读取.exec文件内部包含ExecutionDataStore执行数据和SessionInfoStore会话信息。Analyzer解析器核心作用是将“执行数据”与“原始字节码”关联生成覆盖率数据。analyzeClass()解析单个类analyzeAll()批量解析目录下所有类。CoverageBuilder覆盖率数据构建器解析完成后通过getClasses()获取所有解析后的类覆盖率数据IClassCoverage。IClassCoverage/IMethodCoverage/ILineCoverage/IBranchCoverage覆盖率数据接口分别对应类、方法、行、分支级数据提供获取覆盖率百分比、覆盖数量、总数量等方法。3.4 输出示例执行上述测试代码后会输出类似以下的详细覆盖率数据.exec文件加载成功target/jacoco.exec 会话信息 会话IDdefault 开始时间1735689600000 结束时间1735689660000 详细覆盖率数据 【类信息】 类名TargetService 类全限定名com.example.TargetService 类行覆盖率85.71% 类分支覆盖率75.00% 类方法覆盖率100.00% 覆盖的行数量12 总行了数量14 【方法信息】 方法名doBusiness 方法描述符参数返回值类型(Ljava/lang/String;)Ljava/lang/String; 方法行覆盖率83.33% 方法分支覆盖率66.67% 方法开始行号10 方法结束行号25 行号 10完全覆盖该行代码/所有分支均执行 行号 11完全覆盖该行代码/所有分支均执行 行号 12部分覆盖分支行仅部分分支执行 分支覆盖数量2 分支总数量3 分支覆盖率66.67% 行号 13未覆盖该行代码未执行 行号 14完全覆盖该行代码/所有分支均执行 ...import org.jacoco.core.analysis.Analyzer; import org.jacoco.core.analysis.CoverageBuilder; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.IMethodCoverage; import org.jacoco.core.data.ExecFileLoader; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.data.SessionInfoStore; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class JacocoCoverageSerializer { // 定义覆盖率数据DTO用于序列化避免直接序列化JaCoCo原生接口 public static class CoverageDTO { // 会话信息 private SessionDTO session; // 类覆盖率列表 private ListClassCoverageDTO classCoverages; // getter/setter public SessionDTO getSession() { return session; } public void setSession(SessionDTO session) { this.session session; } public ListClassCoverageDTO getClassCoverages() { return classCoverages; } public void setClassCoverages(ListClassCoverageDTO classCoverages) { this.classCoverages classCoverages; } } public static class SessionDTO { private String sessionId; private long startTime; private long endTime; // getter/setter public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId sessionId; } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime startTime; } public long getEndTime() { return endTime; } public void setEndTime(long endTime) { this.endTime endTime; } } public static class ClassCoverageDTO { private String className; private String fullClassName; private double lineCoverage; private double branchCoverage; private double methodCoverage; private int coveredLines; private int totalLines; private ListMethodCoverageDTO methodCoverages; // getter/setter public String getClassName() { return className; } public void setClassName(String className) { this.className className; } public String getFullClassName() { return fullClassName; } public void setFullClassName(String fullClassName) { this.fullClassName fullClassName; } public double getLineCoverage() { return lineCoverage; } public void setLineCoverage(double lineCoverage) { this.lineCoverage lineCoverage; } public double getBranchCoverage() { return branchCoverage; } public void setBranchCoverage(double branchCoverage) { this.branchCoverage branchCoverage; } public double getMethodCoverage() { return methodCoverage; } public void setMethodCoverage(double methodCoverage) { this.methodCoverage methodCoverage; } public int getCoveredLines() { return coveredLines; } public void setCoveredLines(int coveredLines) { this.coveredLines coveredLines; } public int getTotalLines() { return totalLines; } public void setTotalLines(int totalLines) { this.totalLines totalLines; } public ListMethodCoverageDTO getMethodCoverages() { return methodCoverages; } public void setMethodCoverages(ListMethodCoverageDTO methodCoverages) { this.methodCoverages methodCoverages; } } public static class MethodCoverageDTO { private String methodName; private String methodDesc; private double lineCoverage; private double branchCoverage; private int firstLine; private int lastLine; private ListLineCoverageDTO lineCoverages; // getter/setter public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName methodName; } public String getMethodDesc() { return methodDesc; } public void setMethodDesc(String methodDesc) { this.methodDesc methodDesc; } public double getLineCoverage() { return lineCoverage; } public void setLineCoverage(double lineCoverage) { this.lineCoverage lineCoverage; } public double getBranchCoverage() { return branchCoverage; } public void setBranchCoverage(double branchCoverage) { this.branchCoverage branchCoverage; } public int getFirstLine() { return firstLine; } public void setFirstLine(int firstLine) { this.firstLine firstLine; } public int getLastLine() { return lastLine; } public void setLastLine(int lastLine) { this.lastLine lastLine; } public ListLineCoverageDTO getLineCoverages() { return lineCoverages; } public void setLineCoverages(ListLineCoverageDTO lineCoverages) { this.lineCoverages lineCoverages; } } public static class LineCoverageDTO { private int lineNum; private String lineStatus; private BranchCoverageDTO branchCoverage; // getter/setter public int getLineNum() { return lineNum; } public void setLineNum(int lineNum) { this.lineNum lineNum; } public String getLineStatus() { return lineStatus; } public void setLineStatus(String lineStatus) { this.lineStatus lineStatus; } public BranchCoverageDTO getBranchCoverage() { return branchCoverage; } public void setBranchCoverage(BranchCoverageDTO branchCoverage) { this.branchCoverage branchCoverage; } } public static class BranchCoverageDTO { private int coveredBranches; private int totalBranches; private double branchCoverageRatio; // getter/setter public int getCoveredBranches() { return coveredBranches; } public void setCoveredBranches(int coveredBranches) { this.coveredBranches coveredBranches; } public int getTotalBranches() { return totalBranches; } public void setTotalBranches(int totalBranches) { this.totalBranches totalBranches; } public double getBranchCoverageRatio() { return branchCoverageRatio; } public void setBranchCoverageRatio(double branchCoverageRatio) { this.branchCoverageRatio branchCoverageRatio; } } // 核心方法解析.exec文件并将覆盖率数据序列化为JSON文件 public static void serializeToJson(String execPath, String classDirPath, String jsonOutputPath) throws IOException { // 1. 解析.exec文件获取全量类覆盖率数据 CoverageDTO coverageDTO parseExecToCoverageDTO(execPath, classDirPath); // 2. 使用FastJSON序列化需引入fastjson依赖 String jsonStr JSON.toJSONString(coverageDTO, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue); // 3. 写入JSON文件 try (FileWriter writer new FileWriter(jsonOutputPath)) { writer.write(jsonStr); System.out.println(JSON序列化完成文件路径 jsonOutputPath); } } // 核心方法解析.exec文件并将覆盖率数据序列化为XML文件 public static void serializeToXml(String execPath, String classDirPath, String xmlOutputPath) throws IOException, JAXBException { // 1. 解析.exec文件获取全量类覆盖率数据 CoverageDTO coverageDTO parseExecToCoverageDTO(execPath, classDirPath); // 2. 使用JAXB序列化JDK自带无需额外依赖 JAXBContext jaxbContext JAXBContext.newInstance(CoverageDTO.class); Marshaller marshaller jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 格式化输出 marshaller.setProperty(Marshaller.JAXB_ENCODING, UTF-8); // 编码 // 3. 写入XML文件 marshaller.marshal(coverageDTO, new File(xmlOutputPath)); System.out.println(XML序列化完成文件路径 xmlOutputPath); // 可选打印XML字符串 StringWriter stringWriter new StringWriter(); marshaller.marshal(coverageDTO, stringWriter); System.out.println(XML内容\n stringWriter.toString()); } // 辅助方法解析.exec文件转换为自定义CoverageDTO核心数据转换 private static CoverageDTO parseExecToCoverageDTO(String execPath, String classDirPath) throws IOException { // 1. 加载并解析.exec文件 ExecFileLoader execFileLoader new ExecFileLoader(); execFileLoader.load(new File(execPath)); CoverageBuilder coverageBuilder new CoverageBuilder(); Analyzer analyzer new Analyzer(execFileLoader.getExecutionDataStore(), coverageBuilder); analyzer.analyzeAll(new File(classDirPath)); // 2. 转换为CoverageDTO CoverageDTO coverageDTO new CoverageDTO(); // 2.1 转换会话信息 SessionInfoStore sessionInfoStore execFileLoader.getSessionInfoStore(); if (!sessionInfoStore.getInfos().isEmpty()) { SessionDTO sessionDTO new SessionDTO(); var sessionInfo sessionInfoStore.getInfos().iterator().next(); sessionDTO.setSessionId(sessionInfo.getId()); sessionDTO.setStartTime(sessionInfo.getStartTime()); sessionDTO.setEndTime(sessionInfo.getDumpTime()); coverageDTO.setSession(sessionDTO); } // 2.2 转换类覆盖率数据 CollectionIClassCoverage classCoverages coverageBuilder.getClasses(); ListClassCoverageDTO classCoverageDTOList new ArrayList(); for (IClassCoverage classCoverage : classCoverages) { ClassCoverageDTO classDTO new ClassCoverageDTO(); classDTO.setClassName(classCoverage.getName()); classDTO.setFullClassName(classCoverage.getPackageName() . classCoverage.getName()); classDTO.setLineCoverage(Math.round(classCoverage.getLineCoverage() * 10000) / 100.0); // 保留两位小数 classDTO.setBranchCoverage(Math.round(classCoverage.getBranchCoverage() * 10000) / 100.0); classDTO.setMethodCoverage(Math.round(classCoverage.getMethodCoverage() * 10000) / 100.0); classDTO.setCoveredLines(classCoverage.getCoveredLines()); classDTO.setTotalLines(classCoverage.getLines()); // 转换方法覆盖率数据 ListMethodCoverageDTO methodDTOList new ArrayList(); for (IMethodCoverage methodCoverage : classCoverage.getMethods()) { MethodCoverageDTO methodDTO new MethodCoverageDTO(); methodDTO.setMethodName(methodCoverage.getName()); methodDTO.setMethodDesc(methodCoverage.getDesc()); methodDTO.setLineCoverage(Math.round(methodCoverage.getLineCoverage() * 10000) / 100.0); methodDTO.setBranchCoverage(Math.round(methodCoverage.getBranchCoverage() * 10000) / 100.0); methodDTO.setFirstLine(methodCoverage.getFirstLine()); methodDTO.setLastLine(methodCoverage.getLastLine()); // 转换行覆盖率数据 ListLineCoverageDTO lineDTOList new ArrayList(); for (int lineNum methodCoverage.getFirstLine(); lineNum methodCoverage.getLastLine(); lineNum) { var lineCoverage methodCoverage.getLine(lineNum); if (lineCoverage ! null) { LineCoverageDTO lineDTO new LineCoverageDTO(); lineDTO.setLineNum(lineNum); lineDTO.setLineStatus(getLineStatusDesc(lineCoverage.getStatus())); // 转换分支覆盖率数据仅分支行 if (lineCoverage.getBranchCoverage() ! null) { var branchCoverage lineCoverage.getBranchCoverage(); BranchCoverageDTO branchDTO new BranchCoverageDTO(); branchDTO.setCoveredBranches(branchCoverage.getCoveredBranches()); branchDTO.setTotalBranches(branchCoverage.getTotalBranches()); branchDTO.setBranchCoverageRatio(Math.round(branchCoverage.getCoverageRatio() * 10000) / 100.0); lineDTO.setBranchCoverage(branchDTO); } lineDTOList.add(lineDTO); } } methodDTO.setLineCoverages(lineDTOList); methodDTOList.add(methodDTO); } classDTO.setMethodCoverages(methodDTOList); classCoverageDTOList.add(classDTO); } coverageDTO.setClassCoverages(classCoverageDTOList); return coverageDTO; } // 辅助方法行状态码转描述 private static String getLineStatusDesc(int status) { return switch (status) { case 0 - 未覆盖; case 1 - 部分覆盖; case 2 - 完全覆盖; default - 未知; }; } // 测试序列化覆盖率数据 public static void main(String[] args) throws IOException, JAXBException { // 依赖说明JSON序列化需引入fastjson依赖 // dependency // groupIdcom.alibaba/groupId // artifactIdfastjson/artifactId // version2.0.44/version // /dependency // 1. 序列化为JSON serializeToJson(target/jacoco.exec, target/classes, target/coverage-report.json); // 2. 序列化为XML注释掉上面打开下面测试 // serializeToXml(target/jacoco.exec, target/classes, target/coverage-report.xml); } }3.5import org.jacoco.report.*; import org.jacoco.report.html.HTMLFormatter; import java.io.*; import java.util.*; public class HtmlReportGenerator { /** * 生成HTML格式的覆盖率报告 */ public static void generateHtmlReport( ExecutionDataStore executionData, File classesDirectory, File sourceDirectory, File reportDirectory) throws IOException { // 1. 创建报告生成器 final CoverageBuilder coverageBuilder new CoverageBuilder(); final Analyzer analyzer new Analyzer(executionData, coverageBuilder); // 2. 分析所有类文件 analyzeAllClasses(analyzer, classesDirectory); // 3. 创建HTML格式化器 HTMLFormatter htmlFormatter new HTMLFormatter(); IReportVisitor visitor htmlFormatter.createVisitor( new FileMultiReportOutput(reportDirectory)); // 4. 设置报告信息 visitor.visitInfo( executionData.getContents(), executionData.getSessionInfo() ); // 5. 生成报告 visitor.visitBundle( coverageBuilder.getBundle(MyApplication), new DirectorySourceFileLocator( sourceDirectory, UTF-8, 4 ) ); visitor.visitEnd(); } /** * 递归分析所有类文件 */ private static void analyzeAllClasses( Analyzer analyzer, File directory) throws IOException { for (File file : directory.listFiles()) { if (file.isDirectory()) { analyzeAllClasses(analyzer, file); } else if (file.getName().endsWith(.class)) { analyzer.analyzeAll(file); } } } /** * 生成详细的类级别报告 */ public static void generateClassReport( ExecutionDataStore data, File classFile, String className, File outputFile) throws IOException { // 分析单个类 CoverageBuilder builder new CoverageBuilder(); Analyzer analyzer new Analyzer(data, builder); analyzer.analyzeClass(new FileInputStream(classFile), className); // 获取类覆盖率 IClassCoverage classCoverage builder.getClasses().stream() .filter(c - c.getName().equals(className)) .findFirst() .orElse(null); if (classCoverage ! null) { // 生成类级别的详细报告 generateClassDetailsReport(classCoverage, outputFile); } } private static void generateClassDetailsReport( IClassCoverage coverage, File outputFile) throws IOException { try (PrintWriter writer new PrintWriter(outputFile)) { writer.println(Class: coverage.getName()); writer.println(); writer.printf(Line Coverage: %.2f%%\n, coverage.getLineCounter().getCoveredRatio() * 100); writer.printf(Branch Coverage: %.2f%%\n, coverage.getBranchCounter().getCoveredRatio() * 100); writer.printf(Method Coverage: %.2f%%\n, coverage.getMethodCounter().getCoveredRatio() * 100); writer.println(\nLine Details:); writer.println(Line | Status | Missed Branches); writer.println(-----|--------|----------------); for (int i coverage.getFirstLine(); i coverage.getLastLine(); i) { int status coverage.getLine(i).getStatus(); String statusStr getStatusString(status); writer.printf(%4d | %6s | %d\n, i, statusStr, coverage.getLine(i).getBranchCounter().getMissedCount()); } } } private static String getStatusString(int status) { switch (status) { case ICounter.NOT_COVERED: return MISSED; case ICounter.PARTLY_COVERED: return PARTIAL; case ICounter.FULLY_COVERED: return COVERED; default: return EMPTY; } } } - ## 4.2 序列化关键说明 - 自定义DTO由于JaCoCo原生接口如IClassCoverage是接口类型且部分方法不支持序列化因此定义了一套与原生数据对应的DTO类如CoverageDTO、ClassCoverageDTO用于数据转换和序列化。 - JSON序列化使用FastJSON实现支持格式化输出、空值保留等特性需引入FastJSON依赖。 - XML序列化使用JDK自带的JAXB实现无需额外依赖通过Marshaller将DTO对象转换为XML格式并写入文件。 - 数据精度对覆盖率百分比进行四舍五入处理保留两位小数便于阅读。 ## 4.3 序列化输出示例JSON Plain Text { session: { sessionId: default, startTime: 1735689600000, endTime: 1735689660000 }, classCoverages: [ { className: TargetService, fullClassName: com.example.TargetService, lineCoverage: 85.71, branchCoverage: 75.00, methodCoverage: 100.00, coveredLines: 12, totalLines: 14, methodCoverages: [ { methodName: doBusiness, methodDesc: (Ljava/lang/String;)Ljava/lang/String;, lineCoverage: 83.33, branchCoverage: 66.67, firstLine: 10, lastLine: 25, lineCoverages: [ { lineNum: 10, lineStatus: 完全覆盖, branchCoverage: null }, { lineNum: 12, lineStatus: 部分覆盖, branchCoverage: { coveredBranches: 2, totalBranches: 3, branchCoverageRatio: 66.67 } } ] } ] } ] }字节码一致性解析时使用的原始字节码.class文件必须与生成.exec文件时的字节码完全一致即同一版本的代码否则会导致解析失败或覆盖率数据不准确。依赖版本匹配JaCoCo API版本需与生成.exec文件的JaCoCo插件版本一致如均使用0.8.11避免因版本差异导致的文件格式不兼容。类加载路径解析单个类时需确保目标类的字节码可通过类加载器获取批量解析时指定的类目录如target/classes需正确且包含所有需要解析的.class文件。序列化兼容性若需长期存储序列化后的覆盖率数据建议使用稳定的序列化框架如FastJSON、JAXB并固定DTO类结构避免后续版本变更导致反序列化失败。性能优化批量解析大量类时建议分批次解析避免一次性加载过多字节码导致内存溢出序列化大体积覆盖率数据时可采用流式写入如FileWriter减少内存占用。六、参考资料JaCoCo 官方API文档https://www.jacoco.org/jacoco/trunk/doc/api/JaCoCo 官方.exec文件格式说明https://www.jacoco.org/jacoco/trunk/doc/execution-data.html
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

网站轮换图网络运营是干嘛的

文章目录摘要主要技术与实现手段系统设计与实现的思路系统设计方法java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!摘要 随着移动互联网的普及,高校校园活动的组织与管理逐渐向数字化、智能化方向发…

张小明 2026/1/5 0:46:25 网站建设

英语网站都可以做哪些内容wordpress 转跳到登录

第11.4节 混合储能系统能量管理 11.4.1 多时间尺度能量管理策略 混合储能系统(HESS)的能量管理策略(EMS)是其实现技术经济性优势的智能中枢。该策略的核心任务是根据外部功率需求Pdemand(t)P_{demand}(t)P

张小明 2026/1/5 0:45:53 网站建设

湖南系统建站怎么用城乡和住房建设厅网站首页

抖音视频批量下载终极指南:三步搞定海量内容保存 【免费下载链接】douyinhelper 抖音批量下载助手 项目地址: https://gitcode.com/gh_mirrors/do/douyinhelper 还在为一个个手动保存抖音视频而烦恼吗?无论是内容创作者需要收集素材,还…

张小明 2026/1/5 0:45:21 网站建设

提供网站建设排行榜设计参考图哪个网站好

云端办公利器:Acrobat.com 与 Google 工具全解析 在当今数字化办公的浪潮中,云服务为我们的工作和生活带来了极大的便利。Acrobat.com 和 Google 工具是其中备受关注的两类,下面将为大家详细介绍它们的特点和使用方法。 1. Acrobat.com 概述 Acrobat.com 是一套出色的生产…

张小明 2026/1/6 2:33:19 网站建设

服务器做网站用什么系统手机网站版面设计

如何用LPrint实现全平台标签打印?开源解决方案终极指南 【免费下载链接】lprint A Label Printer Application 项目地址: https://gitcode.com/gh_mirrors/lp/lprint 在数字化办公环境中,跨平台标签打印一直困扰着众多企业和个人用户。不同操作系…

张小明 2026/1/6 6:09:46 网站建设

网站栏目英文WordPress二级目录文章404

终极指南:5分钟快速上手Ocrad.js免费OCR识别 【免费下载链接】ocrad.js OCR in Javascript via Emscripten 项目地址: https://gitcode.com/gh_mirrors/oc/ocrad.js Ocrad.js是一个基于Emscripten编译的JavaScript光学字符识别库,让你在浏览器中轻…

张小明 2026/1/5 0:43:45 网站建设