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
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
- Optionally reads the parameters for each
- Optionally will include the return type of each method
- Adds a
Stringfor each method to one of two
- 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
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.
This particular method will do the comparison and output a text version of the intersection and bi-directional difference of
StringBuilder classes. Because I have used the default constructor, method parameter types and return types are excluded from the comparison.
Now, let’s compare the output when we include the parameters in the methods.
Here’s the output with the method parameters included.
The classes still look identical. So let’s include return types, by setting the second flag in the
ClassComparer constructor to
Now the output looks much different.
Many of the method signatures return either
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
Including parameter types
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.
First, let’s compare the method signatures for
RichIterable from a purely conceptual view. We can do this just by using the constructor with no parameter on
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.
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.
Look what happens to the text output when we add parameter types and return types to the methods in the comparison.
As we can see, there are quite a few methods overloaded in the Eclipse Collections
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 is potentially more useful for this particular comparison, since scrolling is required in both cases.
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.
eclipse-collections/ClassComparer.java at master · eclipse/eclipse-collections
Eclipse Collections is a collections framework for Java with optimized data structures and a rich, functional and…
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.
Graduating from Minimal to Rich Java APIs
Combining ease of learning with reduced code duplication for greater productivity.
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
The 2021 Java Programmer RoadMap
An illustrated guide to becoming a Java Developer in 2021 with links to relevant courses
11 Advanced Core Java Online Courses to Join in 2021
These are the best online courses for core java developers to learn skills like multithreading, Collections, JVM…