Wednesday, September 5, 2007

Import / Export Database from / to XML

I'm using Hibernate to manage my database persistency and I wanted to add export/import to/from XML capabilities. Hibernate does support XML but the documentation is very limited. Next, it is not capable of generating a schema (xsd). XStream has the same problem. So that left only JAXB. Issue with JAXB is that it is very document (web service) oriented. The HyperJAXB - project uses the web services xml as a starting point. I want it the other way; my domain classes are the source of truth; they form the basis from which I want to persist and export/import.

Since i'm neither a JAXB nor a Hibernate expert it has proven to be quite an exercise. Especially Hibernate's merge operation in combination with Spring's IdTransferringMergeEventListener caused a lot of headache. I did not fix this properly, but replaced the merge() with saveOrUpdate().

Anyway the basic steps to export/import a database (aka repository) are as follows:

  • Create a container class that contains collections of the top-level domain classes. My sample is based on two domain classes Person and FiledCase. The class Repository contains two collections of these classes. The collections are extensions of a special HibernateCollectionAdapter class. This class takes care of loading from and persisting to the database for a domain class. The container class is passed to JAXB for import or export
  • Annotate the database id field in each domain class with @XmlTransient, we do not use this field since it is not guaranteed to be unique across all classes. (if it would be you could use this field as xml id)
  • Add an xml id field to the domain classes that can be referred to. Annotate the get method with @XmlID. The get method should return the fully quantified classname appended with the database id. (to make the ID unique across all classes)
  • Annotate the classes that needs to be exported with @XmlRootElement
  • Mark the get methods that refer to other objects that are not aggregated, but have an association type of relationship with @XmlIDREF
  • Make sure that the classes are exported in the order of least referenced, use the annotation @XmlType with field proporder to specify the order of the properties. This is very important during import. JAXB will patch references of objects afterwards when they cannot be resolved immediately (because the object is not yet imported). However when the object is already persisted it will not reflect the updated references.
  • The HibernateCollectionAdapter class implements the Collection interface. In the add() method it will store() an object and in the contains() it delegates to a find() method. The store and find methods are overridden in the descended classes. There are a couple of other methods that should also be overriden.
Sample is uploaded, see comment below

12 comments:

Donal said...

Hi Alexander,
I'm looking to do nearly the same thing with Hibernate and SQLServer Express. The job I'm working on at the moment is to produce a desktop application to model customer's IT infrastructures on a project by project basis. We have a requirement whereby all project info can be exported from one instance of the application to another. We'd love to find a Java/XML based solution to this and what you described in the post above sounds very close. If you wouldn't mind posting a little code to get us started, I'd be very appreciative. Thanks, Donal

Stephan Westen said...

I will try to get something out of the door this week.

Stephan Westen said...

I uploaded the files to http://oosten.4shared.com/

I've left a couple of files out. The association relationship between Person and Case.

Donal said...

That's fantastic Alexander, thanks very much!

Anonymous said...

Hi Alexander,

I cannot access the files, can you please re-upload ?

Thanks,
Amol

Unknown said...

Hi Alexander,

I cannot access the files, could you mail me them to klaus.demetz-schittek at online.de?

Thanks,

Klaus Demetz-Schittek

Stephan Westen said...

I dumped a bunch of files into: http://home.planet.nl/~west2387/Download/ImpExp/

The FTP side does not allow to browse the folder. You need to append the file name to the above URL.

HibernateCollectionAdapter.java
LegalEntityCollectionImpl.java
NotaryCaseCollectionImpl.java
PersonCollectionImpl.java
Repository.java
XMLImportExport.java
XMLImportExportStatus.java
XMLImportStatus.java
ActPersistency.java

BaseEntity.java
Contact.java
FamilyLawCase.java
LegalEntity.java
MiscCase.java
MortgageCase.java
NamedEntity.java
NotaryCase.java
NotaryCaseImpl.java
Partnership.java
Person.java
RealEstateCase.java

You have to ignore the Dutch comments.

Stephan Westen said...

Argh, I had to change the .java extensions into .txt (again the provider is a bit paranoid)

So for example http://home.planet.nl/~west2387/Download/ImpExp/Person.txt should work

Unknown said...

Thank you very very much!!!

Matt Gleeson said...

Hi, thanks for all your work on this - this is just what I was looking for.
In gratitude, I've compiled a list of the links for ease of download for everyone:


HibernateCollectionAdapter.txt
LegalEntityCollectionImpl.txt
NotaryCaseCollectionImpl.txt
PersonCollectionImpl.txt
Repository.txt
XMLImportExport.txt
XMLImportExportStatus.txt
ImpExp/XMLImportStatus.txt
ActPersistency.txt


BaseEntity.txt
Contact.txt
FamilyLawCase.txt
LegalEntity.txt
MiscCase.txt
MortgageCase.txt
NamedEntity.txt
NotaryCase.txt
NotaryCaseImpl.txt
Partnership.txt
Person.txt
RealEstateCase.txt

Unknown said...

Hi Alexander,
could you mind to upload your source code again. the previous links are not work.

Unknown said...

Hi Alexander,
could you mind to upload your source code again. the previous links are not work.