带有自定义JAX-B绑定的JAX-WS MarshalException:无法将类型“java.lang.String”编组为元素

时间:2010-04-13 03:22:58

标签: java web-services soap jaxb jax-ws

我似乎遇到了Jax-WS和Jax-b一起玩的问题。我需要使用一个具有预定义WSDL的Web服务。执行生成的客户端时,我收到以下错误:

  

javax.xml.ws.WebServiceException:javax.xml.bind.MarshalException - 包含链接异常:   [com.sun.istack.SAXException2:无法封装类型“java.lang.String”作为元素,因为它缺少@XmlRootElement注释]

当我使用外部自定义绑定文件将不必要的复杂类型映射到java.lang.string时,就开始发生这种情况。以下是我的绑定文件的摘录:

<?xml version="1.0" encoding="UTF-8"?>
  <bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.0" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
      xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
    <bindings schemaLocation="http://localhost:7777/GESOR/services/RegistryUpdatePort?wsdl#types?schema1" node="/xs:schema">
      <bindings node="//xs:element[@name='StwrdCompany']//xs:complexType//xs:sequence//xs:element[@name='company_name']">
        <property>
          <baseType name="java.lang.String" />
        </property>
      </bindings>
      <bindings node="//xs:element[@name='StwrdCompany']//xs:complexType//xs:sequence//xs:element[@name='address1']">
        <property>
          <baseType name="java.lang.String" />
        </property>
      </bindings>
      <bindings node="//xs:element[@name='StwrdCompany']//xs:complexType//xs:sequence//xs:element[@name='address2']">
        <property>
          <baseType name="java.lang.String" />
        </property>
      </bindings>
      ...more fields
  </bindings>
</bindings>

对提供的WSDL执行wsimport时,会生成StwrdCompany并声明以下变量:

@XmlRootElement(name = "StwrdCompany")
public class StwrdCompany 
{
    @XmlElementRef(name = "company_name", type = JAXBElement.class)
    protected String companyName;
    @XmlElementRef(name = "address1", type = JAXBElement.class)
    protected String address1;
    @XmlElementRef(name = "address2", type = JAXBElement.class)
    ... more fields

    ... getters/setters

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "value"
    })
    public static class CompanyName {

        @XmlValue
        protected String value;
        @XmlAttribute
        protected Boolean updateToNULL;

        /**
         * Gets the value of the value property.
         * 
         * @return
         *     possible object is
         *     {@link String }
         *     
         */
        public String getValue() {
            return value;
        }

        /**
         * Sets the value of the value property.
         * 
         * @param value
         *     allowed object is
         *     {@link String }
         *     
         */
        public void setValue(String value) {
            this.value = value;
        }

        /**
         * Gets the value of the updateToNULL property.
         * 
         * @return
         *     possible object is
         *     {@link Boolean }
         *     
         */
        public boolean isUpdateToNULL() {
            if (updateToNULL == null) {
                return false;
            } else {
                return updateToNULL;
            }
        }

        /**
         * Sets the value of the updateToNULL property.
         * 
         * @param value
         *     allowed object is
         *     {@link Boolean }
         *     
         */
        public void setUpdateToNULL(Boolean value) {
            this.updateToNULL = value;
        }

       ... more inner classes
       }
   }

最后,这里是来自WSDL的关联片段,似乎引起了这样的悲痛。

<xs:element name="StwrdCompany">
  <xs:complexType>
    <xs:sequence>
      <xs:element maxOccurs="1" minOccurs="0" name="company_name" nillable="true">
        <xs:complexType>
          <xs:simpleContent>
            <xs:extension base="xs:string">
              <xs:attribute default="false" name="updateToNULL" type="xs:boolean"/>
            </xs:extension>
          </xs:simpleContent>
        </xs:complexType>
      </xs:element>
      <xs:element maxOccurs="1" minOccurs="0" name="address1" nillable="true">
        <xs:complexType>
          <xs:simpleContent>
            <xs:extension base="xs:string">
              <xs:attribute default="false" name="updateToNULL" type="xs:boolean"/>
            </xs:extension>
          </xs:simpleContent>
        </xs:complexType>
      </xs:element>
      ... more fields in the same format

      <xs:element maxOccurs="1" minOccurs="0" name="p_source_timestamp" nillable="false" type="xs:string"/>
    </xs:sequence>
    <xs:attribute name="company_xid" type="xs:string"/>
  </xs:complexType>
</xs:element>

自定义绑定的原因是我可以更轻松地将用户输入从pojo映射到StwrdCompany对象,无论是直接实例化还是通过使用Dozer进行bean映射。没有自定义绑定,我无法在对象之间成功映射。

最后,我尝试的另一件事是设置一个globalBinding定义:

<globalBindings generateValueClass="false"></globalBindings>  

这导致服务器通过参数不匹配异常,因为Soap Message使用xs:string xml类型而不是传递定义的复杂类型,所以我放弃了这个想法。

非常感谢任何有关导致MarshalException的原因或如何解决调用web服务和更轻松地映射这些对象的问题。我一直在寻找几天,我很遗憾地认为我很难过。

2 个答案:

答案 0 :(得分:2)

您需要在<xjc:simple />部分中添加<jaxb:globalBindings>元素,以使JAXB正确处理根元素。只需将以下内容插入绑定文件

即可
<jaxb:globalBindings>
   <xjc:simple />
</jaxb:globalBindings>

我有一个JAXB映射样本here,您可以使用它来获取灵感。

答案 1 :(得分:1)

该错误意味着JAXB正在尝试对String进行编组,就好像它是一个XML元素 - 显然它不是。因此,例如将“foo”编组为XML,实际上应该是“foo”之类的东西。这样做的原因是因为映射...使一个元素到一个String也具有相同的效果:所以它试图将String映射到一个元素,这会导致无效的XML。

Lars的解决方案应该有效。您可以做的另一件事是将它映射到JAXB可以编组的(简单)自定义类。如果你很勇敢,你也可以尝试使用JAXBElement。