I have a response from a RESTful XML webservice, stored as a string.
String responseAsStr = response.readEntity(String.class);
Im trying to map the response to an object I generated using a schema.
XmlMapper xmlMapper = new XmlMapper();
ResponseType responseAsObj = xmlMapper.readValue(responseAsStr, ResponseType.class);
When executing the line xmlMapper.readValue(...) I get this error :
Unrecognized field "ResponseType" (class blah.bleh.smth.ResponseType), not marked as ignorable (22 known properties: "responseType" ...)
The generated class containing the problem field looks like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"responseType",
...
})
#XmlRootElement(name = "SomeClassElement")
public class SomeClassElement {
#XmlElement(name = "ResponseType")
protected ResponseType responseType;
...
public ResponseType getResponseType() {
return responseType;
}
public void setErrorDetail(ResponseType value) {
this.responseType = value;
}
...
}
The problem field class looks like:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"1",
"2"
})
public static class ResponseType {
#XmlElement(name = "1", required = true)
protected String 1;
#XmlElement(name = "2", required = true)
protected String 2;
/**
The incoming XML Looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SomeClassElement xmlns="redacted">
<ResponseType>
<1>BlahBlah</1>
<2>BlahBlah</2>
</ResponseType>
</SomeClassElement>
Has anyone encountered this before? It seems as if Jackson is unable to identify the field due to the lack of capitalisation in the "known properties" array (responseType as opposed to ResponseType). I altered the #XmlType decorator to see if changing capitalization fixed the issue here but alas the error persists.
Related
I am having the typical 'unexpected element (uri:"", local:"stickynote")' JAXB error, although it only shows when I set the event handler on the unmarshaller object. When the event handler is not set code runs fine, but the specific data needed is not unmarshalled.
I have worked on the problem for a couple of days, including many Internet searches, and am not hitting on the right solution. I feel like I am missing something simple, but so far it is eluding me.
Notes:
I am using Java JDK 8 with Apache NetBeans 15.
The original code was generated with the xjc command from schemas we receive from multiple vendors. I cannot modify the schemas and have to figure out how to use them "as is".
I wrote the code below to duplicate the issue and simplify the posted code. Import statements have been removed for brevity. If they are needed please let me know.
Since inheritance is involved in one of the classes, I added the appropriate #XmlSeeAlso annotation. That did not help.
This is my first real foray into JAXB. It seems to be perfect for this project. I just have to figure out how to get it to work.
First, example XML:
<?xml version="1.0" encoding="UTF-8"?>
<documents>
<document>
<notes>
<stickynote id="123">test note</stickynote>
</notes>
</document>
</documents>
Code to create the JAXB context and create the Unmarshaller object:
JAXBContext context = JAXBContext.newInstance( Documents.class );
Unmarshaller u = context.createUnmarshaller();
u.setEventHandler(new DefaultValidationEventHandler());
JAXBElement< Documents > root =
u.unmarshal(
new StreamSource( new File( FILENAME )),
Documents.class );
The corresponding classes to handle each element:
Documents class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "document" })
#XmlRootElement(name = "documents", namespace = "http://www.example.org/documents")
public class Documents {
protected Document document;
public Document getDocument() {
return document;
}
public void setDocument(Document document) {
this.document = document;
}
}
Document class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "notes" })
#XmlRootElement(name = "document", namespace = "http://www.example.org/documents")
public class Document {
protected NotesType notes;
public NotesType getNotes() {
return notes;
}
public void setNotes(NotesType notes) {
this.notes = notes;
}
}
NotesType class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "NotesType", propOrder = { "notes" })
public class NotesType {
protected List<NoteType> notes;
public List<NoteType> getNotes() {
if ( isNull( notes )) {
notes = new ArrayList<>();
}
return this.notes;
}
}
NoteType class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "NoteType", propOrder = { "note" })
#XmlSeeAlso({ StickyNote.class })
public class NoteType {
#XmlAttribute(name = "id", required = true)
protected String id;
protected String note;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
And finally, the StickyNote class, which extends the NoteType class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "subType" })
public class StickyNote extends NoteType {
protected String subType = "sticky";
public String getSubType() {
return subType;
}
public void setSubType(String subType) {
this.subType = subType;
}
}
The exception is:
DefaultValidationEventHandler: [ERROR]: unexpected element (uri:"", local:"stickynote"). Expected elements are <{}notes>
Location: line 5 of file:/C:/Test/documents.xml
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"stickynote"). Expected elements are <{}notes>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
*and so on*
Thanks in advance for any and all suggestions and help!
john
My issue turned out to be how I was using xjc. I was building each schema we received individually, not realizing there was some overlap in the schemas due to the vendors using other vendors schemas. This caused issues when one vendor's schema was built early in the process and then another vendor's schema was built after it that used the earlier vendor's schema.
Building all the schemas as a group, instead of individually, allowed xjc to "see" everything it needed to see and the corresponding code worked as expected.
A sample code with jaxb-api 2.3.1 and Java 8 using StringWriter for jaxbMarshaller:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"currencyCode",
"discountValue",
"setPrice"
})
#XmlRootElement(name = "countryData")
public class CountryData {
protected String currencyCode;
protected String discountValue = "";
protected String setPrice = "";
// setters and setters
}
When I marshal the entity to a XML string with:
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(countryDataObject, sw);
sw.toString();
How to get expected result for empty values?
<currencyCode>GBP</currencyCode>
<discountValue/>
<setPrice/>
Actual output:
<currencyCode>GBP</currencyCode>
<discountValue></discountValue>
<setPrice></setPrice>
don't initialized the variables. use the nillable attribute and set it value to true
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "currencyCode", "discountValue", "setPrice" })
#XmlRootElement(name = "countryData")
public class CountryData {
#XmlElement(nillable=true)
protected String currencyCode;
#XmlElement(nillable=true)
protected String discountValue;
#XmlElement(nillable=true)
protected String setPrice;
// getters and setters
}
output
<currencyCode>GBP</currencyCode>
<discountValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<setPrice xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
Although the strings are empty they still contain non-null data and the end tag is generated. Remove the default values of the strings or set them as null (a default instance field value):
protected String discountValue;
protected String setPrice;
The tags become closed:
<discountValue/>
<setPrice/>
I have the following JAXB annotated classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"payload"
})
#XmlRootElement(name = "response")
public class MyResponse {
#XmlElement(required = true)
protected MyPayload payload;
public MyPayload getPayload() {
return payload;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "myPayload", propOrder = {
"any"
})
public class MyPayload {
#XmlAnyElement(lax = true)
protected Object any;
public Object getAny() {
return any;
}
public void setAny(Object value) {
this.any = value;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "mySpecificPayload", propOrder = {
"field1",
"field2",
})
public class MySpecificPayload {
#XmlElement(name = "field-1", required = true)
protected String field1;
#XmlElement(name = "field-2")
protected String field2;
}
When I try and deserialize an input of:
<response>
<payload>
<my-specific-payload>
<field-1>value1</field-1>
<field-2>value2</field-2>
</my-specific-payload>
</payload>
</response>
using:
ObjectMapper mapper = new XmlMapper();
mapper.registerModule(new JaxbAnnotationModule());
MyResponse value = mapper.readValue(myXmlString, MyResponse.class);
I get:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "my-specific-payload" (class
com.example.MyPayload), not marked as ignorable (one known property:
"any"])
I would like to be able to do:
MyResponse value = mapper.readValue(myXmlString, MyResponse.class);
MySpecificPayload msp = (MySpecificPayload) value.getPayload().getAny();
Currently using jackson libs with version: 2.9.6 How can I get jackson to achieve this?
Thank you kindly,
Jason
Im struggling with the jaxb2marshaller configuration to work with classes generated from wsdl file.
My jaxb2marshaller
public Jaxb2Marshaller marshaller() {
final Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPaths("org.otheruri", "org.tempuri");
return marshaller;
}
I prepare a structure of classes and pass them thru marshaller.marshal to get the xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:ValidateResponse xmlns="http://otheruri.org" xmlns:ns2="http://tempuri.org/">
<ns2:ValidateResult>
<ArrayOfPerson>
<Person><NawNumber>personNAW</NawNumber></Person>
</ArrayOfPerson>
</ns2:ValidateResult>
</ns2:ValidateResponse>
But when I take this xml and run marshaller.unmarshall the ValidateResult.arrayOfPerson is null. There is no stacktrace or anything.
My generated classes look like this
package org.tempuri
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"validateResult"
})
#XmlRootElement(name = "ValidateResponse")
public class ValidateResponse {
#XmlElementRef(name = "ValidateResult", namespace = "http://tempuri.org/", type = JAXBElement.class, required = false)
protected JAXBElement<org.otheruri.ValidateResponse> validateResult;
public JAXBElement<org.otheruri.ValidateResponse> getValidateResult() {
return validateResult;
}
public void setValidateResult(JAXBElement<org.otheruri.ValidateResponse> value) {
this.validateResult = value;
}
}
and
package org.otheruri
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ValidateResponse", propOrder = {
"persons",
"userLoggedIn"
})
public class ValidateResponse {
#XmlElementRef(name = "Persons", namespace = "http://otheruri.org", type = JAXBElement.class, required = false)
protected JAXBElement<ArrayOfPerson> persons;
#XmlElementRef(name = "UserLoggedIn", namespace = "http://otheruri.org", type = JAXBElement.class, required = false)
protected JAXBElement<ValidateCredentialsResponse> userLoggedIn;
public JAXBElement<ArrayOfPerson> getPersons() {
return persons;
}
public void setPersons(JAXBElement<ArrayOfPerson> value) {
this.persons = value;
}
public JAXBElement<ValidateCredentialsResponse> getUserLoggedIn() {
return userLoggedIn;
}
public void setUserLoggedIn(JAXBElement<ValidateCredentialsResponse> value) {
this.userLoggedIn = value;
}
}
EDIT
So after time and lots of debbuging I know what is wrong. For unknown reason the created xml has ArrayOfPerson node (like class name) instead of Persons (that is specified in #XmlElementRef). Still I dont know why this is happening
So in the end it appeared that my generated object factory had 2 methods that returned same JaxbObject and accepted ArrayOfPerson object and very similar name, but had different name specified in the #XmlElementDecl, and of course I used the wrong one to generate xml, so I could not consume it later. :/
I have the following JAXB entity:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNER)
public class FilePartner
{
#XmlAttribute(name = EntityConstants.IDENTIFIER, required = true)
private String identifier;
#XmlElement(name = EntityConstants.NAME)
private String name;
#XmlElement(name = EntityConstants.ROOT_PATH)
private String rootPath;
...
}
which serialized into a similar structure:
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
I also have an entity which represents a list of partners:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private List<FilePartner> partners = new ArrayList<FilePartner>();
public List<FilePartner> getPartners()
{
return partners;
}
public void addPartners(List<FilePartner> partners)
{
this.partners.addAll(partners);
}
}
which serializes into:
<partners>
<file-partner identifier="foo">
...
</file-partner>
<file-partner identifier="foo2">
...
</file-partner>
...
</partners>
I am looking for a way to force the jaxb unmarshaller to deserialize XMLs in the form of
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
into FilePartnerList instances with list size of 1, i.e:
JAXBContext context = JAXBContext.newInstance(FilePartner.class, FilePartnerList.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
InputStream inputStream = getResourceAsStream(filePartnerAsXml);
FilePartnerList partnerList = (FilePartnerList) unmarshaller.unmarshal(inputStream); // This SHOULD be unmarshalled to FilePartnerList instead of FilePartner
assertTrue(partnerList.getPartners().getSize().equals(1));
How do I achieve that?
private List<FilePartner> partners = new ArrayList<FilePartner>(**1**);
That way you'll get a fixed size input array....
But I'm sure that you will want to get the XSD of that model with the 'maxocurrs=1' so you will end modifying the XSD manually.
Anyway: why don't you, if the list size must be fixed to '1', simply set it as a simple node with a single child? Something like this (untested):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private FilePartner partners;
public FilePartner getFilePartner()
{
return partner;
}
public void setPartner(FilePartner partner)
{
this.partner = partner;
}
}
This way you will have one and only one partner per parnets-list.
The XML that fullfits the XSD of your service a text and in that text is indistinguible a list with max size 1 and a node.