检测 Java 项目中的循环引用

随着Java项目变得越来越大,并且有多个开发人员在进行工作,这可能导致代码具有循环引用。因此使用循环引用序列化对象是很苦难的。我创建了一个工具来检测Java项目中的循环引用:循环引用检测器Gitlab源代码。以下是检测Java项目中的循环引用所采取的步骤。

计划目标

  • 输入:Java项目的源文件的路径。
  • 输出:包含循环引用的每个类的循环图的图像文件的文件夹。

步骤

  • 使用Java解析器,解析给定源目录中的每个Java文件,并使用JgraphT在有向图中收集类的引用
  • 使用JgraphT的 CycleDetector检测图中每个顶点的周期
  • 使用jgrapht-ext库将图形存储为PNG文件

代码段

解析源目录中的Java文件,并将类引用添加到图形中。

Graph<String, DefaultEdge> classReferencesGraph = new DefaultDirectedGraph<>(DefaultEdge.class);
try (Stream<Path> filesStream = Files.walk(Paths.get(srcDirectory))) {
    filesStream             
    .filter(path -> path.getFileName().toString().endsWith(".java"))
    .forEach(path ->{
        Set<String> instanceVarTypes = getInstanceVarTypes(path.toFile());
        if( ! instanceVarTypes.isEmpty()) {                     
            String className = getClassName(path.getFileName().toString());
            classReferencesGraph.addVertex(className);
            instanceVarTypes.forEach(classReferencesGraph::addVertex);
            instanceVarTypes.forEach( var -> classReferencesGraph.addEdge(className, var));
        }
    });
}
 

使用Java解析器收集类的实例变量

CompilationUnit compilationUnit = StaticJavaParser.parse(javaSrcFile);      
List<Node> instanceVarTypes = compilationUnit.findAll(FieldDeclaration.class)
    .stream()
    .map(f -> f.getVariables().get(0).getType())
    .filter(v -> !v.isPrimitiveType())
    .map( Object::toString)
    .collect(Collectors.toSet());
 

使用地图创建有向图

Graph<String, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);       
//add vertices
classNametoInstanceVarTypesMap.keySet().forEach(className ->{           
  graph.addVertex(className);
});
//add edges
classNametoInstanceVarTypesMap
  .forEach((className , instanceVariableTypes) -> {
      instanceVariableTypes.forEach( instVar -> {
        if (classNametoInstanceVarTypesMap.containsKey(instVar)){
          graph.addEdge(className, instVar);
        }           
    });
});
 

使用JGraphT CycleDetector检测图中每个顶点的周期,并将周期添加到地图。

Map<String, AsSubgraph<String, DefaultEdge>> cyclesForEveryVertexMap = new HashMap<>();
CycleDetector<String, DefaultEdge> cycleDetector = new CycleDetector<>(classReferencesGraph);
cycleDetector.findCycles().forEach(v -> {
    AsSubgraph<String, DefaultEdge> subGraph = new AsSubgraph<>(classReferencesGraph,
            cycleDetector.findCyclesContainingVertex(v));
    cyclesForEveryVertexMap.put(v,subGraph);
});
 
  • findCyclesContainingVertex(vertex)返回参与顶点循环的一组顶点。使用这些顶点创建主图的子图。

使用jgrapht-ext库创建图的PNG图像。

new File(outputDirectoryPath).mkdirs();
File imgFile = new File(outputDirectoryPath+"/graph" + imageName + ".png");
if(imgFile.createNewFile()) {
    JGraphXAdapter<String, DefaultEdge> graphAdapter = new JGraphXAdapter<>(subGraph);
    mxIGraphLayout layout = new mxCircleLayout(graphAdapter);
    layout.execute(graphAdapter.getDefaultParent());
 
    BufferedImage image = mxCellRenderer.createBufferedImage(graphAdapter, null, 2, Color.WHITE, true, null);
    if (image != null) {
        ImageIO.write(image, "PNG", imgFile);
    }
}
 

样本输出图形图像

原文链接:https://dev.to//nikhilpereira1793/detecting-circular-references-in-a-java-project-32fd

你可能感兴趣的:(检测 Java 项目中的循环引用)