i have the following code
#XmlAccessorType (XmlAccessType.FIELD)
private static class MyAttribute<T> {
private String name;
#XmlElement(name = "value")
private T value;
}
#XmlRootElement(name = "duke-eport")
#XmlAccessorType (XmlAccessType.FIELD)
public class DukeDBInfo {
#XmlElement(name = "sys-attribute")
private List<MyAttribute<?>> sysAttribute;
}
when using jaxb marshaller with it i get the following output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<duke-eport>
<sys-attribute>
<name>username</name>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">udsds</value>
</sys-attribute>
<sys-attribute>
<name>ip</name>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">127.0.0.1</value>
</sys-attribute>
<sys-attribute>
<name>server-date</name>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:dateTime">2015-05-19T16:23:09.595+03:00</value>
</sys-attribute>
how can i remove the xmlns:xsi and the xml:xs from each and add it only once to the root node ?
import org.w3._2001.xmlschema.Adapter1;
#XmlAccessorType (XmlAccessType.FIELD)
#XmlType(name = "myAttribute", propOrder = {
"username",
"server-date"
})
private static class MyAttribute<T> {
protected String username;
#XmlElement(type = String.class)
#XmlJavaTypeAdapter(Adapter1 .class)
#XmlSchemaType(name = "dateTime")
protected Calendar server-date;
#XmlElement(username = "value")
private T value;
}
#XmlRootElement(username = "duke-eport")
#XmlAccessorType (XmlAccessType.FIELD)
public class DukeDBInfo {
#XmlElement(username = "sys-attribute")
private List<MyAttribute<?>> sysAttribute;
}
Related
I have the following class which shall be serialized/deserialized to XML.
#XmlRootElement(name = "nnxml")
#XmlAccessorType(XmlAccessType.FIELD)
public class InfoRequest {
#XmlElement(name = "vendor_id")
private String vendorId;
#XmlElement(name = "vendor_authcode")
private String authCode;
}
This currently gives me this XML which is consistent and correct:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<nnxml>
<vendor_id>vendor id</vendor_id>
<vendor_authcode>auth code</vendor_authcode>
</nnxml>
However I need to wrap the XML elements in another element like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<nnxml>
<info_request>
<vendor_id>vendor id</vendor_id>
<vendor_authcode>auth code</vendor_authcode>
</info_request>
</nnxml>
How can I wrap the above fields in a info_request element? Do I have to create something like an inner class or is there a simpler approach?
One approach is to create a Wrapper class like this and to insert your class
#XmlRootElement(name = "nnxml")
#XmlAccessorType(XmlAccessType.FIELD)
public class Nnxml implements Serializable {
#XmlElement(name = "info_request")
private InfoRequest request;
}
The annotations of subclass are optional
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "info_request", propOrder = {
"vendorId",
"authCode"
})
class InfoRequest implements Serializable{
#XmlElement(name = "vendor_id")
private String vendorId;
#XmlElement(name = "vendor_authcode")
private String authCode;
}
Output is
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<nnxml>
<info_request>
<vendor_id>vendor id</vendor_id>
<vendor_authcode>auth code</vendor_authcode>
</info_request>
</nnxml>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<InstanceTree xmlns="http://www.testsite.org/Schemas/xyzSchema">
<Instance id="inst0" depth="1">
<UserData type="Instance">
<userValue title="occurrenceUUID" value="abc/>
</UserData>
<UserData type="Part" name="pqr">
<UserValue title="PartNumber" value="MTG_238_ZB_LACKIERUNG" />
</UserData>
</Instance>
</InstanceTree>
#XmlRootElement(name = "InstanceTree")
public class InstanceTree {
}
#XmlRootElement(name = "Instance")
public class Instance {
private List<Userdata> userdata;
#XmlElement
public List<Userdata> getUserdata() {
return userdata;
}
}
#XmlRootElement(name = "UserValue")
public class UserValue {
private List<UserValue> userValue;
#XmlElement
public List<UserValue> getUserValue() {
return userValue;
}
}
#XmlRootElement(name = "UserData")
public class Userdata {
}
In xml giving NullPointerException for upper case Instance, UserData, UserValue.
Giving error for xmlns="http://www.testsite.org/Schemas/abcSchema". working fine after removing url.
Use #XmlElement(name="Userdata") otherwise jaxb uses the attribute name.
#XmlRootElement(name = "Instance")
public class Instance {
private List<Userdata> userdata;
#XmlElement(name = "Userdata")
public List<Userdata> getUserdata() {
return userdata;
}
}
use also package-info.java
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://www.testsite.org/Schemas/abcSchema",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "", namespaceURI = "http://www.testsite.org/Schemas/abcSchema")
}
)
package com.your.package;
I'm having trouble unmarshalling XML that represents an invoice in this form:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<Response xmlns="Lamp">
<Result>
<Title>The Title</Title>
<Lines>
<anyType xsi:type="InvoiceLine">
<Name>Name One</Name>
<Quantity>1.0000</Quantity>
</anyType>
<anyType xsi:type="InvoiceLine">
<Name>Name Two</Name>
<Quantity>2.0000</Quantity>
</anyType>
</Lines>
</Result>
</Response>
</soap:Body>
</soap:Envelope>
The Invoice class:
#XmlAccessorType(XmlAccessType.FIELD)
public class Invoice {
public String Title;
public List<InvoiceLine> Lines;
}
The InvoiceLine class:
#XmlAccessorType(XmlAccessType.FIELD)
public class InvoiceLine extends anyType {
public String Name;
public float quantity;
}
And a abstract class for anyType:
public abstract class anyType {}
This is the code I'm using to do the unmarshalling:
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream("input.xml");
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(is);
xsr.nextTag();
while(!xsr.getLocalName().equals("Result")) {
xsr.nextTag();
}
JAXBContext jc = JAXBContext.newInstance(Invoice.class, InvoiceLine.class);
javax.xml.bind.Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<Invoice> jb = unmarshaller.unmarshal(xsr, Invoice.class);
xsr.close();
System.out.println(jb.getValue());
}
The problem is the Lines list only contains 1 entry with Name=null and quantity=0.0.
-- Edit:
I've just tried adding XmlElement and XmlElementWrapper annotations to both classes, the only change is that the Lines list has no elements.
Modified Invoice:
#XmlAccessorType(XmlAccessType.FIELD)
public class Invoice {
#XmlElement(name = "Title")
public String Title;
#XmlElement(name = "anyType")
#XmlElementWrapper(name = "Lines")
public List<InvoiceLine> Lines;
}
Modified InvoiceLine:
#XmlAccessorType(XmlAccessType.FIELD)
public class InvoiceLine extends anyType {
#XmlElement(name = "Name")
public String Name;
#XmlElement(name = "Quantity")
public float Quantity;
}
-- Edit:
I've just tried making the attributes lower case, but still no luck.
I've a service that returns this XML:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<project>
<id>id1</id>
<owner>owner1</owner>
</project>
<project>
<id>id2</id>
<owner>owner2</owner>
</project>
</result>
or
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<user>
<id>id1</id>
<name>name1</name>
</user>
<user>
<id>id2</id>
<name>name2</name>
</user>
</result>
I want to unmarshall the retrieved XML using these classes:
Result:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlElementWrapper(name = "result")
#XmlElement
protected List<T> result;
}
Project:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Project {
#XmlElement
public String id;
#XmlElement
public String owner;
}
User:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class User {
#XmlElement
public String id;
#XmlElement
public String name;
}
First not working solution
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
I get an empty list.
Second not working solution
Inspired by this article http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html I've modified the Response class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlAnyElement(lax=true)
protected List<T> result;
}
And then tested it with this code:
Response<Project> responseProject = unmarshal(unmarshaller, Project.class, "responseProject.xml");
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
private static <T> Response<T> unmarshal(Unmarshaller unmarshaller, Class<T> clazz, String xmlLocation) throws JAXBException {
StreamSource xml = new StreamSource(xmlLocation);
#SuppressWarnings("unchecked")
Response<T> wrapper = (Response<T>) unmarshaller.unmarshal(xml, Response.class).getValue();
return wrapper;
}
And I get this exception reading the response list:
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to org.test.Project
Note: I can't modify the original XML. There are more types other than Project and User.
Thanks to Blaise Doughan and his article I've found the solution.
First we need the Wrapper class provided in the article:
#XmlRootElement
public class Wrapper<T> {
private List<T> items;
public Wrapper() {
items = new ArrayList<T>();
}
public Wrapper(List<T> items) {
this.items = items;
}
#XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
}
Then I've modified the Response class in order to use it:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlElement
protected Wrapper<T> result;
...
public Response(String status, List<T> result) {
this.status = status;
this.result = new Wrapper<>(result);
}
...
public List<T> getResult() {
return result.getItems();
}
...
}
Finally the unmarshalling code:
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class, Wrapper.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
I've added the Wrapper class to the context class list.
Alternatively you can add this annotation to the Response class:
#XmlSeeAlso({Project.class, User.class})
Using #XmlSeeAlso({Project.class, User.class}) on Response classes has the drawback of generating some garbage information on each entity in the list: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount"
<resources>
<links>
<link>
<rel>self</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=0&limit=2</uri>
</link>
<link>
<rel>prev</rel>
<uri></uri>
</link>
<link>
<rel>next</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=2&limit=2</uri>
</link>
</links>
<collection>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>638f502a0e409348ccc2e36c24907f0</activationCode>
<email>michzio#hotmail.com</email>
<login>michzio</login>
<password>sAmPL3#e</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>1</userId>
</user-account>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>334bc79d142a291894bd71881e38a719</activationCode>
<email>alicja#krainaczarow.com</email>
<login>alicja</login>
<password>zAczka!00</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>2</userId>
</user-account>
</collection>
</resources>
I'm having a problem using Moxy to marshal/unmarshal Salesforce outbound message XMLs. The exception that I'm getting is:
javax.xml.bind.JAXBException
- with linked exception:
[Exception [EclipseLink-44] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Missing class indicator field from database row [UnmarshalRecord()].
Descriptor: XMLDescriptor(service.salesforce.model.SObject --> [])]
The classes that I have are:
#XmlSeeAlso({Account.class, Opportunity.class})
#XmlDiscriminatorNode("#type")
public abstract class SObject {
public abstract String getId();
public abstract void setId(String id);
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlDiscriminatorValue("sf:Opportunity")
public class Opportunity extends SObject {
#XmlElement(name = "Id", namespace = "urn:sobject.enterprise.soap.sforce.com")
private String id;
#XmlElement(name = "AccountId", namespace = "urn:sobject.enterprise.soap.sforce.com")
private String accountId;
#XmlElement(name = "StageName", namespace = "urn:sobject.enterprise.soap.sforce.com")
private String stageName;
#XmlElement(name = "Agreement_Date_Signed__c", namespace = "urn:sobject.enterprise.soap.sforce.com")
private Date agreementDateSigned;
#XmlElement(name = "Agreement_Date_Start__c", namespace = "urn:sobject.enterprise.soap.sforce.com")
private Date agreementDateStart;
#XmlElement(name = "Payment_Method__c", namespace = "urn:sobject.enterprise.soap.sforce.com")
private String paymentMethod;
// getters and setters...
}
The XML that I'm trying to unmarshal is:
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:out="http://soap.sforce.com/2005/09/outbound" xmlns:urn="urn:sobject.enterprise.soap.sforce.com">
<soapenv:Header/>
<soapenv:Body>
<out:notifications>
<out:OrganizationId>123456789123456789</out:OrganizationId>
<out:ActionId>123456789123456789</out:ActionId>
<out:SessionId>sessId</out:SessionId>
<out:EnterpriseUrl>http://www.enterpriseexample.com</out:EnterpriseUrl>
<out:PartnerUrl>http://www.partnerexample.com</out:PartnerUrl>
<out:Notification>
<out:Id>987654321987654321</out:Id>
<out:sObject xsi:type="sf:Opportunity" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
<urn:Id>121212121212121212</urn:Id>
<urn:AccountId>121212121212121212</urn:AccountId>
<urn:Agreement_Date_Signed__c>2012-01-01T08:34:56Z</urn:Agreement_Date_Signed__c>
<urn:Agreement_Date_Start__c>2012-02-01</urn:Agreement_Date_Start__c>
<urn:StageName>Booking</urn:StageName>
</out:sObject>
</out:Notification>
</out:notifications>
</soapenv:Body>
</soapenv:Envelope>
Any idea?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
Since you are using the xsi:type attribute as your discriminator node as your inheritance indicator, I would recommend using the standard JAXB mechanisms rather than MOXy's #XmlDescriminatorNode/#XmlDescriminatorValue extension.
SObject
package forum987537;
import javax.xml.bind.annotation.XmlSeeAlso;
#XmlSeeAlso({Account.class, Opportunity.class})
public abstract class SObject {
public abstract String getId();
public abstract void setId(String id);
}
Opportunity
package forum987537;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name="Opportunity")
public class Opportunity extends SObject {
private String id;
#Override
public String getId() {
return id;
}
#Override
public void setId(String id) {
this.id = id;
}
}
Notification
package forum987537;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="Notification", namespace="http://soap.sforce.com/2005/09/outbound")
public class Notification {
private SObject sObject;
#XmlElement(namespace="http://soap.sforce.com/2005/09/outbound")
public SObject getsObject() {
return sObject;
}
public void setsObject(SObject sObject) {
this.sObject = sObject;
}
}
package-info
#XmlSchema(
namespace="urn:sobject.enterprise.soap.sforce.com",
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(prefix="out", namespaceURI = "http://soap.sforce.com/2005/09/outbound"),
#XmlNs(prefix="sf", namespaceURI = "urn:sobject.enterprise.soap.sforce.com"),
})
package forum987537;
import javax.xml.bind.annotation.*;
Demo
package forum987537;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Notification.class);
Notification notification = new Notification();
Opportunity opportunity = new Opportunity();
opportunity.setId("ABC123");
notification.setsObject(opportunity);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(notification, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<out:Notification xmlns:sf="urn:sobject.enterprise.soap.sforce.com" xmlns:out="http://soap.sforce.com/2005/09/outbound">
<out:sObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="sf:Opportunity">
<sf:id>ABC123</sf:id>
</out:sObject>
</out:Notification>
For More Information
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html
http://blog.bdoughan.com/2012/02/jaxb-and-inheritance-eclipselink-moxy.html