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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2626771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 22:05:29  来源:igfitidea点击:

JAX-WS MarshalException with custom JAX-B bindings: Unable to marshal type "java.lang.String" as an element

javaweb-servicessoapjaxbjax-ws

提问by tnicks

I seem to be having an issue with Jax-WS and Jax-b playing nicely together. I need to consume a web-service, which has a predefined WSDL. When executing the generated client I am receiving the following error:

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

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. Here is an excerpt from my binding file:

当我使用外部自定义绑定文件将不必要的复杂类型映射到 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>

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. I was unable to successfully map between the objects without the custom binding.

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

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 消息使用 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. I've been searching for days and I sadly think I am stumped.

非常感谢您对导致 MarshalException 的原因或如何解决调用 Web 服务和更轻松地映射这些对象的问题的任何见解。我已经找了好几天了,可悲的是我觉得自己被难住了。

采纳答案by Lars Tackmann

You need to add a <xjc:simple />element inside your <jaxb:globalBindings>section for making JAXB handling root elements correctly. Just insert the following into your bindings file

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

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

I have a JAXB mapping sample hereyou can use for inspiration.

我在这里有一个 JAXB 映射示例您可以从中汲取灵感。

回答by Gabriel Jiva

That error means JAXB is trying to marshall a String as if it were an XML element -- which it obviously isn't. So, for example marshalling "foo" as XML, when really it should be something like "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.

该错误意味着 JAXB 试图将 String 当作 XML 元素来编组——这显然不是。因此,例如将“foo”编组为 XML,而实际上它应该类似于“foo”。它这样做的原因是因为映射......将元素制作成字符串也有另一种方式的相同效果:所以它试图将字符串映射到一个元素,这会导致无效的 XML。

Lars' solution with should work. The other thing you can do is map it to a (simple) custom class that JAXB can marshal. If you're brave, you can try messing around with JAXBElement too.

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