Search code examples
javajaxbmarshallingunmarshallingjaxb2

Generating attribute option in xml using JAXB


I have to generate the following xml in my program using JAXB.

         <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <Employee empId="12345">
          <name>ABC</name>
          <address type="Residence">Bangalore</address>
         </Employee>

I have to generate the above xml using JAXB. I am having the Employee class as follows:

Employee Class

    package mypack;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement (name = "Employee")
    public class Employee {
            private String name;
        private String address;
        private int empId;
        private String addressType;

        @XmlAttribute
        public int getEmpId() {
            return empId;
        }
        public void setEmpId(int empId) {
            this.empId = empId;
        }

        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }

        public String getAddress() {
            return address;
        }
        public void setAddress(String address) {
            this.address = address;
        }

        public String getType() {
            return addressType;
        }
        public void setType(String addressType) {
            this.addressType = addressType;
        }   
    }

I am using JAXB to marshal the object.

Employee emp = new Employee();
            emp.setName("ABC");
            emp.setEmpId(12345);
                emp.setAddress("Bangalore");
                    emp.setType("Residence");
                    JAXBContext context = JAXBContext.newInstance(Employee.class);
            Marshaller marshaller = context.createMarshaller();
            marshaller.marshal(emp, System.out);

It does not generate the required xml. Rather it generates the xml as follows:

**Xml Being Generated**

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Employee empId="12345">
       <name>ABC</name>
       <address>Bangalore</address>
       <type>Residence</type>
    </Employee>

Actually I don't know how to annotate the type attribute so that I will generate the xml as <address type="Resident">Bangalore</address> Is my Employee class should be like as above? If yes, then how to annotate the type attribute so that it will come as an attribute in <address> tag.

Please help me out.


Solution

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

    You could use the MOXy's @XmlPath extension for this use case:

    @XmlPath("address/@type")
    public String getType() {
        return addressType;
    }
    

    Employee

    package mypack;
    
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;
    
    import org.eclipse.persistence.oxm.annotations.XmlPath;
    
    @XmlRootElement(name = "Employee")
    public class Employee {
    
        private String name;
        private String address;
        private int empId;
        private String addressType;
    
        @XmlAttribute
        public int getEmpId() {
            return empId;
        }
    
        public void setEmpId(int empId) {
            this.empId = empId;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @XmlPath("address/@type")
        public String getType() {
            return addressType;
        }
    
        public void setType(String addressType) {
            this.addressType = addressType;
        }
    }
    

    Demo

    package mypack;
    
    import java.io.File;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.Unmarshaller;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Employee.class);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            File xml = new File("src/mypack/input.xml");
            Employee employee = (Employee) unmarshaller.unmarshal(xml);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(employee, System.out);
        }
    
    }
    

    Input/Output

    <?xml version="1.0" encoding="UTF-8"?>
    <Employee empId="12345">
       <address type="Resident">Bangalore</address>
       <name>ABC</name>
    </Employee>
    

    For More Information


    UPDATE

    If you do not want to use any vendor specific extension then you could introduce a second class to represent the address information:

    Address

    package mypack;
    
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlValue;
    
    public class Address {
    
        private String address;
        private String addressType;
    
        @XmlValue   
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @XmlAttribute
        public String getType() {
            return addressType;
        }
    
        public void setType(String addressType) {
            this.addressType = addressType;
        }
    }
    

    Employee

    package mypack;
    
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement(name = "Employee")
    public class Employee {
    
        private String name;
        private Address address;
        private int empId;
    
        @XmlAttribute
        public int getEmpId() {
            return empId;
        }
    
        public void setEmpId(int empId) {
            this.empId = empId;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
    }