JAXB Unmarsharller: XMLAttributes are mapped, but its XmlElements are not - java

TL;DR: When I unmarshall from XML to POJO I only have the XmlAttributes well mapped, however all XmlElement are null.
Hi there!
I have the following problem. This class was generated with JAXB
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"activity"
})
#XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
#XmlElement(required = true)
protected Activity activity;
#XmlAttribute(name = "schemaVersion", required = true)
protected float schemaVersion;
#XmlAttribute(name = "actionType")
protected ActionTypes actionType;
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar timestamp;
This is an example XML
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
But, when this code is executed (please don't judge me, it's legacy code):
Object xmlClass = Class.forName("com.lorem.ipsum." + className).getConstructor().newInstance();
final JAXBContext jaxbContext = JAXBContext.newInstance(xmlClass.getClass());
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(element));
The result "object" have all XmlAttribute well mapped, but no one of their XmlElement
PS: The namespace in the generated class was added manually, if I don't do that I have this exception:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://lorem.ipsum.com/", local:"activityDetails"). Expected elements are <{}activityDetails>
Thanks in advance.
UPDATED: If I set all #XmlElement the namespace property I finally map the elements, but I must intervene all the classes. Is there another way to achieve that without having to modify all the fields of all the classes?

I guess I am able to figure out the issue. This is happening because you have not provided any prefix to your namespace in XML. Following code would work for your provided sample XML:
XML:
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns:ns0="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
ActivityDetails.class:
#XmlAccessorType(XmlAccessType.FIELD)
#Data
#XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
private Activity activity;
#XmlAttribute
private float schemaVersion;
#XmlAttribute
private String actionType;
#XmlAttribute
private String timestamp;
}
Activity.class:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Activity {
private ActivityID activityId;
}
ActivityID.class:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class ActivityID {
private String start;
private String end;
}
Main.class:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("activity.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(ActivityDetails.class).createUnmarshaller();
final ActivityDetails activityDetails = unmarshaller.unmarshal(xmlStreamReader, ActivityDetails.class).getValue();
System.out.println(activityDetails.toString());
Marshaller marshaller = JAXBContext.newInstance(ActivityDetails.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(activityDetails, System.out);
}
}
Following is your output:
ActivityDetails(activity=Activity(activityId=ActivityID(start=2020-01-01T03:00:00Z, end=2020-01-02T02:59:00Z)), schemaVersion=2.0, actionType=CREATE, timestamp=2020-01-02T15:31:50.549Z)
<ns0:activityDetails xmlns:ns0="http://lorem.ipsum.com/" schemaVersion="2.0" actionType="CREATE" timestamp="2020-01-02T15:31:50.549Z">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</ns0:activityDetails>

Finally I found this solution: Instead of putting the namespace in each of the XMLElements I put the following package-info.java in the package of the generated classes.
#XmlSchema(
elementFormDefault=XmlNsForm.QUALIFIED,
namespace="http://lorem.ipsum.com/",
xmlns={#XmlNs(prefix="", namespaceURI="http://lorem.ipsum.com/")})
package com.lorem.ipsum.generated;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

Related

Convert SOAP XML String to Java Object

I want to convert SOAP XML to Java Object without using xsd files and other stuff. I generate SOAP XML using POJO classes, #Xml annotations. What I want is to somehow deserialize String to not Envelope.class Object, but NumberToWords.class Object.
And by the way I didn't wanna have ns2:/xmlns="" stuff, that's why I used final static String as #XmlAttribute`s instead of namespace initializations.
Here are my classes >>>
#Setter
#Builder
#ToString
#NoArgsConstructor
#AllArgsConstructor
#XmlRootElement(name = "soap:Envelope")
public class Envelope {
#XmlAttribute(
name = "xmlns:soap"
)
#JacksonXmlProperty(isAttribute = true)
private static final String xmlns = "http://schemas.xmlsoap.org/soap/envelope/";
#XmlElement(
name = "soap:Body"
)
private Body body;
public String printBody() {
return body.toString();
}
}
#Getter
#Setter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Body {
#XmlElement(name = "NumberToWords")
private NumberToWords numberToWords;
#XmlElement(name = "Name")
private Name name;
}
#Getter
#Builder
#ToString
#NoArgsConstructor
#AllArgsConstructor
#XmlAccessorType(XmlAccessType.FIELD)
public class NumberToWords {
#XmlAttribute(name = "xmlns")
private final static String xmlns = "http://www.dataaccess.com/webservicesserver/";
#XmlElement(name = "ubiNum")
private Integer ubiNum;
}
Mapper Class which gets Marshaller Bean from another config class, but I decided to not add it here.
#Component
#RequiredArgsConstructor
public class EnvelopeMapper {
private final Marshaller marshaller;
#SneakyThrows
public String getXml(NumberToWords numberToWords) {
Envelope envelope = Envelope.builder()
.body(
Body.builder()
.numberToWords(numberToWords)
.build())
.build();
StringWriter stringWriter = new StringWriter();
marshaller.marshal(envelope, stringWriter);
return stringWriter.toString();
}
}
localhost:8080/get-num-xml/123
STRING:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<NumberToWords xmlns="http://www.dataaccess.com/webservicesserver/">
<ubiNum>123</ubiNum>
</NumberToWords>
</soap:Body>
</soap:Envelope>
When I call this endpoint it throws an exception.
#GetMapping("/get-num-xml/{num}")
public String getNumXml(#PathVariable Integer num) throws JAXBException {
String xml = envelopeService.getNumberToWords(num);
NumberToWords numberToWords = (NumberToWords) unmarshaller.unmarshal(new StringReader(xml));
System.out.println(numberToWords.getUbiNum());
return envelopeService.getNumberToWords(num);
}
GIVES:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://schemas.xmlsoap.org/soap/envelope/", local:"Envelope"). Expected elements are <{}Name>,<{}body>,<{}soap:Envelope>
This one is also throws an exception.
#GetMapping("/get-num-xml/{num}")
public String getNumXml(#PathVariable Integer num) throws JAXBException, SOAPException, IOException {
String xml = envelopeService.getNumberToWords(num);
SOAPMessage message = MessageFactory.newInstance().createMessage(null, new ByteArrayInputStream(xml.getBytes()));
JAXBContext jc = JAXBContext.newInstance(NumberToWords.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
NumberToWords rc = (NumberToWords) unmarshaller.unmarshal(message.getSOAPBody().extractContentAsDocument());
return envelopeService.getNumberToWords(num);
}
GIVES:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.dataaccess.com/webservicesserver/", local:"NumberToWords"). Expected elements are (none)
I don't have a clue how to unmarshal xml, so I hope someone has an answer for this one.

Write pojo class for this xml file

I'm getting null value when unmarshelling the xml file to java class. But the xml file as values corresponding to the its attributes. Is there any mistake in my pojo class or unmarshelling?
Please help
This is my pojo
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "CardUpdateResponse",namespace="http://www.samople.com/Prepaid")
public class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
//Setters and Getters
}
This is my xml file
<?xml version="1.0" encoding="UTF-8"?>
<CardUpdateResponse xmlns="http://www.samople.com/Prepaid">
<CARDUPDATE_RET>
<ResErrorMsg>ID Issue Date must be equal or less than present date</ResErrorMsg>
<ResErrorCode>ErrIsud01</ResErrorCode>
<ResCode>0</ResCode>
<ACCOUNTNUMBER>2000000003918246</ACCOUNTNUMBER>
</CARDUPDATE_RET>
</CardUpdateResponse>
this is code for unmarshelling
public class XmlUnmarshelling {
public void unmarshell()
{
try
{
System.out.println("xml unmarshelling class");
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(FVCardUpdateResponse.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
FVCardUpdateResponse CARDUPDATE_ret = (FVCardUpdateResponse) jaxbUnmarshaller.unmarshal(file);
System.out.println("xml unmarshelled = "+CARDUPDATE_ret.getResErrorMsg());//Getting null value as response.
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Your POJO doesn't have the same structure as your XML. CardUpdateResponse doesn't directly contain the properties in your POJO, it contains CARDUPDATE_RET element which contains the properties.
You could modify your POJO like this to match the XML:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "CardUpdateResponse", namespace="http://www.samople.com/Prepaid")
public static class CardUpdateResponseWrapper {
#XmlElement(name="CARDUPDATE_RET")
private FVCardUpdateResponse response;
// Getter and setter for response
public static class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
// Getters and setters
}
}
Now the CardUpdateResponseWrapper class will represent your root XML element and it will have instance of FVCardUpdateResponse which will represent the CARDUPDATE_RET XML element.
Do unmarshall it, just call:
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(CardUpdateResponseWrapper.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
CardUpdateResponseWrapper wrapper = (CardUpdateResponseWrapper) jaxbUnmarshaller.unmarshal(file);
System.out.println(wrapper.getResponse().getResErrorMsg());
I think that the issue is a combination of two problems, one what Bohuslav is saying, the other you need to repeat your namespace on every XmlElement annotation, e.g.
#XmlElement(name = "ResCode", namespace="http://www.samople.com/Prepaid")
and one particular issue, you need to match the cases as well so the name for AccountNumber should be capitalized ACCOUNTNUMBER

How to create model class for XML parsing which has iteration of element

I'm beginner JAVA programming. I'm making model class through XML parsing. I know there are some example such as : JAXB, xmapper etc..
I have some xml file which element has iteration. How to create model class for this xml ? Any help..
Let’s map some xml:
<root a="2.2">
<main>
<node1>123</node1>
<node2>123</node2>
</main>
<client value="1" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
<client value="2" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
<client value="3" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
// ...
<client value="100" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
<System>
<DebugFrame>0</DebugFrame>
</System>
</root>
I found http://docs.oracle.com/cd/E12840_01/wls/docs103/webserv/data_types.html. Is that what I want ?
Edited
Here is real code. I have some compile error. Java version is
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
Here is error message ;
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Class has two properties of the same name "mode"
this problem is related to the following location:
at public java.lang.String xmlParserTest.RootTest.getMode()
at xmlParserTest.RootTest
this problem is related to the following location:
at private java.lang.String xmlParserTest.RootTest.mode
at xmlParserTest.RootTest
Class has two properties of the same name "inputFile"
this problem is related to the following location:
at public java.lang.String xmlParserTest.MainEntity.getInputFile()
at xmlParserTest.MainEntity
at private xmlParserTest.MainEntity xmlParserTest.RootTest.main
at xmlParserTest.RootTest
this problem is related to the following location:
at private java.lang.String xmlParserTest.MainEntity.inputFile
at xmlParserTest.MainEntity
at private xmlParserTest.MainEntity xmlParserTest.RootTest.main
at xmlParserTest.RootTest
: console.java
package xmlParserTest;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class console {
public static void main(String[] args) {
try
{
JAXBContext jc = JAXBContext.newInstance(RootTest.class);
Unmarshaller u = jc.createUnmarshaller();
File f = new File("Testing.xml");
RootTest product = (RootTest) u.unmarshal(f);
System.out.println(product.getMode());
System.out.println(product.getMainEntity().getInputFile());
System.out.println(product.getMainEntity().getOutputFolder());
}catch (JAXBException e) {
e.printStackTrace();
}
}
}
: RootTest.java
package xmlParserTest;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Function")
public class RootTest {
private MainEntity main;
private String mode;
#XmlElement(name="Main")
public MainEntity getMainEntity() {
return main;
}
public void setMainEntity(MainEntity _main) {
this.main = _main;
}
#XmlAttribute(name="mode")
public String getMode() {
return mode;
}
public void setMode(String _mode) {
this.mode = _mode;
}
public RootTest()
{
}
}
: MainEntity.java
package xmlParserTest;
import javax.xml.bind.annotation.XmlElement;
public class MainEntity {
private String inputFile;
private String inputType;
private String outputFolder;
private String outputType;
#XmlElement(name="InputFile")
public String getInputFile() {
return inputFile;
}
public void setInputFile(String _inputFile) {
this.inputFile = _inputFile;
}
public String getInputType() {
return inputType;
}
public void setInputType(String _type) {
this.inputType = _type;
}
#XmlElement(name="OutputFolder")
public String getOutputFolder() {
return outputFolder;
}
public void setOutputFolder(String _outputFolder) {
this.outputFolder = _outputFolder;
}
public String getOutputType() {
return outputType;
}
public void setOutputType(String _type) {
this.outputType = _type;
}
public MainEntity()
{
}
}
: Testing.xml
<?xml version="1.0" encoding="UTF-8"?>
<Function mode="Execute">
<Main>
<InputFile type="string">C:\DATA\test.txt</InputFile>
<OutputFolder type="string">C:\Test</OutputFolder>
</Main>
</Function>
If You wnat to use JAXB, first of all, You need to create main model, that looks like this:
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
private MainEntity main;
#XmlElement(name = "client")
private List<ClientEntity> clients;
#XmlAttribute
private String a;
#XmlElement(name = "System")
private SystemEntity system;
//getters and setters for all fields
}
Then, specify entities:
public class MainEntity {
private String node1;
private String node2;
//getters and setters for all fields
}
#XmlAccessorType(XmlAccessType.FIELD)
public class ClientEntity {
#XmlElement(name = "C_node1")
private String C_node1;
#XmlElement(name = "C_node2")
private String C_node2;
#XmlAttribute
private Long value;
#XmlAttribute
private boolean use;
//getters and setters for all fields
}
#XmlAccessorType(XmlAccessType.FIELD)
public class SystemEntity {
#XmlElement(name = "DebugFrame")
private Long debugFrame;
//getters and setters for all fields
}
As You see, we use #XmlElement(name = "System") to set alias for field and #XmlAttribute to read field from attribute.
To unmarshall XML with JAXB, create context for your class model:
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(file);
Don't forget: when You create model, You need to specify getters and setters for fields that You want to marshall/unmarshall and also specify non-argument constructor for class.
More about annotations You can find here:
http://www.techferry.com/articles/jaxb-annotations.html
Have fun!:)
With JAXB, you can create the required Java classes as below:
#XmlRootElement(name = "main")
public class Main {
String node1;
String node1;
//getters and setters for fields
}
#XmlRootElement(name = "client")
public class Client {
String node1;
String node1;
#XmlAttribute
private boolean use;
#XmlAttribute
private int value;
//getters and setters for fields
}
And then create a Root class to represent your XML file:
#XmlRootElement(name = "root")
public class Root {
//add a list of client instances
#XmlElement(name = "client")
private List<Client> clientList;
//add an instance of main
#XmlElement(name = "main")
private Main main;
// setters to set the values for main and clients
}
Now, with these lines of code you can create the XML representation for the Root class:
Root root = new Root();
root.setMain(CREATE_AND_SET_AN_INSTANCE_OF_MAIN);
root.setClientList(CREATE_AND_SET_A_LIST_OF_CLIENTS);
String filePath = "PATH_TO_SAVE_YOUR_FILE";
File file = new File(filePath);
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(alpha, file);
And you can use these lines of code to read the XML back to Java object:
String filePath = "XML_FILE_PATH";
File file = new File(filePath);
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root) jaxbUnmarshaller.unmarshal(file);
Ref: Java Architecture for XML Binding (JAXB)

JAXB troubles when trying to unmarshall a BES-XADES signature document

i need your help : please, please please.
I've a Xades-signed XML document that i receive as a byteArray : so i convert my byteArray to a String.
After, i try to unmarhall so that i obtain a Java Object mapped.
The result is that i get an instance of "MyJavaObj" with all informations but Xades-Signature. My signature is null in the Java Object while all other informations are well-mapped. The following is my java method. Please, help me to get the object signature in the instance of MyJavaObj.
<school>
<documentVersion>2.10</documentVersion>
<teacher>
.....
</teacher>
<student>
<name></name>
<age></age>
....
</student>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-2b72d2f4-4794-4a8b-8cbf-4c74d33629a7">
<ds:SignedInfo>
........
</ds:SignedInfo>
.......
</ds:Signature>
</school>
this is the method to convert
public static MyJavaObj unmarshallBinary(final byte[] pByteStr) {
try {
final String xmlFlow = new String(pByteStr, "UTF-8");
final StringBuffer xmlStr = new StringBuffer(xmlFlow);
// Unmarshalling with JAXB
final JAXBContext jaxbContext = JAXBContext.newInstance("generated.package");
// marshaller
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
// Unmarshalling
final JAXBElement<MyJavaObj> root = unmarshaller.unmarshal(
new StreamSource(new StringReader(xmlStr.toString())), MyJavaObj.class);
return root.getValue();
} catch (final Throwable excep) {
excep.printStacktrace();
}
}
MyJavaObj result = unmarshallBinary(..a ByteArray..);
result.getDocumentVersion() : returns 2.10;
result.getStudent() : returns the students;
result.getSignature() : return NULL;
The file MyJavaObj.java is well annotated
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "My_Java_Obj", namespace = "urn:my_java_obj",
propOrder = {"documentVersion", "teacher", "student","signature"})
public class MyJavaObj {
#XmlElement(name = "documentVersion", required = true)
protected String documentVersion;
#XmlElement(name = "teacher", required = true)
protected Teacher teacher;
#XmlElement(name = "student", required = true)
protected Student student;
#XmlElement(name = "Signature")
protected Signature signature;
#XmlAttribute(name = "Id", required = true)
#XmlJavaTypeAdapter(CollapsedStringAdapter.class)
#XmlID
#XmlSchemaType(name = "ID")
protected String id;
.....
getters and setters
}
Thanks for any help.
The Signature element is in the http://www.w3.org/2000/09/xmldsig#" namespace so you need to include this in the #XmlElement for the signature field.
#XmlElement(name="Signature", namespace="http://www.w3.org/2000/09/xmldsig#")
protected Signature signature;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
my solution is bit different
i used uddi-ws. Maven dependency is here:
<!-- https://mvnrepository.com/artifact/org.apache.juddi/uddi-ws -->
<dependency>
<groupId>org.apache.juddi</groupId>
<artifactId>uddi-ws</artifactId>
<version>3.3.2</version>
</dependency>
In class:
//in my case, import org.w3.x2000.x09.xmldsig.SignatureType isn't working
import org.w3._2000._09.xmldsig_.SignatureType;
//Signature declaration
private SignatureType Signature;
//namespace is important part, without namespace, it returns null
#XmlElement(name = "Signature", namespace = "http://www.w3.org/2000/09/xmldsig#")
public SignatureType getSignature() {
return Signature;
}
More info:
https://www.codesynthesis.com/pipermail/xsd-users/2006-December/000674.html

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