Reputation: 43
Facing issues with unmarshalling using JAXB. I need to use multiple namespaces. The Java classes are generated for the XSDs provided by a third party. So I do not want to specify the namespace at XMLRootElement in the Java classes and do not want to manually change multiple classes.
The marshalling logic as below:
private <R extends BasicResponseType, T extends BasicRequestType> R doPost(T request, String requestname) throws Exception {
if (jaxbContext == null)
jaxbContext = JAXBContext.newInstance(TokenRequest.class, TokenResponse.class,
BasicResponseType.class, GeneralErrorResponse.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
logXML(marshaller, request);
// POST to baseURL/requestname and show response
HttpURLConnection conn = openConnection("/" + requestname);
OutputStream os = conn.getOutputStream();
marshaller.marshal(request, os);
os.flush();
// Normaler Output oder Error liefern, je nach HTTP Response
InputStream is = null;
boolean ok = true;
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
is = conn.getErrorStream();
ok = false;
} else {
is = conn.getInputStream();
}
R response = (R) unmarshaller.unmarshal(new StreamSource(is));
is.close();
conn.disconnect();
logXML(marshaller, response);
if (ok) {
return response;
} else {
throw new Exception(getMessages((GeneralErrorResponse) response));
}
}
The xmlelement class TokenRequest.java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "TokenRequest")
public class TokenRequest
extends BasicInRequestType{ }
BasicInRequestType.java
package exp._3_0.api;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BasicInRequestType", propOrder = {
"software"
})
@XmlSeeAlso({
TokenRequest.class
})
public class BasicInRequestType
extends BasicRequestType {
@XmlElement(required = true)
protected SoftwareType software;
/**
* Gets the value of the software property.
*
* @return
* possible object is
* {@link SoftwareType }
*
*/
public SoftwareType getSoftware() {
return software;
}
/**
* Sets the value of the software property.
*
* @param value
* allowed object is
* {@link SoftwareType }
*
*/
public void setSoftware(SoftwareType value) {
this.software = value;
}}
BasicRequestType.java
package exp._3_0.api;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
propOrder = {
"header",
"user"
})
@XmlSeeAlso({
BasicInRequestType.class
})
public class BasicRequestType {
@XmlElement(required = true)
protected BasicHeaderType header;
@XmlElement(required = true)
protected UserHeaderType user;
@XmlType(name = "BasicRequestType", namespace = "http://foo/1.0/common",
/**
* Gets the value of the header property.
*
* @return
* possible object is
* {@link BasicHeaderType }
*
*/
public BasicHeaderType getHeader() {
return header;
}
/**
* Sets the value of the header property.
*
* @param value
* allowed object is
* {@link BasicHeaderType }
*
*/
public void setHeader(BasicHeaderType value) {
this.header = value;
}
/**
* Gets the value of the user property.
*
* @return
* possible object is
* {@link UserHeaderType }
*
*/
public UserHeaderType getUser() {
return user;
}
/**
* Sets the value of the user property.
*
* @param value
* allowed object is
* {@link UserHeaderType }
*
*/
public void setUser(UserHeaderType value) {
this.user = value;
}}
XML Output :
<TokenRequest xmlns:common="http://foo/1.0/common" xmlns:ns4="http://foo/3.0/api" xmlns:base="http://foo/3.0/base">
<common:header>
<common:requestId></common:requestId>
<common:timestamp></common:timestamp>
</common:header>
<common:user>
<common:login></common:login>
<common:passwordHash></common:passwordHash>
</common:user>
<software>
<softwareId></softwareId>
<softwareName></softwareName>
</software>
</TokenRequest>
I have specifies the prefix in package-info.java
@javax.xml.bind.annotation.XmlSchema(elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, xmlns = {
@javax.xml.bind.annotation.XmlNs(namespaceURI = "http://foo/3.0/api", prefix = ""),
@javax.xml.bind.annotation.XmlNs(namespaceURI = "http://foo/3.0/base", prefix = "base"),
@javax.xml.bind.annotation.XmlNs(namespaceURI = "http://foo/1.0/common", prefix = "common") })
package exp._3_0.api;
The TokenRequest element actually refers to the namespace = "http://foo/3.0/api". In the xml output the TokenRequest does not have the any prefix which is correct but the xmlns is set to ns4 which is causing the below error.
Request body contains on line: [1] and column: [182] error: [unexpected element (uri:"", local:"TokenRequest"). Expected elements are <{http://foo/3.0/api}TokenRequest>]
Even after specifying the prefix = "" for namespace "http://foo/3.0/api" in package-info, in the output its still appending as ns4. Please help how to fix remove the ns4.
Upvotes: 3
Views: 5906
Reputation: 16045
As remarked in the comments, your @XmlSchema
lacks a namespace
attribute, therefore all @XmlRootElement
and @XmlType
are considered to be without a namespace, unless explicitly qualified. Your java-package.info
should look like this:
@XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = "http://foo/3.0/api", xmlns = {
@XmlNs(namespaceURI = "http://foo/3.0/api", prefix = ""),
@XmlNs(namespaceURI = "http://foo/3.0/base", prefix = "base"),
@XmlNs(namespaceURI = "http://foo/1.0/common", prefix = "common")})
package exp._3_0.api;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
The @XmlNs
annotation does not specify the default namespace used in the Java package. They only provide a suggestion to the JAXB implementation on what prefixes to assign to those namespaces. In your example the tags <TokenRequest>
, <software>
, <softwareId>
and <softwareName>
do not belong to any namespace, therefore JAXB uses an empty prefix for these elements and must use another prefix (ns4
) for the elements in the http://foo/3.0/api
namespace (there aren't any).
Upvotes: 1