0

I have an xml document in this format:

<company>
    <employees>
        <employee firstname="xyz" lastname="abc">
            <empId ID="1"/>
            <department ID="D1"/>
            <manager ID="23"/>
        </employee>
    </employees>
    <departments>
        <department name="dept 1">
            <deptId ID="D1"/>
        </department>
    </departments>
 <company>

I am trying to use JAXB to unmarshal this to Java but am unable to determine a way to map the employee Id to an id field in Employee class.

public class Employee{

@XmlAttribute
private String firstname;

@XmlAttribute
private String lastname;

???
@XmlID
private String id;

???
@XmlIDREF
private String managerId;

}

Any suggestions?

Himanshu
  • 1
  • 2

1 Answers1

0

Based on some comment feedback, you can attempt to marshal the data using the following:

Create two classes to represent the ID fields in your object classes:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="deptId")
public class DepartmentId {
    @XmlAttribute(name="ID") // define an attribute for the ID
    @XmlID
    String id;
    @XmlValue  // define a value, and set to null
    String value = null;

    public DepartmentId() {}

    public void setId(String id) { this.id = id; }
    public String getId() { return this.id; }
}

and

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="empId")
public class EmployeeId {
    @XmlAttribute(name="ID")
    @XmlID
    String id;
    @XmlValue
    String value = null;

    public EmployeeId() {}

    public void setId(String id) { this.id = id; }
    public String getId() { return this.id; }
} 

Annotate your Employee class like so: Some slight mods to your getter/setter methods may be necessary, this is pretty crude, but it should work with the test below, as-is

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="employee")
public class Employee {

    @XmlElement(name="empId")
    private EmployeeId id; // an employee ID object will be used to represent this element

    @XmlAttribute(name="firstname")
    private String firstName;

    @XmlAttribute(name="lastname")
    private String lastName;

    @XmlElement(name="manager")
    private EmployeeId manager;  // same with the manager

    @XmlElement(name="department")
    private DepartmentId department;  // same with the dept

    public Employee() {

    }

    public void setId(String id) {
        this.id = new EmployeeId();
        this.id.setId(id);
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setManager(Employee manager) {
        this.manager = new EmployeeId();
        this.manager.setId(manager.getId());
    }

    public void setDepartment(Department department) {
        this.department = new DepartmentId();
        this.department.setId(department.getId());
    }

    public String getId() { return this.id.getId(); }
    public String getFirstName() { return this.firstName; }
    public String getLastName() { return this.lastName; }
    public EmployeeId getManager() { return this.manager; }
    public DepartmentId getDepartment() { return this.department; }
}

A Department class annotated like this:

@XmlRootElement(name="department")
@XmlAccessorType(XmlAccessType.FIELD)
public class Department {

    @XmlElement(name="deptId")
    private DepartmentId id;

    public Department() {}

    public void setId(String id) {
        this.id = new DepartmentId();
        this.id.setId(id);
    }
    public String getId() { return this.id.getId(); }
}

A Company class annotated like this:

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

    @XmlElement(name="employee")
    private List<Employee> employees;

    @XmlElement(name="department")
    private List<Department> departments;

    public Company() {
        employees = new ArrayList<Employee>();
        departments = new ArrayList<Department>();
    }

    public List<Employee> getEmployees() { return this.employees; }
    public void setEmployees(List<Employee> employees) { this.employees = employees; }
    public List<Department> getDepartments() { return this.departments; }
    public void setDepartments(List<Department> departments ) { this.departments = departments; }
}

With the following test:

public class Test {
    public static void main(String[] args) throws Exception {
        Company c = new Company();
        Department d1 = new Department();
        d1.setId("D1");
        Department d2 = new Department();
        d2.setId("D2");

        Employee e1 = new Employee();
        e1.setId("1");
        e1.setFirstName("Joe");
        e1.setLastName("Smith");
        e1.setDepartment(d1);

        Employee e2 = new Employee();
        e2.setId("2");
        e2.setFirstName("John");
        e2.setLastName("Doe");
        e2.setManager(e1);
        e2.setDepartment(d1);

        c.getEmployees().add(e1);
        c.getEmployees().add(e2);
        c.getDepartments().add(d1);
        c.getDepartments().add(d2);

        JAXBContext context = JAXBContext.newInstance(Company.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.marshal(c, System.out);
    }
}

The following XML is produced:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
    <employee firstname="Joe" lastname="Smith">
        <empId ID="1"/>
        <department ID="D1"/>
    </employee>
    <employee firstname="John" lastname="Doe">
        <empId ID="2"/>
        <manager ID="1"/>
        <department ID="D1"/>
    </employee>
    <department>
        <deptId ID="D1"/>
    </department>
    <department>
        <deptId ID="D2"/>
    </department>
</company>

Since you have an embedded tag employees and departments you will want to have another couple classes to handle that level of nesting. See if this works for you.

See this reference and this reference for additional info.

Community
  • 1
  • 1
Ryan J
  • 8,275
  • 3
  • 25
  • 28
  • Thanks for the detailed reply Ryan. But the problem is that i do not have control over the xml format. It is generated by a third party application. I need to use that data to do further processing. – Himanshu Jun 24 '14 at 00:18
  • All is not lost, you will just need to have a couple extra classes to hold the data you need. See my edits and give it a shot. – Ryan J Jun 24 '14 at 01:33
  • Thanks again Ryan. This works but with a caveat, there cannot be foreign keys. i.e., Employee object would contain a DepartmentID key which would be different than DepartmentID key for that department. – Himanshu Jun 24 '14 at 14:43
  • Not sure I follow, but I'm glad to hear you got further. Let me know if I can be of further help. – Ryan J Jun 24 '14 at 16:16
  • What I am looking for is something similar to this use of @XmlIDREF to refer to other objects instead of creating an instance of ID: http://stackoverflow.com/questions/15635318/jaxb-xmlidref-xmlid-work-amazingly i.e., Employee should contain an object of type Department instead of "DepartmentID" and another object of type "Employee" instead of "EmployeeID" called manager – Himanshu Jun 28 '14 at 02:20
  • XMLIDRef requires that the field you refer to (the XMLID) be a String. Since the XML format has an attribute for the ID rather than just a value, it requires the use of an additional class object to fully represent it. If you try to use XMLIDRef on the Employee or Department object in this manner, it will expand the entire tag, rather than just refer to the ID when you marshal it. – Ryan J Jun 28 '14 at 18:30