Search code examples
javaxmljaxbmoxy

JAXB/MOXy use same Entity-type for several properties


I have a rather large object tree which I want to export to XML. An object named Person is used at several places (as userCreated, userModified of many child entities, as client, etc)

Depending of the use of the Person-object I need to have different elements in the xml. Example:

<policy>
  <userCreated>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
  </userCreated>
  <client>
    <clientId>1234</clientId>
    <email>[email protected]</email>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
  </client>
</policy>

userCreated and client are instances of the same object (named Person)

How can this be set up in bindings.xml ?


Solution

  • You can use EclipseLink JAXB (MOXy)'s @XmlNamedObjectGraph extension to support this use case. What @XmlNamedObjectGraph allows you to do is create multiple views on your data.

    Person

    Below we will use @XmlNamedObjectGraph to create a view on the Person class that only exposes 2 fields (firstName and lastName).

    import javax.xml.bind.annotation.*;
    import org.eclipse.persistence.oxm.annotations.*;
    
    @XmlNamedObjectGraph(
        name = "simple", 
        attributeNodes = {
            @XmlNamedAttributeNode("firstName"), 
            @XmlNamedAttributeNode("lastName")
         }
    )
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Person {
    
        private int clientId;
        private String firstName;
        private String lastName;
        private String email;
    
        public void setClientId(int clientId) {
            this.clientId = clientId;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
    }
    

    Policy

    We will also use @XmlNamedObjectGraph on the Policy class. It says that for the userCreated field apply the named object graph called simple that we defined on the Person class.

    import javax.xml.bind.annotation.*;
    import org.eclipse.persistence.oxm.annotations.*;
    
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlNamedObjectGraph(
        name = "policy", 
        attributeNodes = {
            @XmlNamedAttributeNode(value = "userCreated", subgraph = "simple"),
            @XmlNamedAttributeNode("client") 
        }
    )
    public class Policy {
    
        private Person userCreated;
        private Person client;
    
        public void setUserCreated(Person userCreated) {
            this.userCreated = userCreated;
        }
    
        public void setClient(Person client) {
            this.client = client;
        }
    
    }
    

    Demo

    In the demo code below we will specify the named object graph that we want applied on the Marshaller using the MarshallerProperties.OBJECT_GRAPH property.

    import javax.xml.bind.*;
    import org.eclipse.persistence.jaxb.MarshallerProperties;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Policy.class);
    
            Person person = new Person();
            person.setClientId(1234);
            person.setFirstName("John");
            person.setLastName("Doe");
            person.setEmail("[email protected]");
    
            Policy policy = new Policy();
            policy.setClient(person);
            policy.setUserCreated(person);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "policy");
            marshaller.marshal(policy, System.out);
        }
    
    }
    

    Output

    Below is the output from running the demo code:

    <?xml version="1.0" encoding="UTF-8"?>
    <policy>
       <userCreated>
          <firstName>John</firstName>
          <lastName>Doe</lastName>
       </userCreated>
       <client>
          <clientId>1234</clientId>
          <firstName>John</firstName>
          <lastName>Doe</lastName>
          <email>[email protected]</email>
       </client>
    </policy>
    

    For More Information