简体   繁体   English

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

[英]JAX-WS MarshalException with custom JAX-B bindings: Unable to marshal type “java.lang.String” as an element

I seem to be having an issue with Jax-WS and Jax-b playing nicely together. 我似乎遇到了Jax-WS和Jax-b一起玩的问题。 I need to consume a web-service, which has a predefined WSDL. 我需要使用一个具有预定义WSDL的Web服务。 When executing the generated client I am receiving the following error: 执行生成的客户端时,我收到以下错误:

javax.xml.ws.WebServiceException: javax.xml.bind.MarshalException - with linked exception: [com.sun.istack.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an @XmlRootElement annotation] javax.xml.ws.WebServiceException:javax.xml.bind.MarshalException - 带有链接异常:[com.sun.istack.SAXException2:无法封送类型“java.lang.String”作为元素,因为它缺少@XmlRootElement注解]

This started occurring when I used an external custom binding file to map needlessly complex types to java.lang.string. 当我使用外部自定义绑定文件将不必要的复杂类型映射到java.lang.string时,就会发生这种情况。 Here is an excerpt from my binding file: 以下是我的绑定文件的摘录:

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

When executing wsimport against the provided WSDL, StwrdCompany is generated with the following variables declared: 对提供的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
       }
   }

Finally, here is the associated snippet from the WSDL that seems to be causing such grief. 最后,这里是来自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>

The reason for the custom binding is so I can map user input from a pojo into the StwrdCompany object more easily, whether it be direct instantiation or through the use of Dozer for bean mapping. 自定义绑定的原因是我可以更容易地将来自pojo的用户输入映射到StwrdCompany对象,无论是直接实例化还是通过使用Dozer进行bean映射。 I was unable to successfully map between the objects without the custom binding. 没有自定义绑定,我无法在对象之间成功映射。

Finally, one other thing I tried was setting a globalBinding definition: 最后,我尝试的另一件事是设置一个globalBinding定义:

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

This caused the server to through an argument mismatch exception since the Soap Message was using xs:string xml types instead of passing the defined complex types, so I abandoned that idea. 这导致服务器通过参数不匹配异常,因为Soap Message使用xs:string xml类型而不是传递定义的复杂类型,所以我放弃了这个想法。

Any insight into what is causing the MarshalException or how to go about solving the issue of calling the webservice and mapping these objects more easily, is greatly appreciated. 我们非常感谢您对导致MarshalException的原因以及如何解决调用Web服务和更轻松地映射这些对象的问题的深入了解。 I've been searching for days and I sadly think I am stumped. 我一直在寻找几天,我很遗憾地认为我很难过。

You need to add a <xjc:simple /> element inside your <jaxb:globalBindings> section for making JAXB handling root elements correctly. 您需要在<jaxb:globalBindings>部分中添加<xjc:simple />元素,以使JAXB正确处理根元素。 Just insert the following into your bindings file 只需将以下内容插入绑定文件即可

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

I have a JAXB mapping sample here you can use for inspiration. 我在这里有一个JAXB映射示例您可以使用它来获取灵感。

That error means JAXB is trying to marshall a String as if it were an XML element -- which it obviously isn't. 该错误意味着JAXB正在尝试对String进行编组,就好像它是一个XML元素 - 显然它不是。 So, for example marshalling "foo" as XML, when really it should be something like "foo". 因此,例如将“foo”编组为XML,实际上应该是“foo”之类的东西。 The reason it's doing this is because of the mapping... making an element to a String also has the same effect the other way: so it's trying to map the String to an element, which results in invalid XML. 这样做的原因是因为映射...使一个元素到一个String也具有相同的效果:所以它试图将String映射到一个元素,这导致无效的XML。

Lars' solution with should work. Lars的解决方案应该有效。 The other thing you can do is map it to a (simple) custom class that JAXB can marshal. 您可以做的另一件事是将它映射到JAXB可以编组的(简单)自定义类。 If you're brave, you can try messing around with JAXBElement too. 如果你很勇敢,你也可以尝试使用JAXBElement。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM