Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i store the ArrayList of complex objects into xml?

I have two classes which are having relations with each other as below. I have a list of ObjReal objects where the whole data is presented. I want to save the whole List into xml without losing the object relationships. I mean an object represented in XML should have their corresponding objStrucs along with it. To store ObjReal into xml is straight forward but i am getting confused with its ObjStruc relations. Please helpe to solve this problem.

My ObjReal is:

Class ObjReal
{
  private String id;
  private String data;

  ArrayList<ObjStruc> objStrucs=new ArrayList<ObjStruc>();

  public ArrayList<ObjStruc> getObjStrucs()
    {
        return objStrucs;
    }

  public String getId()
 {
      return id;
 }

  public String getData()
    {
      return data;
    }

    public void setId(String id)
    {
        this.id=id;
    }
    public void setData(String data)
    {
        this.data=data;
    }

}

My ObjStruc is:

Class ObjStruc
{
    private ObjReal objReal;
    public ObjReal getObjReal()
 {
      return objReal;
 }

  public ObjReal setObjReal(ObjReal objReal)
    {
      this.objReal=objReal;
    }

}

And the complete data is in ArrayList<ObjReal> obreals object which i want to dump into xml. I hope i kept a clear point. Thanks in advance.

like image 942
user1119970 Avatar asked Jan 15 '12 07:01

user1119970


4 Answers

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

There are a couple interesting aspects of your use case:

  1. ArrayList as the root object
  2. Bidirectional relationship between ObjReal and ObjStruc

1. ARRAYLIST AS ROOT OBJECT

JAXB implementations (MOXy, Metro, JaxMe, etc) do not provide direct support for handling Collection types as root objects. To handle this use case you simply need to create a wrapper class that has the desired Collection as a field/property.

@XmlRootElement(name="root-element-name")
@XmlAccessorType(XmlAccessType.FIELD)
public class ListWrapper {

    private ArrayList<ObjReal> objReals;        

}

2. BIDIRECTIONAL RELATIOSNHIP

You can use the @XmlInverseReference extension in EclipseLink implementation of JAXB to handle the bidirectional relationship in your model. Below I have included a complete example. I have omitted most of the accessor methods to save space.

ObjReal

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

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
class ObjReal {

  private String id;
  private String data;
  ArrayList<ObjStruc> objStrucs=new ArrayList<ObjStruc>();

  public ArrayList<ObjStruc> getObjStrucs() {
    return objStrucs;
  }

}

ObjStruc

The @XmlInverseReference annotation is used on this class. On this annotation you specify the fied/property name for the other direction of the relationship:

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

@XmlAccessorType(XmlAccessType.FIELD)
class ObjStruc {

    @XmlInverseReference(mappedBy="objStrucs")
    private ObjReal objReal;

    public ObjReal getObjReal() {
        return objReal;
    }

}

jaxb.properties

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

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

Demo

You can run the following code to verify the mapping:

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

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum8868303/input.xml");
        ObjReal objReal = (ObjReal) unmarshaller.unmarshal(xml);

        for(ObjStruc objStruc : objReal.getObjStrucs()) {
            System.out.println(objStruc.getObjReal());
        }

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

}

Input (input.xml)

<?xml version="1.0" encoding="UTF-8"?>
<objReal>
    <id>123</id>
    <data>some data</data>
    <objStrucs/>
    <objStrucs/>
</objReal>

Output

Below is the output from running the demo code. As you can see the objReal property on each of the ObjStruc objects was populated during the unmarshal:

forum8868303.ObjReal@7f712b3a
forum8868303.ObjReal@7f712b3a
<?xml version="1.0" encoding="UTF-8"?>
<objReal>
   <id>123</id>
   <data>some data</data>
   <objStrucs/>
   <objStrucs/>
</objReal>

For More Information

  • http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html
  • http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
  • http://blog.bdoughan.com/2010/07/jaxb-xml-binding-standard.html
  • http://blog.bdoughan.com/2010/10/how-does-jaxb-compare-to-xstream.html

Download EclipseLink

You can download EclipseLink at:

  • http://www.eclipse.org/eclipselink/downloads/
like image 189
bdoughan Avatar answered Nov 03 '22 17:11

bdoughan


There are several libraries that will serialiaze object structures to xml. One of them is XStream. There is an easy and fast tutorial here.

like image 24
Andreas Wederbrand Avatar answered Nov 03 '22 17:11

Andreas Wederbrand


Just feed it to XStream! It works both ways. Code snippets here. Good luck!

like image 2
aviad Avatar answered Nov 03 '22 15:11

aviad


Any easy way to write a java object to xml is to use the java xml encoder. This writes your entire object and its dependencies to xml format. You can then read them back in to your object also.

public static boolean writeXMLFile(final Object data, final String fileName) {

    XMLEncoder encoder = null;

    boolean result = true;

    try {
        encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(fileName)));
        encoder.writeObject(data);
    } catch (final IOException e) {
        logger.error(e.getMessage());
        result = false;
    } finally {
        if (encoder != null) {
            encoder.close();
        } else {
            result = false;
        }
    }

public static Object readXMLFile(final String fileName) {

    XMLDecoder decoder = null;
    Object data = null;

    try {
        FileInputStream fis = new FileInputStream(fileName);
        BufferedInputStream bis = new BufferedInputStream(fis);
        decoder = new XMLDecoder(bis);
        data = decoder.readObject();
    } catch (final FileNotFoundException e) {
        data = null;
        logger.error(e.getMessage());
    } catch (final Exception e) {
        data = null;
        logger.error(e.getMessage());
    } finally {
        if (decoder != null) {
            decoder.close();
        } else {
            data = null;
        }
    }

    return data;
}
like image 1
Logan Avatar answered Nov 03 '22 17:11

Logan