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

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

πŸ‘‹ Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay