2

I'm working on a framework for backwards compatiblity between different versions of a class (from serialized binary representations).

One thing I'm stuck on is how to replace a field used in a class with a different version of the field's class - at runtime.

I know how I could do it using a Classloader if the class in question is the parent object ( Java - how to load different versions of the same class? ).

But this doesn't work when I already have an object and need to change a field of it (or I don't see how). The reflection API also doesn't seem to have methods to set classes after they have been instantiated.

I'll give an example so it's better to understand. Let's say I have a wrapper class:

class Wrapper{
  int version;
  Object content;
}

Now assume that the class I'm loading as the variable content changed 20 versions ago. I still have the original .java (or .class-)file used from back then though. What I intend to do is, create an instance of wrapper with the old class version of content, load that from disc, transform it and write it into a up to date version of wrapper with the current version of the class used for content.

It also needs to be very generic, which is why I'm using object and not the actual class in the wrapper. The real issue is that I need this for protostuff runtime (de-)serialization. Which means I'm passing Wrapper.class to protostuff and it generates a serialization schema for it. This currently fails because the wrapper.class file automatically references the new version (it's in the project's package).

Schema<Wrapper> schema= RuntimeSchema.getSchema(Wrapper.class);
Wrapper resultWrapper = schema.newMessage();

I'm not sure if this ever even goes through a classloader and if so, when. I suppose it has to, but I'm not sure when this happens.

What would be the best way of approaching this?

Community
  • 1
  • 1
user2323596
  • 523
  • 1
  • 6
  • 11
  • One thing you may want to check out is Javassist. I've not used it directly myself, but it is (was?) used by Hibernate internally to wrap bean properties so that they are lazily loaded when they are first needed. I think it could fit your needs as well. See http://www.javassist.org Not for the faint of heart though. – geert3 Feb 24 '15 at 14:04
  • Maybe this would all be way easier if I drop the wrapper idea and store the format version somehow differently. Then I can just use a simple classloader :-\ – user2323596 Feb 24 '15 at 15:02

1 Answers1

1

One thing you could do, is to have a separate ClassLoader objects for different versions. As the ClassLoader is part of an the identity of a class, in addition to it's package and name, you are then able to have multiple versions of the class in memory. The only problem with this approach is that you will end up relying reflection to do anything with these objects.

You could then create an object of your current version and transfer the values of those fields using reflection. This would get around the problem of having to modify the field types during run time.

PeterK
  • 1,697
  • 10
  • 20
  • Yeah it looks like this is what it's going to be heading towards, thank you. – user2323596 Feb 25 '15 at 15:41
  • I just wanted to confirm, this method was indeed exactly what I was looking for, I tested it out now. As long as all the referenced classes are loaded by the same custom classloader, it'll build an object for the old data format. Thanks again. – user2323596 Feb 25 '15 at 17:23