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.
Related
In src/main/java, I have POJO classes and in src/test/resource I have XML file. I'm writing a Junit test case where I have to parse the XML file into POJOs using JAXBException and then I have to check whether the variables are null or not.
I created a test class and added the asseertNotNull statement but after running the code as "Junit test" I'm getting some errors.
Java Class :-
package com.examples.demo;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "book")
// Defining order
#XmlType(propOrder = { "author", "name", "publisher", "isbn" })
public class Book {
private String name;
private String author;
private String publisher;
private String isbn;
// Changing to title
#XmlElement(name = "title")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlAttribute(name = "AuthorName")
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
#XmlElement(name = "publisher")
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
#XmlElement(name = "isbn")
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("Book{");
sb.append("name='").append(name).append('\'');
sb.append(", author='").append(author).append('\'');
sb.append(", publisher='").append(publisher).append('\'');
sb.append(", isbn='").append(isbn).append('\'');
sb.append('}');
return sb.toString();
}
}
Test Class :-
package com.examples.demo;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.bind.JAXBException;
import org.junit.jupiter.api.Test;
import jakarta.xml.bind.JAXBContext;
public class BookTest {
private static final String BOOKSTORE_XML = "src/test/resources/bookstore.xml";
#Test
public void oneDemo() throws JAXBException, IOException, jakarta.xml.bind.JAXBException {
JAXBContext context = JAXBContext.newInstance(BookStore.class);
BookStore bookStore = (BookStore) context.createUnmarshaller().unmarshal(new StringReader(BOOKSTORE_XML));
String name = bookStore.getName();
assertNotNull(name);
}
}
XML file :-
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:bookStore xmlns:ns2="com.zetcode">
<bookList>
<book AuthorName="Neil Strauss">
<title>The Game</title>
<publisher>Harpercollins</publisher>
<isbn>978-0060554736</isbn>
</book>
<book AuthorName="Charlotte Roche">
<title>Feuchtgebiete</title>
<publisher>Dumont Buchverlag</publisher>
<isbn>978-3832180577</isbn>
</book>
</bookList>
<location>Livres belles</location>
<name>Fraport Bookstore</name>
</ns2:bookStore>
How to solve this? please help me
Taking the xml you are using for tests (I omitted non significative tags from code, up to you integrate them):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:bookStore xmlns:ns2="com.zetcode">
<bookList>
<book AuthorName="Neil Strauss">
<title>The Game</title>
<publisher>Harpercollins</publisher>
<isbn>978-0060554736</isbn>
</book>
<book AuthorName="Charlotte Roche">
<title>Feuchtgebiete</title>
<publisher>Dumont Buchverlag</publisher>
<isbn>978-3832180577</isbn>
</book>
</bookList>
<location>Livres belles</location>
<name>Fraport Bookstore</name>
</ns2:bookStore>
The first problem is about the presence of <ns2:bookStore xmlns:ns2="com.zetcode"> tag, you have to define a BookStorewrapper class matching the <bookStore> tag to wrap the <bookList> tag using the XmlRootElement annotation:
#Data //<--lombok annotation
#XmlRootElement(name="bookStore", namespace = "com.zetcode")
#XmlAccessorType(XmlAccessType.FIELD) //<-- used for permit access to fields
public class BookStore {
public BookList bookList;
}
You have to repeat the same process for the bookList tag being aware it contains a list of books with the help of the XmlElement annotation which specifies every book is an element of the list:
#Data
#XmlRootElement(name="bookList")
#XmlAccessorType(XmlAccessType.FIELD)
public class BookList {
#XmlElement(name = "book")
private List<Book> books;
}
#Data
#XmlRootElement(name = "book")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {"author", "name", "publisher", "isbn"})
public class Book {
private String name;
private String author;
private String publisher;
private String isbn;
}
Then you can verify that everything is ok unmarshalling and marshalling the xml, printing it to the stdout :
public class JaxbMain {
public static void main(String[] args) throws JAXBException {
File xml = new File("msg.xml");
//unmarshalling the xml
JAXBContext jc = JAXBContext.newInstance(BookStore.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
BookStore bookStore = (BookStore) unmarshaller.unmarshal(xml);
//marshalling the xml to the stdout
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//ok it prints the same xml
marshaller.marshal(bookStore, System.out);
}
}
Pom.xml:
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
</dependencies>
I have an xml structure as follows:
<?xml version="1.0" encoding="UTF-8"?>
<school>
<students>
<student>
<firstName>A</firstName>
<id>1</id>
<lastName>C</lastName>
<company>BCD</company>
<responsibilities>
<responsibility>Leader</responsibility>
<responsibility>Dancer</responsibility>
<responsibility>Reporter</responsibility>
</responsibilities>
</student>
<student>
<firstName>B</firstName>
<id>2</id>
<lastName>C</lastName>
<company>EFG</company>
<responsibilities>
<responsibility>Singer</responsibility>
</responsibilities>
</student>
</students>
<Teachers>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<responsibilities>
<responsibility>English</responsibility>
<responsibility>Hindi</responsibility>
<responsibility>Softskills</responsibility>
</responsibilities>
</Teacher>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<company>BCD</company>
<responsibilities>
<responsibility>Science</responsibility>
<responsibility>Math</responsibility>
</responsibilities>
</Teacher>
</Teachers>
</school>
I would want to dynamically parse all the objects and put it into a list.
I have created classes for school,students,student,teacher,teacehrs,responsibilities, responsibility.
These are shown below:
import lombok.Data;
#Data
#XmlRootElement(name="school")
public class School {
private List<Students> Students;
private List<Teachers> Teachers;
}
#Data
public class Students {
private List<Student> student;
}
#Data
public class Student {
private long Id;
private String firstName;
private String lastName;
private String company;
private Responsibilities Responsibilities;
}
#XmlAccessorType(XmlAccessType.PROPERTY)
public class Responsibilities {
public List<String> responsibility ;
}
public class Responsibility {
private String responsibility;
}
#Data
public class Teachers {
private List<Teacher> teacher;
}
public class Teacher {
private String firstName;
private String lastName;
private String company;
private Responsibilities Responsibilities;
}
Also i have the main parsing file, where i want to generically pass all the objects through the root tag (school).
public class ParsingXML {
public static void main(String[] args) {
// TODO Auto-generated method stub
List<School> Entries = new ArrayList<School>();
try {
File xmlFile = new File("Student.xml");
JAXBContext jaxbContext;
jaxbContext = JAXBContext.newInstance(School.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
School entries = (School) jaxbUnmarshaller.unmarshal(xmlFile);
Entries.add(entries);
/*
* for(Student s: students.getStudent()) { System.out.println(s); }
*/
}
catch (JAXBException e)
{
e.printStackTrace();
}
ListIterator<School> litr = Entries.listIterator();
System.out.println(Entries.size());
//System.out.println("\n Using list iterator");
while(litr.hasNext()){
System.out.println(litr.next());
}
}
}
I expect to get Teachers entries too.. But I get ony students here.
Output:
School(Students=[Students(student=[Student(Id=1, firstName=A, lastName=C, company=BCD, Responsibilities=Responsibilities(responsibility=[Leader, Dancer, Reporter])), Student(Id=2, firstName=B, lastName=C, company=EFG, Responsibilities=Responsibilities(responsibility=[Singer]))])], Teachers=null)
Please suggest me my mistakes and provide me some guidance here
The following code would work for you:
School.class
#XmlRootElement(name = "school")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class School {
#XmlElementWrapper(name="students")
#XmlElement(name="student")
private List<Student> students;
#XmlElementWrapper(name="Teachers")
#XmlElement(name="Teacher")
private List<Teacher> responsibilities;
}
Teacher.class:
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Teacher {
#XmlElement(name="firstName")
private String firstName;
#XmlElement(name="lastName")
private String lastName;
#XmlElementWrapper(name="responsibilities")
#XmlElement(name="responsibility")
private List<String> responsibilities;
}
Student.class:
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Student {
#XmlElement(name="id")
private long Id;
#XmlElement(name="firstName")
private String firstName;
#XmlElement(name="lastName")
private String lastName;
#XmlElement(name="company")
private String company;
#XmlElementWrapper(name="responsibilities")
#XmlElement(name="responsibility")
private List<String> responsibilities;
}
Main.class:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("students.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(School.class).createUnmarshaller();
final School school = unmarshaller.unmarshal(xmlStreamReader, School.class).getValue();
System.out.println(school.toString());
Marshaller marshaller = JAXBContext.newInstance(School.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(school, System.out);
}
}
Following is the output:
School(students=[Student(Id=1, firstName=A, lastName=C, company=BCD, responsibilities=[Leader, Dancer, Reporter]), Student(Id=2, firstName=B, lastName=C, company=EFG, responsibilities=[Singer])], responsibilities=[Teacher(firstName=A, lastName=C, responsibilities=[English, Hindi, Softskills]), Teacher(firstName=A, lastName=C, responsibilities=[Science, Math])])
<school>
<students>
<student>
<id>1</id>
<firstName>A</firstName>
<lastName>C</lastName>
<company>BCD</company>
<responsibilities>
<responsibility>Leader</responsibility>
<responsibility>Dancer</responsibility>
<responsibility>Reporter</responsibility>
</responsibilities>
</student>
<student>
<id>2</id>
<firstName>B</firstName>
<lastName>C</lastName>
<company>EFG</company>
<responsibilities>
<responsibility>Singer</responsibility>
</responsibilities>
</student>
</students>
<Teachers>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<responsibilities>
<responsibility>English</responsibility>
<responsibility>Hindi</responsibility>
<responsibility>Softskills</responsibility>
</responsibilities>
</Teacher>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<responsibilities>
<responsibility>Science</responsibility>
<responsibility>Math</responsibility>
</responsibilities>
</Teacher>
</Teachers>
</school>
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>
Im using javax.xml.bind.annotation and I need to get the attribute "xmlns:language" (see below xml)
<type xmlns:language="ru" xmlns:type="string">Some text</type>
What annotation should I use?
#XmlRootElement(name = "type")
#XmlAccessorType(XmlAccessType.FIELD)
public class Type {
#XmlValue
protected String value;
#XmlAttribute
protected String language;
}
In the document from your question you are declaring that the prefix language will be associated with the namespace ru.
<type xmlns:language="ru" xmlns:type="string">Some text</type>
I do not believe the above is what you are trying to do. If you are trying to specify the language for your document I would recommend using the xml:lang attribute instead (as suggested by Ian Roberts).
<type xml:lang="ru">Some text</type>
Type
Then you would map to it as follows using the #XmlAttribute annotation:
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Type {
#XmlValue
protected String value;
#XmlAttribute(name = "lang", namespace = "http://www.w3.org/XML/1998/namespace")
protected String language;
}
Demo
import java.io.StringReader;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Type.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader(
"<type xml:lang='ru' xmlns:type='string'>Some text</type>");
Type type = (Type) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(type, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<type xml:lang="ru">Some text</type>
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