Reading xmlAttribute from XmlElement in jaxB - java

Hello i have the following xml:
With the following code:
How can I get the attribute DispalyName of each element without creating new class for Down and Up and using #xmlAttribute.
I can solve it by adding new 2 classes UpElement and DownElement and for each class get the the #xmlAttribute but i want to it in once class.
Code Example:
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "StatusesList")
#XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
public class StatusesListElement
{
#XmlElement(name = "Down")
private String down = "";
#XmlElement(name = "Up")
private String up = "";
public String getDown()
{
return down;
}
public void setDown(String down)
{
this.down = down;
}
public String getUp()
{
return up;
}
public void setUp(String up)
{
this.up = up;
}
}

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
Using EclipseLink JAXB (MOXy)
You could use the #XmlPath extension in MOXy to map this use case:
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "StatusesList")
#XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
public class StatusesListElement
{
#XmlPath("Down/#DisplayName")
private String down = "";
#XmlElement(name = "Up/#DisplayName")
private String up = "";
}
Using any JAXB Implementation
You could use an XmlAdapter for this use case. Below is a link to an answer I gave that demonstrates how this can be done:
JAXB Element mapping

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 super class field not being deserialized

I am trying to deserialize xml string into object but ran across strange problem. Everything is being serialized as intended, however when deserializing field which originates from parent class always returns null.
MyNffgDescriptor is a class which contain VNFTypeReader as attribute. All fields are deserialized correctly, VNFTypeReader ones as well except the name which is passed from parent class (NamedEntityReaderImpl) and it returns null.
Parent class
package it.polito.dp2.NFV.sol3.client1.implementations;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import it.polito.dp2.NFV.NamedEntityReader;
#XmlAccessorType(XmlAccessType.NONE)
public class NamedEntityReaderImpl implements NamedEntityReader, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String entityName;
public NamedEntityReaderImpl() {
this.entityName = "";
}
public NamedEntityReaderImpl(String name) {
this.entityName = name;
}
#Override
public String getName() {
return this.entityName;
}
}
Child class
package it.polito.dp2.NFV.sol3.client1.implementations;
import java.io.Serializable;
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 it.polito.dp2.NFV.VNFTypeReader;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class VNFTypeReaderImpl extends NamedEntityReaderImpl implements Serializable,VNFTypeReader {
/**
*
*/
private static final long serialVersionUID = 1L;
#XmlElement
private int requiredMemory;
#XmlElement
private int requiredStorage;
#XmlElement
private it.polito.dp2.NFV.FunctionalType funcType;
public VNFTypeReaderImpl() {
super(null);
this.requiredMemory = 0;
this.requiredStorage = 0;
this.funcType = null;
}
public VNFTypeReaderImpl(VNFTypeReader reader) {
super(reader.getName());
this.requiredMemory = reader.getRequiredMemory();
this.requiredStorage = reader.getRequiredStorage();
this.funcType = reader.getFunctionalType();
}
#Override
public int getRequiredMemory() {
return this.requiredMemory;
}
#Override
public int getRequiredStorage() {
return this.requiredStorage;
}
#Override
public it.polito.dp2.NFV.FunctionalType getFunctionalType() {
return this.funcType;
}
#Override
#XmlElement(name="name", required=true)
public String getName() {
return super.getName();
}
}
This is the example of xml string I am trying to deserialize:
<?xml version="1.0" encoding="UTF-8"?>
<myNffgDescriptor>
<nodeList id="0">
<funcReader>
<requiredMemory>620</requiredMemory>
<requiredStorage>100</requiredStorage>
<funcType>WEB_SERVER</funcType>
<name>WEBSERVERt</name>
</funcReader>
<hostName>H3</hostName>
<linksList source="0" destination="10" />
<linksList source="0" destination="11" />
<linksList source="0" destination="8" />
</nodeList>
</myNffgDescriptor>
Place where unmarshalling occurs:
jaxbContext = JAXBContext.newInstance(MyNffgDescriptor.class);
unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(nffg);
MyNffgDescriptor nffgDesc = (MyNffgDescriptor) unmarshaller.unmarshal(reader);
Change XmlAccessType.NONE to XmlAccessType.FIELD on parent
class NamedEntityReaderImpl.
Also you could just add on class NamedEntityReaderImpl an annotation above the field:
#XmlElement(name= "name")
private String entityName;
Do either changes (or both) and it would work

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;
}

Is it possible to #XmlElement annotate a method with non-stardard name?

This is what I'm doing:
#XmlType(name = "foo")
#XmlAccessorType(XmlAccessType.NONE)
public final class Foo {
#XmlElement(name = "title")
public String title() {
return "hello, world!";
}
}
JAXB complains:
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
JAXB annotation is placed on a method that is not a JAXB property
this problem is related to the following location:
at #javax.xml.bind.annotation.XmlElement(nillable=false, name=title, required=false, defaultValue=, type=class javax.xml.bind.annotation.XmlElement$DEFAULT, namespace=##default)
at com.example.Foo
What to do? I don't want (and can't) rename the method.
There are a couple of different options:
Option #1 - Introduce a Field
If the value is constant as it is in your example, then you could introduce a field into your domain class and have JAXB map to that:
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(name = "foo")
#XmlAccessorType(XmlAccessType.NONE)
public final class Foo {
#XmlElement
private final String title = "hello, world!";
public String title() {
return title;
}
}
Option #2 - Introduce a Property
If the value is calculated then you will need to introduce a JavaBean accessor and have JAXB map to that:
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(name = "foo")
#XmlAccessorType(XmlAccessType.NONE)
public final class Foo {
public String title() {
return "hello, world!";
}
#XmlElement
public String getTitle() {
return title();
}
}
There might be a better way, but the first solution that comes to mind is:
#XmlElement(name = "title")
private String title;
public String getTitle() {
return title();
}
Why is it you can't name your method according to Java conventions anyway?

Categories

Resources