WebSphere Application Server & Liberty

JSR-352 (Java Batch) Post #102: Handling Changes to Checkpoint Data

By David Follis posted Wed August 05, 2020 09:31 AM

This post is part of a series delving into the details of the JSR-352 (Java Batch) specification. Each post examines a very specific part of the specification and looks at how it works and how you might use it in a real batch application.

To start at the beginning, follow the link to the first post.

The next post in the series is here.

This series is also available as a podcast on iTunesGoogle PlayStitcher, or use the link to the RSS feed

As a chunk step reaches a checkpoint, the reader and writer are both called to provide checkpoint information.  This has to be a Java Serializable object.  The serialized data is hardened into the Job Repository as part of the transaction commit processing at the end of the chunk.  In a retry-rollback or job restart scenario, that checkpoint data is retrieved and provided to the reader and writer as they are called to perform open processing. 

What if a job fails and before it gets restarted the application is updated and that update includes a change to the contents of the checkpoint data?  What happens? Does the job fail?  How do you handle this?  Or can it just never change? 

This is really just a case of a common problem with hardening Serializable Java objects.  If it is possible for the application to change between serialization and deserialization the application needs to handle it.  There are numerous posts elsewhere that discuss the general topic, but I’ll try to just make a few suggestions.

Firstly, you should add a serialVersionUID to your checkpoint data class.  Change it only when you make incompatible changes to the class contents.  An exception will be thrown trying to deserialize the object if you try to read a version of the class that is different than the one currently loaded. 

It is possible to make compatible changes to a class if you’re careful.  For example, you can add a new attribute to a class if you remember that deserializing an older version will set that field to its default value.  Be sure to check that a newly added String isn’t null before you try to use it if it is possible an older serialized version might still be around.

You can also implement your own readObject and writeObject methods to make sure things get properly initialized if the default values cause you problems.  You can also bury your own class version number as an object attribute if that can help you figure out how to handle the serialized object.  Of course, that only works going forward (a version 2 class can read a version 1 object, but not the other way around).  That could happen if you ran a job that failed and then rolled the application itself back to a prior version before restarting it.    

There’s a lot of different advice online about techniques to handle different types of changes.  Of course, the best approach is to just never change the data or else be sure you don’t have any failed jobs that need restarting before you roll out an application update that changes the checkpoint data.