DEV Community

nikhilpereira1793
nikhilpereira1793

Posted on

5

Detecting Circular References In A Java Project

As Java projects get bigger, with several developers working on them, it may lead to code having circular references. It is difficult to serialize objects with circular references. I have created a tool to detect circular references in a Java project : Circular Reference Detector Gitlab Source Code. Below are the steps taken to detect circular references in a Java project.

Program Goal

  • Input : Path to a Java project's source files.
  • Output : Folder containing the image files of cyclic graphs for each class having circular references.

Steps

  • Using Java Parser, parse every Java file in the given source directory and collect the references of a class in a directed graph using JgraphT
  • Detect cycles for each vertex in the graph using JgraphT's CycleDetector
  • Store graphs as PNG files using jgrapht-ext library

Code Snippets

Parse Java files in the source directory and add the class references to a graph.
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));
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

Collecting the Instance Variables of a Class using Java Parser
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());
Enter fullscreen mode Exit fullscreen mode

Create Directed Graph using Map
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);
        }           
    });
});
Enter fullscreen mode Exit fullscreen mode

Detect cycles for each vertex in the graph using JGraphT CycleDetector and add the cycles to a map.
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);
});
Enter fullscreen mode Exit fullscreen mode
  • findCyclesContainingVertex(vertex) returns set of vertices participating in the cycle for a vertex. Create a subgraph of the main graph using these vertices.

Create PNG Image of a graph using jgrapht-ext library.
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);
    }
}
Enter fullscreen mode Exit fullscreen mode

Sample Output Graph Image

Sample output graph image.


References

Image of Datadog

How to Diagram Your Cloud Architecture

Cloud architecture diagrams provide critical visibility into the resources in your environment and how they’re connected. In our latest eBook, AWS Solution Architects Jason Mimick and James Wenzel walk through best practices on how to build effective and professional diagrams.

Download the Free eBook

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

AWS Security LIVE!

Hosted by security experts, AWS Security LIVE! showcases AWS Partners tackling real-world security challenges. Join live and get your security questions answered.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️