JAXB xml string to java object - unexpected element - java

Please help!
I am trying to unmarshall the below XML STRING to a java class. The requirement is only to grab some elements and not all:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type='text/xsl' href='http://myService/rs/../xsl/searchRetrieveResponse.xsl'?>
<searchRetrieveResponse
xmlns="http://www.loc.gov/zing/srw/"
xmlns:srw5="info:srw/extension/5/restrictorSummary">
<version>1.2</version>
<numberOfRecords>1</numberOfRecords>
<records>
<record>
<recordSchema>info:srw/schema/1/CDFXML</recordSchema>
<recordPacking>xml</recordPacking>
<recordData>
<institution active="true" test="true" training="false"
xmlns="info:rfa/rfaRegistry/xmlSchemas/institution"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="info:rfa/rfaRegistry/xmlSchemas/institution http://worldcat.org/registry/xsd/collections/Institutions/institution.xsd">
<identifier>info:rfa/Institutions/113500</identifier>
<versionID>2016-02-17T20:01:22.355Z</versionID>
<nameLocation
xmlns="info:rfa/rfaRegistry/xmlSchemas/institutions/nameLocation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="info:rfa/rfaRegistry/xmlSchemas/institutions/nameLocation http://worldcat.org/registry/xsd/collections/Institutions/nameLocation.xsd">
<lastUpdated>2015-09-27</lastUpdated>
<lastUpdatedTime>03:06:43</lastUpdatedTime>
<first>First Name</first>
</nameLocation>
<identifiers
xmlns="info:rfa/rfaRegistry/xmlSchemas/institutions/identifiers"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="info:rfa/rfaRegistry/xmlSchemas/institutions/identifiers http://worldcat.org/registry/xsd/collections/Institutions/identifiers.xsd">
<lastUpdated>2016-02-17</lastUpdated>
<lastUpdatedTime>15:01:22</lastUpdatedTime>
<age>23</age>
<age>55</age>
</identifiers>
<opac available="true" intranetOnly="false"
xmlns="info:rfa/rfaRegistry/xmlSchemas/institutions/opac"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="info:rfa/rfaRegistry/xmlSchemas/institutions/opac http://worldcat.org/registry/xsd/collections/Institutions/opac.xsd">
<lastUpdated>2009-12-03</lastUpdated>
<lastUpdatedTime>17:43:52</lastUpdatedTime>
<url1>facebook</url1>
<url2>google</url2>
<prefix/>
</opac>
</institution>
</recordData>
<recordPosition>1</recordPosition>
</record>
</records>
</searchRetrieveResponse>
From this file I am only looking to map these tags in my java class below
<first> <age> <age> <url1> <url2>
Java class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "searchRetrieveResponse")
public class MyInfo {
#XmlElement(name = "first")
private String first;
#XmlElement(name = "age")
private List<String> age;
#XmlElement(name = "url1")
private String url1;
#XmlElement(name = "url2")
private String url2;
}
Unmarshalling implementation:
public static void main(String[] args) {
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(MyInfo.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
MyInfo myInfo = (MyInfo) jaxbUnmarshaller.unmarshal(
new StringReader( * * MY_XML_STRING **));
catch(JAXBException ex){
log.error("Error - ", ex);
}
}
Error:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.loc.gov/zing/srw/", local:"searchRetrieveResponse"). Expected elements are <{}searchRetrieveResponse>
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:262)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1149)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:574)...
In My gradle dependencies:
jaxbApi : "javax.xml.bind:jaxb-api:2.4.0-b180830.0359",
jaxbImpl : "com.sun.xml.bind:jaxb-impl:2.4.0-b180830.0438",
jaxbCore : "org.glassfish.jaxb:jaxb-core:2.3.0.1",
And java 11 is the complier.

Add: , namespace = "http://www.loc.gov/zing/srw/"
to your #XmlRootElement:
#XmlRootElement(name = "searchRetrieveResponse", namespace = "http://www.loc.gov/zing/srw/")
...this is what the error message complains about: A mismatch in the namespace!
unexpected element (uri:"http://www.loc.gov/zing/srw/", local:"searchRetrieveResponse").
Expected elements are <{}searchRetrieveResponse>
The {} means empty ("") namespace, in this case.
If namespace omit, it defaults to "##default"...
If the value is "##default", then the XML namespace name is derived from the package of the class ( XmlSchema ). If the package is unnamed, then the XML namespace is the default empty namespace.
EDIT:
In your scenario, I would generate the classes with (built-in) xjc (command line tool ...in ${java.home}/bin)
xjc -d generated <schema>
...where gnerated will be the output folder for the classes (.java files) and <schema> can be a file URL or (structured)directory (with your (readonly) xsd(s)).
Once successfully generated, copy the content of generated into your "main source folder", check it in(, use it) and only change it, when xsd changes.

Related

Generate dynamic xml file through jaxB

I want to generate this below mentioned xml file from my multiple action classes in struts2.
I perform multiple below mentioned operations from my Struts 2 action classes and adding them in single existing xml file.
1) Adding news in xml file
2) Adding footer info in xml file
3) Adding agency info in xml file.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<agencylink>
<agency>
<title>Ministry of Games</title>
<url>http://www.abc.gov.</url>
</agency>
<agencyNews>
<date>22/Apr/2014</date>
<news>How do I clear my web browsers cache, cookies, and history?</news>
</agencyNews>
<headerLogo>
<img>images/header.jpg</img>
</headerLogo>
<footerText>
<ftxt>All rights reserved.</ftxt>
</footerText>
<aLoginLogo>
<img>images/logo1.jpg</img>
</aLoginLogo>
<aHeaderLogo>
<img>images/logo2.jpg</img>
</aHeaderLogo>
</agencylink>
I am using JaxB.
When i am performing this different-different actions, my xml file is appended with that info but issue is tag name is same when it stored in xml file.
Tag name must be looks like above mentioned xml file.
When i update news information all tag name is changed as <agencyNews>.
So please any one help me to get this xml format through JaxB.
Its my Java Code below
package com.ocr.nsw.xml;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
#XmlRootElement(name = "agencylink")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({ Agency.class, AgencyNews.class, HeaderLogo.class,
FooterText.class, ALoginLogo.class, AHeaderLogo.class })
public class AgencyLink {
#XmlElement(name = "agencyNews")
private List<AgencyNews> adate;
#XmlElement(name = "agencyNews")
private List<AgencyNews> anews;
#XmlElement(name = "agency")
private List<Agency> atitle;
#XmlElement(name = "agency")
private List<Agency> aurl;
#XmlElement(name = "footerText")
private List<FooterText> aftxt;
#XmlElement(name = "headerLogo")
private List<HeaderLogo> headerLogoImg;
#XmlElement(name = "aLoginLogo")
private List<ALoginLogo> loginLogoImg;
#XmlElement(name = "aHeaderLogo")
private List<AHeaderLogo> aHeaderLogoImg;
}
_____
public static void xmlWrite(List list, String filePath) {
AgencyLink agencyLink = new AgencyLink();
agencyLink.setAurl(null);
agencyLink.setAnews(list);
agencyLink.setAtitle(null);
agencyLink.setAftxt(null);
agencyLink.setHeaderLogoImg(null);
agencyLink.setLoginLogoImg(null);
agencyLink.setaHeaderLogoImg(null);
if (marshalling(filePath, agencyLink)) {
System.out.println("Success");
}
}
------
#SuppressWarnings("rawtypes")
public static Object unMarshalling(String filePath, Class clazz) {
try {
File file = new File(filePath);
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Object obj = clazz.cast(jaxbUnmarshaller.unmarshal(file));
return obj;
} catch (JAXBException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
From this code i got this below mentioned XML File
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<agencylink>
<agencyNews xsi:type="agency" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<title>Ministry of Health</title>
<url>http://www.abc.gov.bn</url>
</agencyNews>
<agencyNews>
<date>22/Apr/2014</date>
<news>How do I clear my web browsers cache, cookies, and history?</news>
</agencyNews>
<agencyNews>
<date>20/10/2013</date>
<news>10</news>
</agencyNews>
<agencyNews xsi:type="headerLogo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<img>images/header.jpg</img>
</agencyNews>
<agencyNews xsi:type="footerText" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ftxt>All rights reserved</ftxt>
</agencyNews>
<agencyNews xsi:type="aLoginLogo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<img>images/logo1.jpg</img>
</agencyNews>
<agencyNews xsi:type="aHeaderLogo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<img>images/logo2.jpg</img>
</agencyNews>
</agencylink>

JAXB Unmarshalling not working. Expected elements are (none)

I am trying to unmarshal an XML.
This is what my XML looks like
<DeviceInventory2Response xmlns="http://tempuri.org/">
<DeviceInventory2Result xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Obj123 xmlns="">
<Id>1</Id>
<Name>abc</Name>
</Obj123>
<Obj456 xmlns="">
.
.
.
I am trying to get Id and Name under Obj123. However when I run my unmarshal command I get the following error.
An Error: javax.xml.bind.UnmarshalException: unexpected element (uri:"http://tempuri.org/", local:"DeviceInventory2Response"). Expected elements are (none)
My code looks like this in the main class:
Obj123 myObj123 = (Obj123) unmarshaller.unmarshal(inputSource);
And my class for Obj123 looks like this:
package com.myProj.pkg;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name="Obj123")
public class Obj123 {
private String Id;
private String Name;
public String getId() {
return Id;
}
public String getName() {
return Name;
}
}
I thought by setting my XMLRootElement that I should be able to skip the first 2 lines of my XML but that doesn't seem to be happening. Any ideas?
Edit:
This is how my JAXB Context is made:
JAXBContext jaxbContext = JAXBContext.newInstance();
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Obj123 obj123 = (Obj123) unmarshaller.unmarshal(xmlStreamReader);
I solved the problem by adding
#XmlRootElement(name="abc_xxx") to the Root class.(where abc_XXX is the root tag of your XML)
The JAXB classes generated by eclipse didn't add this annotation to my root class.
JAXB implementations will try to match on the root element of the document (not on a child element).
If you want to unmarshal to the middle of an XML document then you can parse the document with StAX advance the XMLStreamReader to the desired element and then unmarshal that.
For More Information
http://blog.bdoughan.com/2012/08/handle-middle-of-xml-document-with-jaxb.html
UPDATE
now I am getting the following error. An Error:
javax.xml.bind.UnmarshalException - with linked exception:
[javax.xml.bind.UnmarshalException: unexpected element (uri:"",
local:"Obj123"). Expected elements are (none)].
A JAXBContext only knows about the classes you tell it about. Instead of:
JAXBContext jaxbContext = JAXBContext.newInstance();
You need to do:
JAXBContext jaxbContext = JAXBContext.newInstance(Obj123.class);
Use ObjectFactory class instead like
JAXBContext jaxbContext = null;
try {
jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
} catch (JAXBException e) {
e.printStackTrace();
}
JAXBElement<ObjectFactory> applicationElement = null;
try {
applicationElement = (JAXBElement<ObjectFactory>)
unmarshaller.unmarshal(Thread.currentThread().getClass()
.getResourceAsStream(fileName));
} catch (JAXBException e) {
e.printStackTrace();
}
Try this and will resolve above problem. My problem has been resolved.

How to remove some elements from XML file generated using JAXB?

I have been trying to generate XML file from lists of object of type Customer class.
Which i have done successfully.But the structure of my XML file is nested and i want to flatten it out.
Following is my XML file content:
<Customers>
<customer>
<accessRole>
<name>Customer Center</name>
<internalId>14</internalId>
</accessRole>
<aging>0.0</aging>
<category>
<name>Individual</name>
<internalId>2</internalId>
</category>
<companyName>Wolfe Electronics</companyName>
<consolAging>0.0</consolAging>
<consolBalance>0.0</consolBalance>
<consolDepositBalance>0.0</consolDepositBalance>
<consolOverdueBalance>0.0</consolOverdueBalance>
<consolUnbilledOrders>2705.23</consolUnbilledOrders>
<creditHoldOverride/>
<dateCreated>2011-06-22T12:30:00+05:30</dateCreated>
<defaultAddress>US</defaultAddress>
<displaySymbol>$</displaySymbol>
<email>suresh#ldbsystems.com</email>
<emailPreference/>
<emailTransactions>false</emailTransactions>
<entityId>A Wolfe</entityId>
<entityStatus>
<name>CUSTOMER-Closed Won</name>
<internalId>13</internalId>
</entityStatus>
<externalId>entity-5</externalId>
<faxTransactions>false</faxTransactions>
<firstName>A</firstName>
<firstVisit>2012-02-25T05:43:18+05:30</firstVisit>
<giveAccess>true</giveAccess>
<globalSubscriptionStatus/>
<internalId>-5</internalId>
<isBudgetApproved>false</isBudgetApproved>
<isInactive>false</isInactive>
<isPerson>true</isPerson>
<lastModifiedDate>2012-12-19T07:12:03+05:30</lastModifiedDate>
<lastName>Wolfe</lastName>
<lastPageVisited>login-register</lastPageVisited>
<lastVisit>2013-02-23T06:10:44+05:30</lastVisit>
<overrideCurrencyFormat>false</overrideCurrencyFormat>
<phone>650-555-9788</phone>
<priceLevel>
<name>Employee Price</name>
<internalId>3</internalId>
</priceLevel>
<printTransactions>false</printTransactions>
<receivablesAccount>
<name>Use System Preference</name>
<internalId>-10</internalId>
</receivablesAccount>
<salesRep>
<name>Clark Koozer</name>
<internalId>23</internalId>
</salesRep>
<shipComplete>false</shipComplete>
<stage/>
<symbolPlacement/>
<taxItem>
<name>CA-SAN MATEO</name>
<internalId>-112</internalId>
</taxItem>
<taxable>false</taxable>
<unbilledOrders>2705.23</unbilledOrders>
<visits>150</visits>
<webLead>No</webLead>
</customer>
<customer>
<accessRole>
<name>Customer Center</name>
<internalId>14</internalId>
</accessRole>
<aging>0.0</aging>
<category>
<name>Corporate</name>
<internalId>1</internalId>
</category>
<consolAging>0.0</consolAging>
<consolBalance>0.0</consolBalance>
<consolDepositBalance>0.0</consolDepositBalance>
<consolOverdueBalance>0.0</consolOverdueBalance>
<consolUnbilledOrders>76.8</consolUnbilledOrders>
<creditHoldOverride/>
<customFieldList>
<customField/>
</customFieldList>
<dateCreated>2011-06-26T12:30:00+05:30</dateCreated>
<defaultAddress>Anderson Boughton Inc.<br>1488 Main<br>Apt 113<br>Seattle WA 98106<br>US</defaultAddress>
<displaySymbol>$</displaySymbol>
<email>boughton751#cscatering.com</email>
<emailPreference/>
<emailTransactions>false</emailTransactions>
<entityId>Anderson Boughton Inc.</entityId>
<entityStatus>
<name>CUSTOMER-Closed Won</name>
<internalId>13</internalId>
</entityStatus>
<faxTransactions>false</faxTransactions>
<firstVisit>2012-07-12T01:30:49+05:30</firstVisit>
<giveAccess>false</giveAccess>
<globalSubscriptionStatus/>
<internalId>75</internalId>
<isBudgetApproved>false</isBudgetApproved>
<isInactive>false</isInactive>
<isPerson>false</isPerson>
<lastModifiedDate>2012-12-19T11:50:14+05:30</lastModifiedDate>
<lastPageVisited>HP xw4100</lastPageVisited>
<lastVisit>2012-07-12T01:30:49+05:30</lastVisit>
<leadSource>
<name>Partner Referral</name>
<internalId>99993</internalId>
</leadSource>
<overrideCurrencyFormat>false</overrideCurrencyFormat>
<partner>
<name>Online electronics</name>
<internalId>171</internalId>
</partner>
<phone>206-555-1302</phone>
<priceLevel>
<name>Base Price</name>
<internalId>1</internalId>
</priceLevel>
<printTransactions>false</printTransactions>
<receivablesAccount>
<name>Use System Preference</name>
<internalId>-10</internalId>
</receivablesAccount>
<salesRep>
<name>A Wolfe</name>
<internalId>-5</internalId>
</salesRep>
<shipComplete>false</shipComplete>
<stage/>
<symbolPlacement/>
<taxable>false</taxable>
<unbilledOrders>76.8</unbilledOrders>
<webLead>No</webLead>
</customer>
</Customers>
So i have nested structure for <accessRole> which i want to flatten out like
<accessRole-name>and i don't want to display element like <internalId>.
Please find a code snippet of my model:
try {
FileWriter fileWriter = new FileWriter ("D:\\adapter-framework\\Customer_XML.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(extractedRecordsArray[0].getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
fileWriter.append("<Customers>");
fileWriter.append('\n');
for(int i = 0; i < extractedRecordsArray.length - 761 ; i++)
{
jaxbMarshaller.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//jaxbMarshaller.marshal(extractedRecordsArray[i],fileWriter);
jaxbMarshaller.marshal(extractedRecordsArray[i],System.out);
fileWriter.append('\n');
AdapterLogger.debug(this.getClass().getName(), "Extracted record number : " + i);
}
fileWriter.append("</Customers>");
fileWriter.close();
} catch (JAXBException e) {
e.printStackTrace();
}
Please help me out if someone knows about it.
Thanks.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
You can use the #XmlPath extension in MOXy to flatten the XML structure.
Customer
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
#XmlPath(".")
private AccessRole accessRole;
}
AccessRole
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class AccessRole {
#XmlElement(name="accessRoleName")
private String name;
}
For More Information
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html

JAXB/xjc: Generate classes from child elements and load them based on class types

I have a configuration file in XML, which looks something like:
<configuration>
<database>
<host></host>
<port></port>
</database>
<queue>
<host></host>
<port></port>
<type></type>
</queue>
</configuration>
I would like to use JAXB/xjc to generate Java classes for this configuration, however I would like to generate these classes and unmarshal these one level into the tree. Rather than receiving a Configuration.java, I would like a Database.java and Queue.java (in order that these can be separately injected into a Guice managed application). I don't (currently) see any way of doing this, however may be searching for the wrong things.
After some experimentation, I have found a solution to generate these classes and be able to populate and return these based on class:
First, I added a bindings.xjb file which will generate the contained classes (Database and Queue in this example)
<jaxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings localScoping="toplevel"/>
</jaxb:bindings>
However, JAXB can't unmarshall using the Database or Queue class, only the Configuration class (this is where I may have missed something). I can do
JAXBContext context = JAXBContext.newInstance(Configuration.class);
Unmarshaller um = context.createUnmarshaller();
Configuration conf = (Configuration) um.unmarhal(xmlFile);
but not
JAXBContext context = JAXBContext.newInstance(Database.class);
Unmarshaller um = context.createUnmarshaller();
Database db = (Database) um.unmarhal(xmlFile);
However, because I can get the database object by calling getDatabase() on an instance of the Configuration object, this can also be made generic using reflection (making this code cache results in the appropriate places is another exercise):
T item = null;
try {
JAXBContext context = JAXBContext.newInstance(Configuration.class);
Unmarshaller um = context.createUnmarshaller();
Configuration conf = (Configuration) um.unmarshal(xmlFile);
Method[] allMethods = Configuration.class.getDeclaredMethods();
for (Method method : allMethods)
{
if (method.getReturnType().equals(clazz))
{
item = (T) method.invoke(conf);
break;
}
}
} catch (JAXBException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new ConfigException("Failure detected while loading configuration", e);
}
return item;
I'm not sure this is the best solution (I only started working with JAXB yesterday), but seems to fulfill my goal.
That particular XML would correspond to a Configuration class that had properties of type Database and Queue. Isn't this what you are looking for?
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Configuration {
private Database database;
private Queue queue;
}
I am answering this question with my solution to the problem as discussed in the question. This meets my requirements:
After some experimentation, I have found a solution to generate these classes and be able to populate and return these based on class:
First, I added a bindings.xjb file which will generate the contained classes (Database and Queue in this example)
<jaxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings localScoping="toplevel"/>
</jaxb:bindings>
However, JAXB can't unmarshall using the Database or Queue class, only the Configuration class (this is where I may have missed something). I can do
JAXBContext context = JAXBContext.newInstance(Configuration.class);
Unmarshaller um = context.createUnmarshaller();
Configuration conf = (Configuration) um.unmarhal(xmlFile);
but not
JAXBContext context = JAXBContext.newInstance(Database.class);
Unmarshaller um = context.createUnmarshaller();
Database db = (Database) um.unmarhal(xmlFile);
However, because I can get the database object by calling getDatabase() on an instance of the Configuration object, this can also be made generic using reflection (making this code cache results in the appropriate places is another exercise):
T item = null;
try {
JAXBContext context = JAXBContext.newInstance(Configuration.class);
Unmarshaller um = context.createUnmarshaller();
Configuration conf = (Configuration) um.unmarshal(xmlFile);
Method[] allMethods = Configuration.class.getDeclaredMethods();
for (Method method : allMethods)
{
if (method.getReturnType().equals(clazz))
{
item = (T) method.invoke(conf);
break;
}
}
} catch (JAXBException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new ConfigException("Failure detected while loading configuration", e);
}
return item;
This allows me to get an unmarshalled Database by passing Database.class without needing to hardcode methods for ever configuration parameter. These can then be injected where needed without needing to inject the entire unmarshalled XML file.
Step1: Create 3 classes configuration.java, database.java, queue.java
configuration.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "configuration")
public class configuration{
#XmlElement
private database db;
#XmlElement
private queue q;
...
}
#XmlAccessorType(XmlAccessType.FIELD)
public class database{
#XmlElement
private String host;
#XmlElement
private String port;
....
}
-------------------------
InputStream xmlStream = new FileInputStream(config.xml);
JAXBContext jaxbContext = JAXBContext.newInstance(configuration.class, database.class,queue.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
configuration config= (configuration) jaxbUnmarshaller.unmarshal(xmlStream);
config.getDatabase().getHost(); //returns the host
config.getDatabase().getPort(); //returns the port
------------------------------------

Can I get MOXy to rename an element when generating json?

From a common JAXB model the xml generated can be of the form
<ipi-list><ipi>1001</ipi><ipi>1002</ipi></ipi-list>
because in json we have arrays we dont need both elements, so by using MOXy's oxml extensions I can flatten the output to give
"ipi" : [ "1001", "1002" ],
but because ipi now refers to an array of things I would like it to be called ipis not ipi
"ipis" : [ "1001", "1002" ],
Is there a way to get MOXy to rename an element ?
You could use EclipseLink JAXB (MOXy)'s external mapping document to tweak the mapping for either the XML or JSON representation.
IPIList
Below is a domain class with JAXB annotations that matches the XML representation from your question:
package forum11449219;
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="ipi-list")
public class IPIList {
private List<String> list = new ArrayList<String>();
#XmlElement(name="ipi")
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}
oxm.xml
We can use MOXy's external mapping document to modify how the list property is mapped to JSON.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum11449219">
<java-types>
<java-type name="IPIList">
<java-attributes>
<xml-element java-attribute="list" name="ipis"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see ):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
The following demo code shows how to reference the external mapping document when creating a JAXBContext.
package forum11449219;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
IPIList ipiList = new IPIList();
ipiList.getList().add("1001");
ipiList.getList().add("1002");
// XML
JAXBContext jc = JAXBContext.newInstance(IPIList.class);
Marshaller xmkMarshaller = jc.createMarshaller();
xmkMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
xmkMarshaller.marshal(ipiList, System.out);
// JSON
Map<String, Object> properties = new HashMap<String, Object>(3);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum11449219/oxm.xml");
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jsonJC = JAXBContext.newInstance(new Class[] {IPIList.class}, properties);
Marshaller jsonMarshaller = jsonJC.createMarshaller();
jsonMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jsonMarshaller.marshal(ipiList, System.out);
}
}
Output
Here is the output from running the demo code:
<?xml version="1.0" encoding="UTF-8"?>
<ipi-list>
<ipi>1001</ipi>
<ipi>1002</ipi>
</ipi-list>
{
"ipis" : [ "1001", "1002" ]
}
For More Information
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://blog.bdoughan.com/2012/04/extending-jaxb-representing-metadata-as.html
http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html

Categories

Resources