8

I would like to be able to compare two versions of a class / library to determine whether there have been any changes that might break code that calls it. For example consider some class Foo that has a method in version a:

public String readWidget(Object widget, Object helper);

and in version b the method becomes:

public String readWidget(Object widget); //removed unnecessary helper object

or something similar in the case of a field:

version a: public static Object sharedFoo;
version b: static Object sharedFoo; //moved to package private for version b

I would like a tool that will flag these changes as potential incompatibilities (but ideally not the reverse i.e. increasing the visibility of a method). Now I know that I can do this via reflections, or by analyzing the output from javap, however it seems like there should be an existing tool (preferably non-commercial). So I wanted to see if anyone can recommend something before I make the mistake of rolling my own / reinventing the wheel unnecessarily.

Anish Gupta
  • 2,218
  • 2
  • 23
  • 37
M. Jessup
  • 8,153
  • 1
  • 29
  • 29

3 Answers3

3

I might not be understanding the question, but isn't the compiler the exact tool that would solve this problem?

Re-compiling the classes that use Foo against the new version of Foo will illuminate very quickly if there are any incompatibilities.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • 1
    Your statement is true, however these are classes to be provided to external resources, so if it breaks their compiler will complain, and I don't want that to be a surprise to them. The idea is to not break their compatibility, basically ensuring there is sufficient time for things to be deprecated before breaking compatibility. In other words I would like to do preventive analysis before it reaches the point of compiler errors. – M. Jessup Mar 24 '11 at 14:44
2

Guava uses JDiff to report version changes, maybe you can find it useful, too?

mindas
  • 26,463
  • 15
  • 97
  • 154
  • I'm not sure this is exactly what I'm looking for but its fairly close. I have also been looking at japitools. – M. Jessup Mar 30 '11 at 17:02
2

Here's the answer you didn't want, but I think it's a valid answer:

  1. Write a suite of unit tests that invoke every single method of your API (you already have this, right? :-)).
  2. When you make an API change, recompile the new version of your API but not the unit tests.
  3. Run the "stale" set of unit tests against the "fresh" API. This stale set of tests become a canary, mimicking the situation that clients of your API would be in.

The first problem with just recompiling all client code is that it might not be possible. The code might not belong to you; it might be custom code that one of your customers has written and is not available to you.

The second problem with just recompiling client code is that sometimes, you won't even get a compilation error because the calling code doesn't need to be changed. I ran into a problem like this once. I had an API method like this:

public void doSomething(){
}

with code that linked against it. I wanted to change it to this:

public boolean doSomething() {
}

So I did so and recompiled. There were no errors, because the code that called the first version of doSomething() silently relinked to the new version (discarding the return value, which is valid in Java). Little did I know, however, that it did change the bytecode of the external class when I recompiled. We started to get errors where the API was updated but the code using it wasn't recompiled.

So instead of looking for errors, I should have also been looking at which external files had their bytecode changed as a result. At that point, I'd say you should just be using unit tests for this purpose since you should be writing them anyhow.

Mark Peters
  • 80,126
  • 17
  • 159
  • 190