XML Serialization

Overview

Platform provides facilities to save java objects in xml format. Most of the platform objects use this approach (reports, report queries, search queries, import/export configurations and mappings, assortment, value providers, job framework objects). The main purpose of xml serializion is to provide JMV independent, 'human readable' and controllable format to store java objects. If you need to persist service objects and you don't need to perform search or match queries on a set of persisted objects then HPM xml serialization is a correct approach to use. A typical example of xml serialization is a user specific configuration object which should be saved between user login sessions.

What xml serialization is not:

  • It is not a domain objects persistence

  • It is not the HPM communication framework marshaling

For JEE folks: HPM XML Serialization has the same purposes as Java Architecture for XML Binding (JAXB) technology.

Services and Interfaces

All necessary services and interfaces can be found in the com.heiler.ppm.xml bundle.
This bundle also contains xml 3rd party libraries which are required in order xml serialization to function properly. Please, don't change or upgrade these libraries because other versions (or spec implementaions) will most likely not work and cause hard-to-diagnose bugs (as of 5.3). These libraries are located in the /endorsed folder of the bundle which is configured as a java.endorsed.dirs java setting. This setting effectively redefines system xml-apis implementions.

Creating xml serializable classes

As of HPM 5.3 the correct way to use xml serialization is to implement DomPersistalbe2 interface (for serialization) and DomPersistalbe2 interface (for deserializazion). DomPersistableFactory implementations shell be contributed using com.heiler.ppm.xml.domPersistableFactories. We recommend to use internal classes for that.

In DomPersistable2#writeToDom( DomPersistWriteContext context, Element anchorElement ) implementation you can decide which fields will be serialized and in which form: as xml attribute or as a xml sub element. If any of the fields types you want to serialize already implements DomPersistable2 then the xml serializer will recognize it and will delegate serialization of this type to its writeToDom(...) method. Such approach helps to serialize complex object trees where every object is responsible only for serialization of its own data only. This feature is quite helpfull when your java objects contain references to platform objects which already support xml serialization (for example SearchParameters). During serialization platform is able to recognize same object instances and serialize them only once (this will save space and time). Xml representations of the duplicate objects will only contain references to the master object (in xml string this is called sys-id).

To serialize and deserialize java object you can use DomPersistUtils.toXml(Object,String) and DomPersistUtils.fromXml(String) methods.

Serialization example
public class MyConfig implements DomPersistable2
{
private static final String XML_MY_NAME = "myName";
 
private static final String XML_ABOUT_ME = "about";
 
private static final String XML_FRIENDS = "myFriendsSearch";
 
private String myName;
 
private String aboutMe;
 
private SearchParameters myFriendsSearchParams;
 
public MyConfig( String myName, String aboutMe, SearchParameters myFriendsSearchParams )
{
this.myName = myName;
this.aboutMe = aboutMe;
this.myFriendsSearchParams = myFriendsSearchParams;
}
 
@Override
public String getFactoryId()
{
DomPersistUtils.warnUnregistered( Factory.IDENTIFIER, Factory.class );
return Factory.IDENTIFIER;
}
 
@Override
public void writeToDom( DomPersistWriteContext context, Element anchorElement ) throws Exception
{
//same name as xml attribute
anchorElement.addAttribute( XML_MY_NAME, this.myName );
//save long text as a body of <about>...</about>
context.writeToDom( this.aboutMe, anchorElement.addElement( XML_ABOUT_ME ) );
//save search params under <myFriendsSearch>...</myFriendsSearch>
context.writeToDom( this.myFriendsSearchParams, anchorElement.addElement( XML_FRIENDS ) );
}
 
public static final class Factory implements DomPersistableFactory
{
public static final String IDENTIFIER = "hlr.me.MyConfig"; //$NON-NLS-1$
 
@Override
public Object createFromDom( DomPersistReadContext context, Element anchorElement ) throws Exception
{
String myName = DomPersistUtils.getAttributeValue( anchorElement, XML_MY_NAME, true, null );
 
Element aboutMeXmlElement = anchorElement.element( XML_ABOUT_ME );
String aboutMe = context.createFromDom( aboutMeXmlElement );
 
Element fredsSearchXmlElement = anchorElement.element( XML_FRIENDS );
SearchParameters searchParams = context.createFromDom( fredsSearchXmlElement );
 
return new MyConfig( myName, aboutMe, searchParams );
}
}
}
 
//contribution in plugin.xml
<extension
point="com.heiler.ppm.xml.domPersistableFactories">
<factory
class="com.heiler.ppm.me.MyConfig$Factory"
id="hlr.me.MyConfig">
</factory>
</extension>

Serialize objects without DomPersistable2 interface.

You can serilize objects which do not implement DomPersistable2 interface by implementing DomPersister interface in a separate class and contributing it using persister element in the com.heiler.ppm.xml.domPersistableFactories extension point.

Deprecated interfaces

HPM platform also still contains two deprecated xml searilizazion machanisms. DomPersistable and PersistableElement interfaces. As well as corresponding extension point com.heiler.ppm.xml.elementFactories. You should not use these mechanisms, but you can still serialize these objects in a context of DomPersistable2 implementaions. For example you can simply call

Serialize DomPersistable
public void writeToDom( DomPersistWriteContext context, Element anchorElement ) throws Exception
{
...
Element e = anchorElement.addElement( XML_LEGACY );
context.writeToDom( this.oldDomPersistable, e );
...
}

add serlialization framework will delegate xml serializaion of this object to the deprecated (but still) working algorithm. So you can mix different xml serilization approaches in the same object tree. However this is highly unrecommended.

The main disadvatage of DomPersistable and PerstableElement aproaches is that they store full qualified class names. So if the class name has been changed between versions then deserialization of the old xml structures will be impossible because the class name is used by refelection on deserialization.

Migration to DomPersistable2

As a general rule you have to migrate your old DomPersistable implementaions to DomPersistable2 approach. Because you also need to support HPM versions migrations you need to follow some rules:

  • New DomPersistable2 implementaion of your class must use the same xml structure as the original DomPersistable implemention.

  • New DomPersistable2 implementaion must have the same full qualified name as the original DomPersistable implemention.

  • New DomPersistable2 implementaion must have an empty argument public constructor.

Data migration will happen automatically as soon as a cycle of read_domPersistable_format - save_in_domPersistable2_format will be sucessfully finished.

It is important to test new DomPersistable2 with old data from DomPersistable serialization. With tests you can be sure that migration with live data will not go wrong in production environment. For that you need to build test cases which take the old XML string and read it using new DomPersistable2 implementaion. Consider this as a required junit test case when you make refactoring of DomPersistable to DomPersistable2.