how to get XmlElement of unmarshaled java object - java

#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Item", propOrder = {
"code",
"name",
"price"
})
#XmlRootElement(name="inventory")
public class Item {
#XmlElement(name="catalog_num", required = true)
protected String code;
#XmlElement(name="catalog_descrip", required = true)
protected String name;
#XmlElement(name="prod_price")
protected double price;
public String getCode() {
return code;
}
JAXBContext databaseJC = JAXBContext.newInstance(Item.class);
Unmarshaller databaseUnmarshaller = databaseJC.createUnmarshaller();
File databaseXML = new File("src/forum6838882/database.xml");
Item item = (Item) databaseUnmarshaller.unmarshal(databaseXML);
My question is:
How could I get the #XmlElement(name="catalog_num", required = true) from item object. I need know the name="catalog_num" here.

JAXB (JSR-222) does not provide an API to introspect the metadata. You can however use the Java Reflection APIs (java.lang.reflect) to get the annotations and examine them yourself.
Demo
import java.lang.reflect.*;
import javax.xml.bind.annotation.*;
public class Demo {
public static void main(String[] args) throws Exception {
Field field = Item.class.getDeclaredField("code");
XmlElement xmlElement = field.getAnnotation(XmlElement.class);
System.out.println(xmlElement.name());
}
}
Output
catalog_num

Related

Parsing XML Failed

I get the following response XML String after calling a SOAP web service. How can i parse the response back to Java entity so that i can handle the ErrMsg and Status accordingly? I tried with the below code, but keep getting error
Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"NewDataSet"). Expected elements are <{TransactionalSubmissionsSvcs}NewDataSet>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
Sample Response in String
<NewDataSet>
<SubmissionResult>
<Status>200</Status>
<RefNo>363180319bigKj83i</RefNo>
<ErrMsg>Successful</ErrMsg>
</SubmissionResult>
</NewDataSet>
Sample Client XML Parser
JAXBContext jaxbContext = JAXBContext.newInstance(NewDataSet.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader("Sample Response in String above");
NewDataSet newDataSet = (NewDataSet) jaxbUnmarshaller.unmarshal(reader);
System.out.println(newDataSet.getSubmissionResult());
NewDataSet.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"submissionResult"
})
#XmlRootElement(name = "NewDataSet")
public class NewDataSet {
#XmlElement(name = "SubmissionResult", required = true)
protected NewDataSet.SubmissionResult submissionResult;
public NewDataSet.SubmissionResult getSubmissionResult() {
return submissionResult;
}
public void setSubmissionResult(NewDataSet.SubmissionResult value) {
this.submissionResult = value;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"status",
"refNo",
"errMsg"
})
public static class SubmissionResult {
#XmlElement(name = "Status")
protected short status;
#XmlElement(name = "RefNo", required = true)
protected String refNo;
#XmlElement(name = "ErrMsg", required = true)
protected String errMsg;
public short getStatus() {
return status;
}
public void setStatus(short value) {
this.status = value;
}
public String getRefNo() {
return refNo;
}
public void setRefNo(String value) {
this.refNo = value;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String value) {
this.errMsg = value;
}
}
}
Note: If possible i prefer to use standard java library or external library that is being maintained regularly and up to date.
It looks like you have many NewDataSet classes in your POJO model. Check this line of code JAXBContext.newInstance(NewDataSet.class) and check import whether you imported correct one because exception says that marshaller expects TransactionalSubmissionsSvcs.NewDataSet.
Before edit
You did not mention what the tool do you use. In case it is Jackson you can parse XML payload as below:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.nio.file.Files;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
String xml = "your xml";
parse(xml);
}
public static void parse(String xml) throws Exception {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
JsonNode root = xmlMapper.readTree(xml);
JsonNode result = root.at("/SendWithXMLResult");
JsonNode jsonNode = xmlMapper.readTree(result.asText());
JsonNode submissionResult = jsonNode.at("/SubmissionResult");
System.out.println(submissionResult.get("Status"));
System.out.println(submissionResult.get("ErrMsg"));
System.out.println(submissionResult.get("RefNo"));
}
}
If you have prepared POJO model you can deserialise XML directly to it using readValue method.
Found the reason, it was resolved by removing the namespace = "TransactionalSubmissionsSvcs"
#javax.xml.bind.annotation.XmlSchema(namespace = "TransactionalSubmissionsSvcs",elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.mailadapter;
to become
#javax.xml.bind.annotation.XmlSchema(elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.mailadapter;

JAXB - how to unmarshal an entity into list of entities with size 1

I have the following JAXB entity:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNER)
public class FilePartner
{
#XmlAttribute(name = EntityConstants.IDENTIFIER, required = true)
private String identifier;
#XmlElement(name = EntityConstants.NAME)
private String name;
#XmlElement(name = EntityConstants.ROOT_PATH)
private String rootPath;
...
}
which serialized into a similar structure:
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
I also have an entity which represents a list of partners:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private List<FilePartner> partners = new ArrayList<FilePartner>();
public List<FilePartner> getPartners()
{
return partners;
}
public void addPartners(List<FilePartner> partners)
{
this.partners.addAll(partners);
}
}
which serializes into:
<partners>
<file-partner identifier="foo">
...
</file-partner>
<file-partner identifier="foo2">
...
</file-partner>
...
</partners>
I am looking for a way to force the jaxb unmarshaller to deserialize XMLs in the form of
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
into FilePartnerList instances with list size of 1, i.e:
JAXBContext context = JAXBContext.newInstance(FilePartner.class, FilePartnerList.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
InputStream inputStream = getResourceAsStream(filePartnerAsXml);
FilePartnerList partnerList = (FilePartnerList) unmarshaller.unmarshal(inputStream); // This SHOULD be unmarshalled to FilePartnerList instead of FilePartner
assertTrue(partnerList.getPartners().getSize().equals(1));
How do I achieve that?
private List<FilePartner> partners = new ArrayList<FilePartner>(**1**);
That way you'll get a fixed size input array....
But I'm sure that you will want to get the XSD of that model with the 'maxocurrs=1' so you will end modifying the XSD manually.
Anyway: why don't you, if the list size must be fixed to '1', simply set it as a simple node with a single child? Something like this (untested):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private FilePartner partners;
public FilePartner getFilePartner()
{
return partner;
}
public void setPartner(FilePartner partner)
{
this.partner = partner;
}
}
This way you will have one and only one partner per parnets-list.
The XML that fullfits the XSD of your service a text and in that text is indistinguible a list with max size 1 and a node.

Make custom xml from javabean

I wants to make xml from javabean like below:
<tag2>message</tag2>
<tag3>message</tag3>
<tag4 id='UNIQUE MT ID 1'>MOBILE No.</tag4>
I tried below code in javabean:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = {"tag2", "tag3", "tag4"})
public class newBean {
#XmlElement(required = true)
private List<String> tag2;
#XmlElement(required = true)
private List<String> tag3;
#XmlElement(required = true)
private List<String> tag4;
#XmlPath("tag4/#id")
private List<String> id;
public List<String> getTag2() {
return tag2;
}
public void setTag2(List<String> tag2) {
this.tag2 = tag2;
}
public List<String> gettag4() {
return tag4;
}
public void settag4(List<String> tag4) {
this.tag4 = tag4;
}
public List<String> getId() {
return id;
}
public void setId(List<String> identifier) {
this.id = identifier;
}
public List<String> gettag3() {
return tag3;
}
public void settag3(List<String> tag3) {
this.tag3 = tag3;
}
}
I am getting below error:
Errorcom.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Property id is present but not specified in #XmlType.propOrder
this problem is related to the following location:
at private java.util.List model.newBean.id
at model.newBean
Please help me.I am using #XmlPath tag and generating error.I searched alot and found that #XmlPath usage is same as above i used but still getting error.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
About #XmlPath
#XmlPath is a EclipseLink JAXB (MOXy) extension and requires that you are using MOXy as your JAXB provider:
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
Valid Use Case #1
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
#XmlElement(required=true)
String tag4;
#XmlPath("tag4/#id")
String id;
}
Valid Use Case #2
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
#XmlPath("tag4/#id")
List<String> id;
}
Invalid Use Case
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
#XmlElement(required=true)
List<String> tag4;
#XmlPath("tag4/#id")
List<String> id;
}
Mapping Your Use Case
You could introduce an object that corresponds to the tag4 element that has two properties corresponding to the id attribute and text. This would work with any JAXB (JSR-222) implementation.
newBean
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
List<Tag4> tag4;
}
Tag4
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Tag4 {
#XmlAttribute
private String id;
#XmlValue
private String value;
}
For More Information
http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html

issues while Unmarshalling using JaxB

I have the following XML file to unmarshall
<root>
<emp>Google</emp>
<emp>Yahoo</emp>
<xyz>random</xyz>
</root>
And i have used annotations in the following way,
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlElement(name = "emp")
private String emp1;
#XmlElement(name = "emp")
private String emp2;
#XmlElement(name = "xyz")
private String xyz;
// added getters and setters for these fields
}
My problem is while i'm trying to get
obj.getEmp1(); // result is Yahoo instead of Google
obj.getEmp2(); // result is null.
Kindly clarify me, what am i doing wrong?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The standard JAXB (JSR-222) annotations do not support mapping 2 different properties to the same XML element.
You could use EclipseLink JAXB (MOXy)'s #XmlPath extension for this use case.
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlPath("emp[1]/text()")
private String emp1;
#XmlPath("emp[2]/text()")
private String emp2;
#XmlElement(name = "xyz")
private String xyz;
// added getters and setters for these fields
}
For More Information
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
If for whatever reason you cannot use MOXy, another solution would be to map the emp element as a list
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlElement(name = "emp")
private List<String> emp;
#XmlElement(name = "xyz")
private String xyz;
// added getters and setters for these fields
}
And then use the following code to get the values:
obj.getEmp().get(0);
obj.getEmp().get(1);
But Blaise's solution is more elegant
You could have a String[] field and have your current accessor methods access the String[].
import javax.xml.bind.annotation.*;
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
private String[] emp = new String[2];
private String xyz;
public String getEmp1() {
return emp[0];
}
public void setEmp1(String emp1) {
this.emp[0] = emp1;
}
public String getEmp2() {
return emp[1];
}
public void setEmp2(String emp2) {
this.emp[1] = emp2;
}
public String getXyz() {
return xyz;
}
public void setXyz(String xyz) {
this.xyz = xyz;
}
}
This might work.
<root>
<emp1>Google</emp1>
<emp2>Yahoo</emp2>
<xyz>random</xyz>
</root>
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class abc {
#XmlElement(name = "emp1")
private String emp1;
#XmlElement(name = "emp2")
private String emp2;
#XmlElement(name = "xyz")
private String xyz;
}

JAXB mappable XML elements

In the root.class from my xi-schema, the element item and ohter objects are part of an itemList:
#XmlElementRef(name = "item", namespace = "xi", type = JAXBElement.class, required = false)
//...
protected List<Object> itemList;
I've in the ObjectFactory.class from the main-schema some items as JAXBElements like this:
#XmlElementDecl(namespace = "de-schema", name = "detailedInformation", substitutionHeadNamespace = "xi", substitutionHeadName = "item")
public JAXBElement<numItemType> createDetailedInformation(numItemType num) {
return new JAXBElement<numItemType>(_detailedInformation_QNAME, numItemType.class, null, num);
}
So the numItemType has some attributes and value(num) for the JAXBElement.
NumItemType.class:
#XmlJavaTypeAdapter(numItemTypeAdapter.class)
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "numItemType", namespace = "xi", propOrder = {
"num"
})
public class NumItemType {
#XmlValue
protected BigDecimal num;
#XmlAttribute(name = "precision")
protected String precision;
#XmlAttribute(name = "decimals")
protected String decimals;
//... more Attributes
}
But when JAXB unmarshal the XML document, it will has only elements, for example:
<detailedInformation>
<element1>1234</element1>
<element2>5678</element2>
<element3>bla</element3>
</detailedInformation>
When I marshal it, it should become (like the JAXB java code):
<detailedInformation element2="5678" element3="bla">1234</detailedInformation>
Therefore, I have written an numItemTypeAdapter.class with
NumItemTypeAdapter extends XmlAdapter
AdaptedNum.class:
public class AdaptedNum {
#XmlElement
private double element1;
#XmlElement
private String element2;
#XmlElement
private String element3;
/** Some getter/setter methods */
}
I thought, that would be help me http://blog.bdoughan.com/2012/02/xmlanyelement-and-xmladapter.html, but it is all a bit tricky :-/
It's a bit tricky to sort out exactly where your problem may be occurring. I'm assuming your original model was generated from an XML Schema, this should work as is without any modifications. I've attempted below to provide a scaled down version of your example which may help.
Root
package forum11343610;
import java.util.*;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElementRef(name = "item", namespace = "xi", type = JAXBElement.class, required = false)
protected List<Object> itemList = new ArrayList<Object>();
public List<Object> getItemList() {
return itemList;
}
public void setItemList(List<Object> itemList) {
this.itemList = itemList;
}
}
NumItemType
package forum11343610;
import java.math.BigDecimal;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "numItemType", namespace = "xi", propOrder = {
"num"
})
public class NumItemType {
#XmlValue
protected BigDecimal num;
#XmlAttribute(name = "precision")
protected String precision;
#XmlAttribute(name = "decimals")
protected String decimals;
//... more Attributes
}
ObjectFactory
package forum11343610;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
#XmlRegistry
public class ObjectFactory {
private static final QName _detailedInformation_QNAME = new QName("de-schema", "detailedInformation");
#XmlElementDecl(namespace = "xi", name = "item")
public JAXBElement<NumItemType> createItem(NumItemType num) {
return new JAXBElement<NumItemType>(_detailedInformation_QNAME, NumItemType.class, null, num);
}
#XmlElementDecl(namespace = "de-schema", name = "detailedInformation", substitutionHeadNamespace = "xi", substitutionHeadName = "item")
public JAXBElement<NumItemType> createDetailedInformation(NumItemType num) {
return new JAXBElement<NumItemType>(_detailedInformation_QNAME, NumItemType.class, null, num);
}
}
Demo
package forum11343610;
import java.math.BigDecimal;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);
ObjectFactory objectFactory = new ObjectFactory();
Root root = new Root();
NumItemType numItemType = new NumItemType();
numItemType.num = BigDecimal.TEN;
numItemType.decimals = "1";
numItemType.precision = "2";
root.getItemList().add(objectFactory.createDetailedInformation(numItemType));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns:ns2="de-schema" xmlns:ns3="xi">
<ns2:detailedInformation precision="2" decimals="1">10</ns2:detailedInformation>
</root>
Thank your for your comment.
That's the point:
Demo
NumItemType numItemType = new NumItemType();
numItemType.num = BigDecimal.TEN;
numItemType.decimals = "1";
numItemType.precision = "2";
root.getItemList().add(objectFactory.createDetailedInformation(numItemType));
It should unmarshal and map the XML automatically.
XML Input
<detailedInformation>
<element1>1234</element1>
<element2>5678</element2>
<element3>bla</element3>
</detailedInformation>
With the Code:
Demo
JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);
Unmarshaller u = jc.createUnmarshaller();
File xml = new File("D:/", "test.xml");
Root root = (Root) u.unmarshal(xml);
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns:ns2="de-schema" xmlns:ns3="xi">
<ns2:detailedInformation precision="2" decimals="1">10</ns2:detailedInformation>
</root>
I could parse the XML Document with DOM to a tree and marhalling with JAXB...
Thank you!
In other words:
I want to set new elements to the NumItemType.class for the unmarshalling without change the schema java code.
NumItemType.class
package forum11343610;
import java.math.BigDecimal;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "numItemType", namespace = "xi", propOrder = {
"num"
})
#XmlJavaTypeAdapter(NumItemTypeAdapter.class)
public class NumItemType {
#XmlValue
protected BigDecimal num;
#XmlAttribute(name = "precision")
protected String precision;
#XmlAttribute(name = "decimals")
protected String decimals;
//... more Attributes
}
NumItemTypeAdapter.class
public class NumItemTypeAdapter extends XmlAdapter<AdaptedNum, NumItemType> {
#Override
public NumItemType unmarshal(AdaptedNum an) throws Exception {
NumItemType nit = new NumItemType();
nit.setNum(an.getNum);
nit.setPrecision(an.getPrecision);
nit.setDecimals(an.getDecimals)
return nit;
}
}
AdaptedNum.class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "adaptedNum", namespace = "", propOrder = {
"element1",
"element2",
"element3"
})
public class AdaptedNum {
#XmlElement(name ="element1")
protected BigDecimal num;
#XmlElement(name ="element2")
private String decimals;
#XmlElement(name ="element3")
private String precison;
// set/get method
}

Categories

Resources