Reputation: 14187
I am not so familiar to JAXB but this is the context I have, please read everything to understand.
1. I am doing the following to get a value using JAXB from this XML...
XML Document snippet (Original):
<Request deploymentMode="production">
<OrderRequest>
<OrderRequestHeader orderID="12345" orderDate="2012-07-04" type="new">
<Total>
<Money currency="USD">200.0</Money>
</Total>
<ShipTo>
<Address>
<Name xml:lang="">Test</Name>
<PostalAddress name="default">
<DeliverTo/>
<Street>Value 1</Street>
<City>Value 2</City>
<State>Value 3</State>
<PostalCode>302010</PostalCode>
<Country isoCountryCode="US">USA</Country>
</PostalAddress>
</Address>
</ShipTo>
So, the value I want is the State
from PostalAddress
and I use this code:
String state = xml.getRequest().getOrderRequest().getOrderRequestHeader().getShipTo().getAddress().getPostalAddress().getState();
//This will return "Value 3"
And everything works good.
2. The problem starts at this point, I will do the same as above but using now this XML...
XML Document snippet (Other):
<Request deploymentMode="production">
<OrderRequest>
<OrderRequestHeader orderID="12345" orderDate="2012-07-04" type="new">
<Total>
<Money currency="USD">200.0</Money>
</Total>
<ShipTo>
<Address>
<Name xml:lang="">Test</Name>
</Address>
</ShipTo>
Well, I know that the value doesn't exist but I don't want to make any change to my code and still using this:
String state = xml.getRequest().getOrderRequest().getOrderRequestHeader().getShipTo().getAddress().getPostalAddress().getState();
The above code will produce a NullPointerException
and stop the process. What I need is not to stop the process cause this is not the only value I am extracting from XML (this is just an example of what I am dealing with). So, If the value can't be found, then I want that my state
variable be null
automatically.
Q: Is there a way for not producing and exception and make my string variable state
just null
if the value can't be found?
PS. A possible solution could be to do something like this:
//Fill the entity
PostalAddressType p = xml.getRequest().getOrderRequest().getOrderRequestHeader().getShipTo().getAddress().getPostalAddress();
//Variable for state
String state = null;
//Evaluate if it is null or not
if(p != null)
//Capture the value if not null
state = p.getState();
But I don't like to make an if
statement for every entity of my XML. As I said, I want something automate without modifying the code and I don't know if there is some JAXB configuration or something to do for this.
Thanks in advance.
Upvotes: 0
Views: 414
Reputation: 149047
JAXB (JSR-222) is the Java standard for converting objects to/from XML. There are multiple open source implementations. The objects JAXB uses are POJOs (plain old Java objects). There isn't any sort of XML logic baked into these classes. Since JAXB is designed to work with existing classes there may be some logic that can be worked out to support your use case. Below are a couple of options.
OPTION #1 - Lazy Load the PostalAddress Property (Not Recommended)
Address
You could add logic to the getPostalAddress()
method to instantiate an instance of PostalAddress
if the property is null
.
package forum11333165;
import javax.xml.bind.annotation.*;
@XmlRootElement(name="Address")
public class Address {
private String name;
private PostalAddress postalAddress;
@XmlElement(name="Name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlElement(name="PostalAddress")
public PostalAddress getPostalAddress() {
if(null == postalAddress) {
postalAddress = new PostalAddress();
}
return postalAddress;
}
public void setPostalAddress(PostalAddress postalAddress) {
this.postalAddress = postalAddress;
}
}
PostalAddress
package forum11333165;
import javax.xml.bind.annotation.XmlElement;
public class PostalAddress {
private String state;
@XmlElement(name="State")
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
Demo
The demo code below demonstrates that you will be able to
package forum11333165;
import java.io.StringReader;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Address.class);
StringReader xml = new StringReader("<Address><Name>Test</Name></Address>");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Address address = (Address) unmarshaller.unmarshal(xml);
System.out.println(address.getPostalAddress().getState());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(address, System.out);
}
}
Output
Below is the output from running the demo code. As you can see we got the null
value we were looking for, but out output contains an extra PostalAddress
method.
null
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Address>
<Name>Test</Name>
<PostalAddress/>
</Address>
OPTION #2 - If Property is Null Return a New Instance (Not Recommended)
Address
package forum11333165;
import javax.xml.bind.annotation.*;
@XmlRootElement(name="Address")
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
@XmlElement(name="Name")
private String name;
@XmlElement(name="PostalAddress")
private PostalAddress postalAddress;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PostalAddress getPostalAddress() {
if(null == postalAddress) {
return new PostalAddress();
}
return postalAddress;
}
public void setPostalAddress(PostalAddress postalAddress) {
this.postalAddress = postalAddress;
}
}
Output
We can use the same demo code from the previous option to produce the new output. The get still works, and we don't get the extra PostalAddress
method. The down side is the state we thought we set was not captured.
null
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Address>
<Name>Test</Name>
</Address>
Option #3 - Check Value is Not Null Before Calling Get On It
This options is a little more work, but will ultimately make your application easier to maintain.
Upvotes: 1