There are many blog entries and articles out there about web service versioning. So why write another? In my day-to-day work, I am often asked about how to solve web service versioning issues. The articles on the web provide different ways to do it, but do not take the impact on the codebase, deployment and testing into consideration. Now that’s exactly what I’ll be trying to do in this article.

First, I’ll briefly describe what I mean with Web Service versioning. Then, I’ll shed some light on different possible solutions. Finally, I’ll compare all of these solutions in terms of complexity, codebase, deployment and testing.

Web service versioning, real or just a myth?

Many, maybe even all, projects that involve web services will encounter a problem they call “web service versioning”. But what is it? And does it really exist?

A web service is a piece of code, published under a more or less strict contract (WSDL and XSD), that can be called by other pieces of code across the web. This contract poses a problem, because your users depend on this contract to communicate with your application. If your request or response message format changes, it will most probably break the contract, causing your clients to send invalid messages and being unable to parse your responses.

So, if you change the contract, are we still talking about the same service? Or is it just another service you are providing? In terms of web services, it will be just another service. However, developers think in terms of code and classes. Since the major part of the codebase will be the same for the new service, we like to think of it as a new version. So, web service versioning doesn’t really exist, but we want our classes to be reused. Now we’ve put our finger on the sore spot.

Why versioning web services is an issue

Web Service versioning doesn’t exist. So why is it an issue? Because developers (myself included) want to be able to reuse existing classes for new versions of a service. So, in our Version Control System (VCS, e.g. Subversion or CVS) repository weÂ?ll want to create a branch for the old version, and continue development in our main branch. We’d want to deploy our application with our old JAR and the new one and provide some mechanism for selecting either the old classes or the new ones.

That’s when class loading comes in to play and ruin our day. Java isn’t able to load the two different classes with the same name, at least, not in this case. It will load class com.mycompany.MyService from only one of both jars, whichever is first on the classpath. For java to accept different implementations of a same class, you’d have to do some class loader tricks.

Solutions for service versioning

The web is full of solutions for versioning. I’ll mention each solution briefly, and explain how it is set up. At the end of this blog entry, I will compare these solutions in terms of codebase, deployment and testing.

1. Don’t do versioning. Force clients to migrate to the newest version available.This is often tried as the first solution, but will most likely fail. Often, client applications are managed by another project, not in the area of influence of the project developing the web service provider. The cons are mostly financial: who’s going to pay for the migration of the client? I’m not going into more detail on this solution, as it doesn’t solve the versioning problem.

2. Deploy another EAR file containing the new version of the web service, leaving the old application untouched.In terms of development and maintenance of the codebase, this is the easiest solution. Just create a branch in your VCS for the old version and continue the development in the main branch. Since the old application is totally unmodified, it doesn’t have to be tested when a new version is created. However, your deployers will have to deploy and maintain one applications per supported version.
In case of bug fixes, there is another choice to be made. Will the bug be fixed in each version, or just in the latest one. In the first case, the code has to be changed in several locations in you repository. Fortunately, today’s VCS tools (e.g. TortoiseSVN) allow you to easily merge changes across branches. Then, testers have to test each modified application and the deployer has to redeploy them.

In conclusion, this solution is easy for the developers, but has more impact on testers and deployers.

3. Deploy a single EAR file, with a WAR file per versionBeware! For this solution to work, all version specific code should be placed in the WEB-INF/lib dir of your WAR file, and each WAR file must have its own class loader.

Just like the previous solution, you can create a branch in your VCS and merge changes across branches. However, a change in one version of the code will change the composition of the entire EAR file, and thus affect other versions, even if the specifications of that version haven’t changed. This means that there is no way to guarantee that old versions are unaffected by changes in newer versions. This puts some extra load on the testers. The deployers however will only have to deploy and maintain a single application, regardless of the number of versions it supports.

4. Use different package names for each versionOn several blog sites, this solution is provided as "the one" to use. If you take java out of the equation, it might be very interesing, because your request and response messages are very clear about the version of the service. However, in the real world, developers use binding frameworks such as jaxb or augis. This would mean different package names (and rewriting code) for each version. This makes solution the worst of all for developers, as the entire codebase has to be changed for each new version.

I am not going into detail about this solution, because it is not a solution to the “versioning” problem. Here, we are just creating a completely new service, with all new classes. No resuse. However, do take this option into consideration for at least a few minutes. Depending on the size of your codebase, it might just not be such a bad solution.

5. Use a framework that supports advanced class loadingPeople who know me would probable wonder by now: “When will he mention OSGi”?. Well, just about now. Frameworks that implement the OSGi specification (e.g. Equinox, Knoplerfish and Felix), are able to load different implementations of the same class, and understand the difference between them. Jettro Coenradie and I have given a presentation on Web Service versioning using OSGi that the Spring 2007 conference (see http://www.nljug.org/pages/events/content/jspring_2007/sessions/00003/). We’ve also dedicated a website to provide information on the subject: http://www.osgisamples.com.

This solution is probably the most difficult one to implement. It is most likely that neither the developers, nor the testers and deployers have knowledge about OSGi and the impact on their work. However, if this knowledge is available to your project, make sure to consider this solution.

Comparing the solutions

Now that I have mentioned each solution briefly, it is time to put them in the ring to compete against each other. Here we go:

EAR versioning
(endpoint versioning)

WAR versioning
(endpoint versioning)

Package versioning
(namespace versioning)

OSGi
(any type of versioning you like)

How the versions are recognized

By endpoint

Either the EARs will be deployed on different app servers, or the WARs inside will have different contexts

By endpoint

Each WAR in the ear wil have a different context (e.g. /services/v1 and /services/v2)

By namespace

We’re talking about different services here. The dispatching process will send each service to the appropriate class

Any way you like. You have complete influence on the dispatching process.

Complexity to set up

No specific set up to be done. Make sure to use a VCS.

Slightly complex. Use e.g. maven to build the WAR files and include the necessary versions in your EAR. Make sure version specific classes and jars are included inside the WAR.

Not complex at all to set up, but each new version will require you to create new classes or rename the old ones.

Consider each new version as a completely new service in your web service dispatcher

Very complex for beginners. OSGi introduces some extra features and a different mindset than Â?normalÂ? java programming.

Impact on codebase, bug fixing and maintenance

Little impact. Keep in mind that each fixed version will have to be redeployed. Use your VCS tools to merge changes across branches.

Little impact. Each modified version will have to be rebuilt and each WAR included in the EAR file. Use your VCS tools to merge changes across branches.

Huge impact. The amount of classes will double with each version. Merging across branches is no longer possible, since class names are different.

You application will have to be set up in a modular fashion. If it already is, the impact on your codebase is small. You can use VCS tools to merge changes, since class names donÂ?t change.

Impact on deployment effort

Highest impact on deployers. Each version requires an extra EAR to be maintained.

Small impact on deployers. There is only a single EAR file to deploy and maintain.

Small impact on deployers. There is only a single EAR file to deploy and maintain.

Small impact on deployers. There is only a single EAR file to deploy and maintain.

Impact on testers

Small impact. Old versions are remained intact when deploying new versions.

Big impact. It is hard to guarantee that old versions are remained intact upon deployment of a new version.

Big impact. It is hard to guarantee that old versions are remained intact upon deployment of a new version.

Big impact. It is hard to guarantee that old versions are remained intact upon deployment of a new version.

Flexibility

Very high. Since versions are completely separate, changes in one version do not affect the other.

High. Because all versions share a common (EAR) class loader, there are some limitations. Especially when using native code.

Low. All versions must use the same shared libraries, as all versions share a single class loader.

Very high. The versioning and dispatching mechanism is completely configurable to your projects needs. Each version of the web service can depend on different versions of external libraries.

Web service versioning in the java world