Details
-
Type: Improvement
-
Status: Open
-
Priority: Major
-
Resolution: Unresolved
-
Affects Version/s: 1.4.1
-
Fix Version/s: None
-
Component/s: Converters, Core
-
Labels:None
Description
We are using XStream in Bamboo to serialize stuff into database as well as over the JMS wire. Bamboo is running an OSGi-based plugin system and recently we made the build agents run the plugin system as well and that brought about some problems, one of them being able to serialize/deserialize classes coming from plugins (OSGi bundles).
After having an extended play with XStream to see the possible solutions we came up with some workarounds, but we feel that XStream API might be improved in this regard. More specifically, it seems that the component responsible for loading the classes is Mapper. Unfortunately mapper is just arbitrarily given an element's name/class attribute. In our case we would like to encode plugin key (equivalent to OSGi bundle symbolic name) and version, so that on the other side we can find corresponding plugin/bundle, make sure it exists and has corresponding version, and use it to load the class. It seems like there could be e.g. an ExtendedMapper interface that would have 'extended' version of methods responsible for serializing/loading classes (like realClass(String name) that would be given more context, in particular the HierarchicalStreamrReader/HierarchicalStreamWriter instance (or sub-interface of it) to read/write attributes. It could then be used in HierarchicalStreams et al. to read/write 'extended' information about the class.
An example of what I have in mind:
// marshalling if (mapper instanceof ExtendedMapper) { ExtendedMapper.class.cast(mapper).writeSerializedClass(writer); } else { // the 'normal' way writer.addAttribute("class", mapper().serializedClass(object.getClass())); } // unmarshalling (in HierarchicalStreams.readClassType()?) if (mapper instanceof ExtendedMapper) { return ExtendedMapper.class.cast(mapper).realClass(reader); } else { // the old way - check class attribute/element name }
We tried various workarounds, one that we will probably settle down with is to encode all the information (plugin key, plugin version) in the class name - but it still sounds like a workaround, not a robust solution...
Hi Dariusz,
can you tell me how you gain the information from the type and what you have to do to load it again? Personally I have not much OSGi experience.
Your proposal is not really realizable, the mapper should not get access to the writer or reader, these objects have completely different concerns. In the mapper you have no idea in what state the reader or writer is and you should not make any assumptions about it. You will never be sure if you can currently write or read attributes without destroying the state.
Actually the idea to manipulate the class name is not bad. But it would require a special ClassLoader for the DefaultMapper where you can register the next OSGi bundle info to use. For the name manipulation you should be able to write a custom mapper. Something along this:
The problem is that at deserialization time you do not yet have the real class name in OSGiMapper.realClass. The call has to go down the complete chain to the DefautlMapper where the real class name actually arrives. However, the bundle info must be stripped first from the name. Therefore this 'hack' with the ThreadLocal.
And if you really want to separate in the XML the type name from the bundle info into element name and attributes, you may additionally implement a special HierarchicalStreamWriter (and HSReader) that extends from WriterWrapper and can strip off the bundle info from the element name again and add it as attributes. You would then use this writer and reader directly with XStream's marshal and unmarshal calls:
Does this help?
BTW: Did you have realized that XStream uses Bamboo for CI?