Javaプロジェクトでの循環参照の検出
18588 ワード
Javaプロジェクトがますます大きくなり、複数の開発者が作業しているため、コードに循環参照がある可能性があります.したがって,ループリファレンスを用いてオブジェクトをシーケンス化することは困難である.Javaプロジェクトの循環参照を検出するツールを作成しました.循環参照検出器Gitlabソースコードです.Javaプロジェクトのループ参照を検出するには、次の手順に従います.
計画目標 Javaプロジェクトのソースファイルのパスを入力します. 出力:ループ参照の各クラスのループ図を含む画像ファイルのフォルダ.
ステップ Java解析器を使用して、所与のソースディレクトリ内の各Javaファイルを解析し、JgraphTを使用して図に収集するクラスの参照 がある. JgraphTのCycleDetectorを用いて図中の各頂点の周期 を検出する. jgrapht-extライブラリを使用してPNGファイル としてグラフィックを格納する.
コードセグメント
ソースディレクトリのJavaファイルを解析し、クラスリファレンスをグラフィックに追加します.
Java解析器を使用してクラスのインスタンス変数を収集する
地図を使って有向図を作成する
JGraphT CycleDetectorを使用して、図の各頂点の周期を検出し、地図に周期を追加します.
jgrapht-extライブラリを使用して、図のPNG画像を作成します.
サンプル出力グラフィック画像
テキストリンク:https://dev.to//nikhilpereira1793/detecting-circular-references-in-a-java-project-32fd
計画目標
ステップ
コードセグメント
ソースディレクトリの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