I have to create object model for following XMLs:
XML sample 1:
<InvoiceAdd>
<TxnDate>2009-01-21</TxnDate>
<RefNumber>1</RefNumber>
<InvoiceLineAdd>
</InvoiceLineAdd>
</InvoiceAdd>
XML Sample 2:
<SalesOrderAdd>
<TxnDate>2009-01-21</TxnDate>
<RefNumber>1</RefNumber>
<SalesOrderLineAdd>
</SalesOrderLineAdd>
</SalesOrderAdd>
The XML output will be based on a single string parameter or enum. String txnType = “Invoice”; (or “SalesOrder”);
I would use single class TransactionAdd:
@XmlRootElement
public class TransactionAdd {
public String txnDate;
public String refNumber;
private String txnType;
...
public List<LineAdd> lines;
}
instead of using subclasses or anything else. The code which creates the TransactionAdd instance is the same for both types of transaction it only differs on the type.
This XML is used by a rather known product called QuickBooks and is consumed by QuickBooks web service – so I can’t change the XML, but I want to make it easy to be able to set element name based on property (txnType).
I would consider something like a method to determine target element name:
@XmlRootElement
public class TransactionAdd {
public String txnDate;
public String refNumber;
private String txnType;
...
public List<LineAdd> lines;
public String getElementName() {
return txnType + "Add";
}
}
Different transactions will be created using following code:
t = new TransactionAdd();
t.txnDate = "2010-12-15";
t.refNumber = "123";
t.txnType = "Invoice";
The goal is to serialize t object with the top-level element name based on txnType. E.g.:
<InvoiceAdd>
<TxnDate>2009-01-21</TxnDate>
<RefNumber>1</RefNumber>
</InvoiceAdd>
In case of t.txnType = “SalesOrder” the result should be
<SalesOrderAdd>
<TxnDate>2009-01-21</TxnDate>
<RefNumber>1</RefNumber>
</SalesOrderAdd>
At the moment I see only one workaround with subclasses InvoiceAdd and SalesOrderAdd and using @XmlElementRef annotation to have a name based on class name. But it will need to instantiate different classes based on transaction type and also will need to have two other different classes InvoiceLineAdd and SalesOrderLineAdd which looks rather ugly.
Please suggest me any solution to handle this. I would consider something simple.
To address the root element aspect you could do will need to leverage @XmlRegistry and @XmlElementDecl. This will give us multiple possible root elements for the TransactionAdd class:
Your TransactionAdd class will look something like the following. The interesting thing to note is that we will make the txnType property @XmlTransient.
Then we need to supply a little logic outside the JAXB operation. For an unmarshal we will use the local part of the root element name to populate the txnType property. For a marshal we will use the value of the txnType property to create the appropriate JAXBElement.
To Do
I will look into addressing the lines property next.