1

I have an old Access database that is basically one flat file. I want to migrate the data to my new whizzy, object oriented, hibernate based wonder-app.

The data is available as an XML file, and I want to map to three separate java pojos. I planned on using JAXB to do this, specifically using @xmlelement annotation. However the structure of the XML file is not optimal, in my pojos I have split up the data into three different objects.

Will JAXB help with this ? Do I need to simply create java pojo based on existing schema/xml file (that is not oo) using jaxb. Then create apdater classes/layer to put the data into my three pojos ? Or can I map straight from the xml file to 3 pojos with correct config/annotation ?

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • Can you provide additional details on what your XML and objects look like? – bdoughan Dec 20 '11 at 15:13
  • @BlaiseDoughan does it make a difference ? I have a 1000's of rows/root elements each with 20 subelements/columns. I have split the twenty sub elements into three separate pojos. Thats it. Loks like I will have to create pojo that matches xml, then map between the one pojo to the other three ... – NimChimpsky Dec 20 '11 at 15:16
  • Depends on the quality of answer you are looking for :). How are the 3 POJOs related to one another? – bdoughan Dec 20 '11 at 15:21
  • You don't need to create that intermediary pojo manually. You can use xjc. See my answer. – smp7d Dec 20 '11 at 15:22
  • @BlaiseDoughan The 3 pojos, well "a" has a reference to "b", which has a reference to "c" ... (they are also hibernate entities) – NimChimpsky Dec 20 '11 at 15:23
  • @smp7d yeah ok thanks. That looks like what I'll do. I was trying to avoid writing the code to map between the one auto generated object, and my 3 objects – NimChimpsky Dec 20 '11 at 15:24
  • Any bidirectional relationships? – bdoughan Dec 20 '11 at 15:25

3 Answers3

4

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

Assuming your XML document looks something like the following:

<?xml version="1.0" encoding="UTF-8"?>
<rows>
    <row>
        <col1>a1</col1>
        <col2>b1</col2>
        <col3>c1</col3>
    </row>
    <row>
        <col1>a1</col1>
        <col2>b2</col2>
        <col3>c2</col3>
    </row>
</rows>

You could leverage MOXy's @XmlPath annotation and do something like. EclipseLink also includes a JPA implementation:

Rows

You will need to create a Root object to hold everything:

package forum8577359;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Rows {

    @XmlElement(name="row")
    private List<A> rows;

}

A

Since the contents for the A, B, and C objects are all at the same level you can use MOXy's @XmlPath annotation and specify the "." XPath. This tells MOXy that the object, and the object it is referencing occur at the same level:

package forum8577359;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
public class A {

    private String col1;

    @XmlPath(".")
    private B b;

}

B

Again we use @XmlPath(".") to map the relationship between B and C:

package forum8577359;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
public class B {

    private String col2;

    @XmlPath(".")
    private C c;

}

C

package forum8577359;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class C {

    private String col3;

}

Demo

The following demo code can be used to run this example:

package forum8577359;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Rows.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum8577359/input.xml");
        Rows rows = (Rows) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(rows, System.out);
    }

}

jaxb.properties

To specify MOXy as your JAXB provider you need to include a jaxb.properties file in the same package as your domain classes with the following entry:

javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory

For More Information

bdoughan
  • 147,609
  • 23
  • 300
  • 400
1

Without knowing the specifics of your issues...it should be possible, but it sounds like this may be a case where you would want to write a schema, use xjc to generate binding objects, unmarshal to the generated binding objects, and then translate to your domain objects in java (or use the generated objects directly if applicable).

smp7d
  • 4,947
  • 2
  • 26
  • 48
1

Typically JAXB helps. Even if you are writing classes and annotations manually I think it takes less time than parsing using DOM API.

Moreover you can generate value objects automatically using JAXB. I think this is the approach you should try. First you should generate XSD file from your XML (unless you already have one). Then you should generated value objects based on the XSD. Then just parse the file. 2 code lines and you are done.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • Hi, Thanks for your response on this. I am a bit stuck in the following issue with regards to `Moxy/JAXB`. If you get a chance can you please have a look and provide your response? https://stackoverflow.com/q/67648941/7584240 – BATMAN_2008 Jun 04 '21 at 07:15