По мере роста проектов Java, над которыми работают несколько разработчиков, это может привести к тому, что код будет иметь циклические ссылки. Трудно сериализовать объекты с циклическими ссылками. Я создал инструмент для обнаружения циклических ссылок в проекте Java: Детектор циклических ссылок Исходный код Gitlab . Ниже приведены шаги, предпринятые для обнаружения циклических ссылок в проекте Java.
Цель программы
- Ввод : Путь к исходным файлам проекта Java.
- Вывод : Папка, содержащая файлы изображений циклических графиков для каждого класса, имеющего циклические ссылки.
Шаги
- Используя Синтаксический анализатор Java , проанализируйте каждый файл Java в данном исходном каталоге и соберите ссылки на класс в ориентированном графе с помощью JGraphT
- Определите циклы для каждой вершины в графике с помощью JGraphT Детектор циклов
- Храните графики в виде файлов PNG с помощью библиотеки jgrapht-ext
Фрагменты Кода
Проанализируйте файлы Java в исходном каталоге и добавьте ссылки на классы в график.
GraphclassReferencesGraph = new DefaultDirectedGraph<>(DefaultEdge.class); try (Stream filesStream = Files.walk(Paths.get(srcDirectory))) { filesStream .filter(path -> path.getFileName().toString().endsWith(".java")) .forEach(path ->{ Set 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); ListinstanceVarTypes = compilationUnit.findAll(FieldDeclaration.class) .stream() .map(f -> f.getVariables().get(0).getType()) .filter(v -> !v.isPrimitiveType()) .map( Object::toString) .collect(Collectors.toSet());
Создание ориентированного графика с помощью Карты
Graphgraph = 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); } }); });
Определите циклы для каждой вершины графика с помощью графического детектора циклов и добавьте циклы на карту.
Map> cyclesForEveryVertexMap = new HashMap<>(); CycleDetector cycleDetector = new CycleDetector<>(classReferencesGraph); cycleDetector.findCycles().forEach(v -> { AsSubgraph subGraph = new AsSubgraph<>(classReferencesGraph, cycleDetector.findCyclesContainingVertex(v)); cyclesForEveryVertexMap.put(v,subGraph); });
найти циклы, содержащие вершину (вершина)
возвращает набор вершин, участвующих в цикле для вершины. Создайте подграф основного графа, используя эти вершины.
Создайте изображение графика в формате PNG с помощью библиотеки jgrapht-ext.
new File(outputDirectoryPath).mkdirs(); File imgFile = new File(outputDirectoryPath+"/graph" + imageName + ".png"); if(imgFile.createNewFile()) { JGraphXAdaptergraphAdapter = 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”