How to introspect and find conceptual symmetry between classes in Java

Donald Raab
Nov 15 · 8 min read

Demonstrating ClassComparer, a utility class built with Eclipse Collections.

Photo by Jack French on Unsplash

A challenge with rich APIs

Rich APIs can be great. They can significantly reduce the duplication of code by providing many useful common behaviors. Sometimes there are different implementations of classes that have a similar rich set of method signatures. Some classes in Java are conceptually equivalent, even if they don’t share a common parent abstraction that defines that behavior.

The problem is that we as humans sometimes need help determining and understanding the subtle differences between classes that are conceptually the same. Parsing and comparing the text in Java source files or Javadoc that may be hundreds of lines long is laborious and error prone. Sometimes we miss things. Computers can help us here so we can identify and understand patterns.

Eclipse Collections is a library that has a primary design goal of providing good symmetry in its API. This goal is extremely challenging to achieve, given the size of the Eclipse Collections API. The Eclipse Collections API has grown so much in the past 18 years, I’ve needed some help to fully understand it.

A solution for comparing classes

A few years ago, I wrote some code in a utility class for comparing the method signatures in two classes. The utility leverages the methods available in Java to introspect classes along with data structures and algorithms available in Eclipse Collections to compare the methods.

There is nothing spectacularly amazing about the utility I wrote that compares classes. I have shared earlier versions of the source code in a previous blog (linked towards the end). It wasn’t until recently when I had to copy the code to my current Eclipse Collections project and modify it in order to compare IntIterable and RichIterable that I decided it would be useful to include it in the Eclipse Collections eclipse-collections-testutils module so I can easily use it in any project where I may need to compare rich APIs.

The utility does the following:

  • Reads the methods of each Class using getMethods
  • Optionally reads the parameters for each Method using getParameters
  • Optionally will include the return type of each method
  • Adds a String for each method to one of two MutableSortedSet instances
  • Calculates the intersection of the two sets of methods
  • Calculates the differences of the two sets of methods in both directions
  • Outputs the methods sorted alphabetically and groups them by their first letter

There are a few other useful methods on the utility class named ClassComparer, but this is its primary purpose.

Keep it simple

The utility creates the equivalent of a Venn Diagram between the method signatures of two classes. The clever part, if there is any, is that the utility class will allow you to optionally include parameter types and return types in the method signature comparison. By excluding parameter types and return types, we are able to determine if two classes have good conceptual symmetry by simply comparing the method names.

A simple comparison

As a first example of a comparison, I will compare StringBuffer and StringBuilder. Note: I was using this code in my local Eclipse Collections project, which is currently using Java 8. StringBuilder was introduced as a drop-in replacement for StringBuffer in Java 5, so we would expect them to have identical method signatures. Conceptually, they are identical. When we dig deeper into the details, we will see that they have subtle differences.

Here’s the code required to compare the two classes, excluding parameter types or return types.

Compare StringBuffer.class and StringBuilder.class

This particular method will do the comparison and output a text version of the intersection and bi-directional difference of StringBuffer and StringBuilder classes. Because I have used the default constructor, method parameter types and return types are excluded from the comparison.

Output of intersection and differences between StringBuffer and StringBuilder

Now, let’s compare the output when we include the parameters in the methods.

Setting the first flag to true enables the inclusion of method parameter types

Here’s the output with the method parameters included.

Output comparing StringBuffer and StringBuilder with parameter types

The classes still look identical. So let’s include return types, by setting the second flag in the ClassComparer constructor to true.

Setting the second flag to true enables the inclusion of method return types

Now the output looks much different.

Output comparing StringBuffer and StringBuilder with parameter and return types

Many of the method signatures return either StringBuffer or StringBuilder. There is a parent abstraction for both named AbstractStringBuilder which defines many of the methods like append that are called from the two subclasses and are overridden to return a the specific return type. This is why the number of methods grew significantly in the bi-directional difference.

An experimental Swing UI

I decided to build a quick prototype Swing UI to display the intersection and differences for ClassComparer. The Swing UI is nicer for quickly comparing the differences, as it uses a three pane list view which more or less emulates a Venn Diagram, just without the overlapping circles.

Here’s what the Swing UI looks like comparing the two classes above.

Excluding parameter and return types

Swing UI comparing StringBuffer and StringBuilder excluding parameter and return types

Including parameter types

Swing UI comparing StringBuffer and StringBuilder including parameter types only

Including parameter and return types

Swing UI comparing StringBuffer and StringBuilder including parameter and return types

Finding asymmetry in the Eclipse Collections API

To illustrate how a developer working on Eclipse Collections can use this utility to find potential work to complete in the space of improving symmetry, I will compare a primitive collection interface with its equivalent on the object side.

IntIterable vs. RichIterable

First, let’s compare the method signatures for IntIterable and RichIterable from a purely conceptual view. We can do this just by using the constructor with no parameter on ClassComparer.

Compare IntIterable and RichIterable interfaces

The output shows some interesting differences between the primitive collection parent type and the object collection parent type even at the conceptual level. Conceptual symmetry is the most important concern we have in Eclipse Collections. We clearly have plenty of work to do in this space.

The output comparing IntIterable and RichIterable interfaces

Looking at the same output in the experimental Swing UI shows one of the strengths of the text output that groups methods by their first letter. There is no need to scroll in the text output, where with the three pane Swing UI, all methods do not fit on the screen so scrolling is required.

The Swing UI comparing IntIterable and RichIterable

Look what happens to the text output when we add parameter types and return types to the methods in the comparison.

Part 1 of the output comparing IntIterable and RichIterable including parameter and return types
Part 2 of the output comparing IntIterable and RichIterable including parameter and return types

As we can see, there are quite a few methods overloaded in the Eclipse Collections RichIterable and IntIterable interfaces. Using the conceptual view without method parameter and return types hides this detail. This detail is important, so both views have value.

This is what the Swing UI looks like for this larger comparison.

The Swing UI comparing IntIterable and RichIterable including parameter and return types

The Swing UI is potentially more useful for this particular comparison, since scrolling is required in both cases.

Stay tuned

The code for ClassComparer will be available in the Eclipse Collections 11.0 release which is due out soon. It is located in the eclipse-collections-testutils module. If you want to see the code, it is now available in the Eclipse Collections repo linked below.

An older version of the code exists in the following blog, which is where I first started exploring how I could more easily understand the differences between rich APIs.

I’ve used the ClassComparer utility to produce all of the examples in this blog. The Swing UI code which is part of a separate class is not included yet in Eclipse Collections. I need to discuss the potential inclusion of the swing code with the other Eclipse Collections committers. It would be unique for Eclipse Collections eclipse-collections-testutils module to include any UI code, so I can’t make any promises on it arriving there. For now, here is a gist with the code for the experimental Swing UI.

I hope you found this useful. Thanks for reading!

I am a Project Lead and Committer for the Eclipse Collections OSS project at the Eclipse Foundation. Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.

Other Java Resource articles you may like to explore

Javarevisited

Medium’s largest Java publication, followed by 13500+ programmers. Follow to join our community.