指定名称空间 JAXB 的前缀

Specifying prefix to namespace JAXB

面临使用 JAXB 解组的问题。我需要使用多个名称空间。 Java classes 是为第三方提供的 XSD 生成的。所以我不想在 Java classes 中的 XMLRootElement 指定名称空间,也不想手动更改多个 classes.

编组逻辑如下:

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));
    }
}

xml元素classTokenRequest.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 输出:

<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>

我在包中指定了前缀-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;

TokenRequest 元素实际上指的是命名空间=“http://foo/3.0/api”。在 xml 输出中,TokenRequest 没有任何正确的前缀,但 xmlns 设置为 ns4,这导致了以下错误。

Request body contains on line: [1] and column: [182] error: [unexpected element (uri:"", local:"TokenRequest"). Expected elements are <{http://foo/3.0/api}TokenRequest>]

即使在 package-info 中为命名空间“http://foo/3.0/api”指定了前缀 =“”,在输出中它仍然附加为 ns4。请帮助如何修复删除ns4。

如评论中所述,您的 @XmlSchema 缺少 namespace 属性,因此所有 @XmlRootElement@XmlType 都被认为没有命名空间,除非 明确合格。您的 java-package.info 应如下所示:

@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;

@XmlNs 注释 没有 指定 Java 包中使用的默认命名空间。他们仅向 JAXB 实现提供 建议 以分配给那些名称空间的前缀。在您的示例中,标签 <TokenRequest><software><softwareId><softwareName> 不属于任何命名空间,因此 JAXB 对这些元素使用空前缀并且必须使用另一个前缀( ns4) 对于 http://foo/3.0/api 命名空间中的元素(没有)。