Kevin Bourrillion mentioned the library's Preconditions class that is closely related to Apache's Validate or Java 7's Objects. Basically all three implementations provide means to check preconditions. This is especially useful to check passed in arguments to fail-fast. At smartics we provided our own version of argument checking some time ago. It is called Arguments and is especially helpful to check for non-null or non-blank values.
The Idea for a Change
There is an interesting feature in Google's
Preconditions class that we do not cover in our library: It returns the checked value. This makes it possible to reformulate the following
This makes the code half as long.
Returning the value also allows to use the check in constructor chaining situations. It may get ugly, but in some situations it may make the failure condition more clear:
This might get a better message in the exception if
Whatever simply refers to a string, since the constructor above still ‘knows’ the name of the parameter to include it in the error message.
Now go for it!
Both scenarios I want to support in the next version of our library. I still want to stick to our version of the argument checking helper class, because I often have to check for argument values not being blank.
So all I have to do is return the passed in argument? “Wrong!” you shout and you are right.
If I change
This change does not break the source code. But I introduce an incompatible change with the previous version that occurs at runtime. This is because changing the return value requires the compiler to create a new method and removing the old. So the change is not binary compatible.
The relevant part in the Java Language Specification:
Changing the result type of a method, replacing a result type with void, or replacing void with a result type has the combined effect of deleting the old method and adding a new method with the new result type or newly void result (see §13.4.12).
For purposes of binary compatibility, adding or removing a method or constructor m whose return type involves type variables (§4.4) or parameterized types (§4.5) is equivalent to the addition (respectively, removal) of the an otherwise equivalent method whose return type is the erasure (§4.6) of the return type of m.Java Language Specification, 13.4.15 Method Result Type
For more information about this topic, please refer to polygenelubricants‘s answer to the question Retrofitting void methods to return its argument to facilitate fluency: breaking change? on StackOverflow.
The report for the incompatible change looks like this on the Clirr report on the project’s Maven Site:
The fix in our case is quite easy if you control all dependent projects: You simply have to recompile. No source code change is required. But in reality this is not feasible. Either you do not have all dependent binaries in your control or you just do not have the resources to recompile and test them all. So the solution to this problem is to be found elsewhere.
Do not break Things
For libraries we have to be very sensitive to changes that break the API. In larger projects there may be a couple of modules that depend on the same library and if there is a change that broke the API all modules have to grade up to work properly together again. Therefore for e.g. Apache makes it easy to use their version 3 of commons-lang alongside with their version 2.
First they provided a new artifact ID:
This allows Maven to resolve a dependency set that includes both libraries. This way some modules can use the new version and other modules can update as soon as they want to.
To succeed in this, the package name has also be adjusted. Where in Version 2 the package for e.g. the
Validate class mentions above was
in Version 3 it is called:
So the library in version 3 can live along with any previous version, since
Validate is effectively a new class.
Mark as deprecated
But in our case we do not have to go this far. We are not planning to release a new major version any time soon. Therefore we have to introduce a new class with the new behavior. It is called
Arg. The old
Arguments class is now marked deprecated.
We inform our API users
- where the new version can be found
- why we made the change
- when this class will go out of service
The deprecation mark is translated into a warning by the compiler. If a developer is in doubt whether to use
Arg she simply has not remember which is newer. This helps to move the code towards the new version supported by the compiler.
The non-breaking change is reported in the Clirr report like this:
Everything green again. No headaches for anyone in the future.