fuin.org
Small Open Source Java Tools and Libraries
Example story of an evolving class
First version of your class
package my.test; public class Address implements Serializable { private static final long serialVersionUID = -7393761964342362874L; private long versionUID = serialVersionUID; private String name; // ... setter/getter and other methods ... }
You serialize some instances of this class to your hard disk.
Now you want to change the class and split the name field into a first name and last name. But what about the serialized versions on disk? If you change the class you cannot read them anymore!
The solution...
From version 1 to version 2
- Make a copy of the class and move it into a separate package like "my.test.old.address.v1" - If you use the VersioningJavaSerializer it's important not to change the name of the class itself (only the package). The Java deserialization process checks if the class names are equal and will fail otherwise! For other VersioningSerializer implementations this is not crucial but it's a good practice to use this naming scheme for all versioning serializers.
-
Change the class and assign a new serialVersionUID:
package my.test; public class Address implements Serializable { private static final long serialVersionUID = -2466841694916192299L; private long versionUID = serialVersionUID; private String firstName; private String lastName; // ... setter/getter and other methods ... }
-
Create a converter that converts an instance of the old class into the new version and put it in the same package as the old class
(my.test.old.address.v1):
package my.test.old.address.v1; /** * Converts version 1 into version 2. */ public class AddressConverter implements Converter<my.test.old.address.v1.Address, my.test.Address> { @Override public final my.test.Address convert(final my.test.old.address.v1.Address src) { if (src == null) { return null; } final String firstName; final String lastName; final String name = src.getName(); if (name == null) { firstName = null; lastName = null; } else { final int p = name.indexOf(" "); if (p == -1) { firstName = null; lastName = name; } else { firstName = name.substring(0, p); lastName = name.substring(p + 1); } } return new my.test.Address(firstName, lastName); } }
-
Add a new entry to the history XML:
<?xml version="1.0" encoding="UTF-8"?> <history versionTag="versionUID"> <class package="my.test" name="Address"> <version> <serialVersionUID>-7393761964342362874</serialVersionUID> <oldClass>my.test.old.address.v1.Address</oldClass> <converterClass>my.test.old.address.v1.AddressConverter</converterClass> </version> </class> </history>
You serialize again some instances of the changed class to your hard disk.
The class changes again by adding a unique identifier!
From version 2 to version 3
- Make a copy of the class and move it into a separate package like "my.test.old.address.v2"
-
Change the class and assign a new serialVersionUID:
package my.test; public class Address implements Serializable { private static final long serialVersionUID = 5570679541850483841L; private long versionUID = serialVersionUID; private int id; private String firstName; private String lastName; // ... setter/getter and other methods ...
-
Create a converter that converts version 2 to version 3:
package my.test.old.address.v2; /** * Converts version 2 into version 3. */ public class AddressConverter implements Converter<my.test.old.address.v2.Address, my.test.Address> { private IdFactory idFactory; /** * Constructor with ID factory. * * @param idFactory * ID factory to use. */ public AddressConverter(final IdFactory idFactory) { super(); this.idFactory = idFactory; } @Override public final my.test.Address convert(final my.test.old.address.v2Address src) { if (src == null) { return null; } return new my.test.Address(idFactory.nextId(), src.getFirstName(), src.getLastName()); } }
-
Add a new entry to the history XML:
<?xml version="1.0" encoding="UTF-8"?> <history versionTag="versionUID"> <class package="my.test" name="Address"> <version> <serialVersionUID>-7393761964342362874</serialVersionUID> <oldClass>my.test.old.address.v1.Address</oldClass> <converterClass>my.test.old.address.v1.AddressConverter</converterClass> </version> <version> <serialVersionUID>-2466841694916192299</serialVersionUID> <oldClass>my.test.old.address.v2.Address</oldClass> <converterClass>my.test.old.address.v2.AddressConverter</converterClass> </version> </class> </history>