Input XML Document
The following is the sample document used on the Google Maps Geocoding API V2 page.
<?xml version="1.0" encoding="UTF-8" ?> <kml xmlns="http://earth.google.com/kml/2.0"> <Response> <name>1600 Amphitheatre Parkway, Mountain View, CA</name> <Status> <code>200</code> <request>geocode</request> </Status> <Placemark id="p1"> <address>1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA </address> <AddressDetails Accuracy="8" xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"> <Country> <CountryNameCode>US</CountryNameCode> <CountryName>USA</CountryName> <AdministrativeArea> <AdministrativeAreaName>CA</AdministrativeAreaName> <SubAdministrativeArea> <SubAdministrativeAreaName>Santa Clara</SubAdministrativeAreaName> <Locality> <LocalityName>Mountain View</LocalityName> <Thoroughfare> <ThoroughfareName>1600 Amphitheatre Pkwy</ThoroughfareName> </Thoroughfare> <PostalCode> <PostalCodeNumber>94043</PostalCodeNumber> </PostalCode> </Locality> </SubAdministrativeArea> </AdministrativeArea> </Country> </AddressDetails> <ExtendedData> <LatLonBox north="37.4251799" south="37.4188847" east="-122.0813633" west="-122.0876585" /> </ExtendedData> <Point> <coordinates>-122.0829964,37.4217080,0</coordinates> </Point> </Placemark> </Response> </kml>
Java Model - Address
In this example we will map a portion of the geocode data to a typical address object. Here we will make use of MOXy's @XmlPath annotation. The get/set methods have been omitted to save space.
The namespace qualification of the XPath corresponds to the configuration in the @javax.xml.bind.annotation.XmlSchema annotation on the package-info class. XPath fragments with out a prefix correspond to the default namespace ("http://earth.google.com/kml/2.0"), and fragments prefixed with "ns" correspond to the namespace "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0".
package blog.geocode; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement(name="kml") @XmlType(propOrder={"country", "state", "city", "street", "postalCode"}) public class Address { @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:Thoroughfare/ns:ThoroughfareName/text()") private String street; @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:LocalityName/text()") private String city; @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:AdministrativeAreaName/text()") private String state; @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:CountryNameCode/text()") private String country; @XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:PostalCode/ns:PostalCodeNumber/text()") private String postalCode; }
Java Model - package-info
We will supply a package-info class to specify the namespace qualication, and field access.
@XmlSchema( namespace="http://earth.google.com/kml/2.0", xmlns={ @XmlNs(prefix="ns", namespaceURI="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0") }, elementFormDefault=XmlNsForm.QUALIFIED) @XmlAccessorType(XmlAccessType.FIELD) package blog.geocode; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlNs; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema;
Java Model - jaxb.properties
In order to specify that we are using the MOXy JAXB implementation we need to put a file called jaxb.properties in with our Address class with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo Code
The following code can be used to demonstrate our mapping. In the URL creation be sure to replace the string "YOUR_KEY_HERE" with your own API key. If you do not have one, you can create one here.
package blog.geocode; import java.io.InputStream; import java.net.URL; 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(Address.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); URL xmlURL = new URL("http://maps.google.com/maps/geo?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA&output=xml&sensor=false&key=YOUR_KEY_HERE"); InputStream xml = xmlURL.openStream(); Address address = (Address) unmarshaller.unmarshal(xml); xml.close(); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(address, System.out); } }
Output
The following is the output from running our Demo class. Note that only the portion of the document that we mapped will be output to XML.
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://earth.google.com/kml/2.0" xmlns:ns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"> <Response> <Placemark> <ns:AddressDetails> <ns:Country> <ns:CountryNameCode>US</ns:CountryNameCode> <ns:AdministrativeArea> <ns:AdministrativeAreaName>CA</ns:AdministrativeAreaName> <ns:SubAdministrativeArea> <ns:Locality> <ns:LocalityName>Mountain View</ns:LocalityName> <ns:Thoroughfare> <ns:ThoroughfareName>1600 Amphitheatre Pkwy</ns:ThoroughfareName> </ns:Thoroughfare> <ns:PostalCode> <ns:PostalCodeNumber>94043</ns:PostalCodeNumber> </ns:PostalCode> </ns:Locality> </ns:SubAdministrativeArea> </ns:AdministrativeArea> </ns:Country> </ns:AddressDetails> </Placemark> </Response> </kml>
Further Reading:
If you enjoyed this post you may also be interested in:
Blaise,
ReplyDeleteIs it possible to annotate the fields (assume default namesapce)
@XmlPath("//Point/coordinates") instead of
@XmlPath("Response/Placemark/Point/coordinates")
Using the "any-level descendant" syntax doesn't work as in I get values as null. Thanks for your help and excellent tutorial on moxy impl.
Hi JT,
ReplyDeleteThe reason we don't allow the "any-level" concept frpm XPath is that we require that information when marshalling to XML.
Are you interested in this type of functionality for unmarshal only use cases?
-Blaise
Hi,
ReplyDeleteI'd be definitely interested in unmarshal-only use-cases.
Zdenek
Hi Zdenek,
ReplyDeleteSorry for the delay in responding. I haven't had a chanve to post an example yet, but if you want to try somethings out yourself just include your XPath in the @XmlPath annotation and make the following magic call after you create your JAXBContext:
JAXBHelper.getJAXBContext(jc).getXMLContext().getSession(0).getDatasourceLogin().setDatasourcePlatform(new DOMPlatform());
-Blaise
This is really exciting.
ReplyDeleteUnfourtnately I get exception:
javax.servlet.ServletException: java.lang.NoSuchMethodError: org.eclipse.persistence.oxm.NamespaceResolver.hasPrefixesToNamespaces()Z
Which environment are you running in? It appears as though you may be using the EclipseLink OSGi bundles, and using a new MOXy bundle and an older core bundle.
Delete-Blaise
This tutorial is great, However when I try to unmarshal a json string to java beans using the code mentioned above I get the following error:
ReplyDeleteException in thread "main" javax.xml.bind.PropertyException: name: eclipselink.media-type value: application/json
at javax.xml.bind.helpers.AbstractMarshallerImpl.setProperty(Unknown Source)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.setProperty(MarshallerImpl.java:533)
at sample.TestJSON.main(TestJSON.java:19)
I have downloaded latest eclipse link jars and have created a jaxb.properties file as well.Can you please help me resolve this problem,
Hi Anusha,
DeleteI have another post covering the JSON aspect of the Geocode API that you may be interested in:
- Binding to JSON & XML - Geocode Example
For that post I have the complete source code available on GitHub:
- https://github.com/bdoughan/blog20110819
-Blaise
Is this propertyException specific to geocoding? I get it too
DeleteExcellent Post..Can you please help me configure EclipseLink MoxY in Spring?
ReplyDeleteThe following should help:
Delete- http://wiki.eclipse.org/EclipseLink/Examples/MOXy/Spring
-Blaise