Hi all,
I've been thinking about backwards compatibility of our persisted
brooklyn state, in the face of us moving classes around and/or deprecating.
---
USE CASES
Let's take two use-cases:
1. `MathPredicates.greaterThan` returns a (static) anonymous inner
class, so is serialized by xstream as `MathPredicates$1`.
We want to move that class to a fixed class name (e.g. `private
static class GreaterThan {...}`) suitable for xstream.
(It's a *really bad* idea to be using `MathPredicates$1`; if someone
in a future release adds some code above it then the class name
would change!)
2. I want to move PortRanges from package `brooklyn.location.basic` to
`brooklyn.util.net.PortRanges`.
However, this contains inner classes such as `SinglePort`.
If it was just code compatibility, we'd have the old `PortRanges
extends brooklyn.util.net.PortRanges`, and do some fancy stuff to
wrap the returned objects so they implement
`brooklyn.location.PortRange`.
---
THE PROBLEM
xstream tries to deserialize MathPredicates$1 but that class no longer
exists. Even if we did leave it around (yuck!), nothing changes it to
the new class name so we could never delete it!
---
THE PROPOSED SOLUTION
I propose we have a lookup file in brooklyn that contains all the
renamed classes.
We register a converter with xstream that, when deserializing, looks up
this (cached) lookup file. If it contains the classname that xstream has
encountered, we switch it for the new one and then let xstream continue
with its deserialization.
See brooklyn.entity.rebind.persister.XmlMementoSerializer for where this
code would go.
(Note that for the `PortRange` example, we'd require that the calling
code had been updated to expect the new `brooklyn.util.net.PortRange`
rather than the old `brooklyn.location.PortRange`. i.e. the returned
instance would not implement all the same interfaces as the original
class! We could perhaps work around that with some extra converter logic
and wrapping classes.)
---
ALTERNATIVE SOLUTION
We could have a separate tool that is run manually once when someone is
upgrading. It would walk through the persisted state, changing the old
class names to the new ones.
Thoughts?
Aled