JAXB元素既可选又可以为nillable [英] JAXB element that is both optional and nillable

查看:108
本文介绍了JAXB元素既可选又可以为nillable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经重新格式化了这个问题,希望能让我的意图更清晰。

I have re-formatted the question to hopefully make my intentions clearer.

架构

我是写一些我将使用JAX-WS自己发布的Web服务。我们已经使用了一段时间的过程是首先编写一个仅定义请求和响应对象的模式。这将被发送给客户以批准xml消息的结构。我不想自己编写整个wsdl,因为它比基本模式更复杂。

Architecture
I'm writing some web services that I will be publishing myself using JAX-WS. The process we have been using for some time is to first write a schema that only defines the request and response objects. This gets sent to the customer to approve the structure of the xml messages. I don't want to write the whole wsdl myself as it's more complicated than the basic schema.

接下来我使用JAXB命令xjc根据请求生成类,我的架构中的响应类型。然后我使用这个类作为参数并在JAX-WS带注释的端点类上返回类型。

Next I use the JAXB command xjc to generate classes based on the request and response types in my schema. I then use this classes as parameters and return types on a JAX-WS annotated endpoint class.

现在这给了我一个我可以调用的Web服务。它使我能够更好地控制发送和返回的xml,但也可以自动完成写入完整wsdl所需的重复。

This now gives me a web service I can call. It gives me more control over the xml being sent and returned but also automates the repetition required in writing the full wsdl.

问题

在模式中我有这样的元素:

Problem
In the schema I have an element like this:

<xs:element name="myElement" type="xs:string" nillable="true" minOccurs="0" /> 

所以我想区分用户设置null或空白。生成的类具有此属性。

So I want to distinguish between the user setting null or blank. The generated class then has this attribute.

@XmlElementRef(name = "myElement", namespace = "/mynamespace", type = JAXBElement.class)
protected JAXBElement<String> myElement;

这样做的结果是元素既不​​是可填充的也不是可选的。 JAX-WS作为wsdl的一部分写入的模式已将元素设置为必需而不是nillable,如果我关闭模式验证,我仍然无法将nil传递给我的对象。

The effect of this is that the element becomes neither nillable or optional. The schema that JAX-WS writes as part of the wsdl has set the element to mandatory and not nillable and if I turn off schema validation I still can't pass nil through to my object.

尝试的事情

如果我将其更改为必需且可以收费,那么我将获得此生成的代码。

Things tried
If I change it to be required and nillable then I get this generated code.

@XmlElement(required = true, nillable = true)
protected String myElement;

如果我将其更改为可选而不是nillable,那么我将获得此生成的代码。

If I change it to optional and not nillable then I get this generated code.

protected String myElement

因此,如果您使用JAXB,您可以拥有或不是两者。非常令人失望!

So you can have either or but not both it seems if you use JAXB. Thoroughly disappointing!

我也尝试手动将生成的类更改为这样。

I've also tried manually changing the generated class to look like this.

@XmlElementRef(name = "myElement", namespace = "/mynamespace", type = JAXBElement.class, required=false)
protected JAXBElement<String> myElement;

这现在使元素可选,但我仍然无法将其设置为nil。这样做会导致JAXBElement的值为空字符串。只有当你关闭模式验证时才会这样做,因为生成的JAX-WS wsdl / schema没有将元素设置为nillable,所以它不是一个有效的请求。

This now makes the element optional but I still can't set it to nil. Doing so results in a JAXBElement with a value of a blank string. That's only if you turn schema validation off as the resulting JAX-WS wsdl/schema doesn't set the element as nillable, so its not a valid request.

摘要

我相信这是JAXB的一个错误。 @XmlElementRef注释具有将其设置为不需要的属性,但没有将该字段设置为可空的属性。

Summary
It's my belief that this is a bug with JAXB. The @XmlElementRef annotation has an attribute to set it as not required but there is no attribute to set the field as nullable.

@XmlElement注释具有必需和可空的属性,但这些只会导致null对象,因此无法区分xml中未包含的元素或包含但为null的元素。这就是为什么你需要使用@XmlElementRef和JAXBElement。

The @XmlElement annotation has attributes for both required and nullable but these just result in a null object so there would be no way to distinguish between an element not included in the xml or an element that was included but null. This is why you need to use @XmlElementRef along with JAXBElement.

我认为这个bug包含两个问题。首先,xjc命令应生成required = false的元素。其次,@ xmlElementRef应该有一个属性来设置元素是否可以为空,这也应该设置。

I think the bug includes two issues. First the xjc command should generate the element with required=false. Second there should be an attribute on @XmlElementRef to set whether the element is nullable and this should be set too.

有没有人知道修复/解决方法?我尝试使用谷歌搜索,但只发现人们在没有答案的情况下问同样的问题。这通常意味着它不可能...... TIA。

Does anyone know of a fix/workaround? I tried googling but only found people asking the same question without an answer. This usually means it's not possible... TIA.

附加

我正在使用jaxb 2.2.6和maven插件是jaxb2-maven-plugin 1.5。

Additional
I'm using jaxb 2.2.6 and the maven plugin is jaxb2-maven-plugin 1.5.

推荐答案

TL; DR



For

TL;DR

For

@XmlElementRef(name="foo", required=false)
protected JAXBElement<String> foo;

文档中缺少的节点将对应于此字段为空。文档中存在的 xsi:nil =true的XML元素将对应于作为 JAXBElement 值为 null

An absent node in the document will correspond to this field being null. An XML element present in the document with xsi:nil="true" will correspond to the value being an instance of JAXBElement with a value of null.

您还可以提供XML架构,而不是让JAXB使用包级别 location 属性 @XmlSchema 注释。

You can also provide an XML schema instead of having JAXB generate one using the location property on the package level @XmlSchema annotation.

@XmlSchema(
    ...
    location="http://www.example.com/schema/root.xsd")
package forum19665550;

import javax.xml.bind.annotation.XmlSchema;






Marshal / Unmarshal



Java模型



Root

这是一个具有两个字段的对象,可以表示可选和可存档的数据。

This is an object with two fields that can represent optional and nillable data.

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlElementRef(name="foo", required=false)
    protected JAXBElement<String> foo;

    @XmlElementRef(name="bar", required=false)
    protected JAXBElement<String> bar;

}

ObjectFactory

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

    @XmlElementDecl(name="foo")
    public JAXBElement<String> createFoo(String foo) {
        return new JAXBElement<String>(new QName("foo"), String.class, foo);
    }

    @XmlElementDecl(name="bar")
    public JAXBElement<String> createBar(String bar) {
        return new JAXBElement<String>(new QName("bar"), String.class, bar);
    }

}



演示代码



演示

下面的演示代码将调查 foo bar 。您可以使用 JAXBIntrospector 类来获取 JAXBElement 实例的实际值。 EclipseLink JAXB(MOXy)中有一个与解组 JAXBElement 实例包装空值有关的错误(请参阅: http://bugs.eclipse.org/420746

The demo code below will investigate the differences in the values for foo and bar. You can use the JAXBIntrospector class to get the real value for an instance of JAXBElement. There is a bug in EclipseLink JAXB (MOXy) related to unmarshalling an instance of JAXBElement wrapping a null value (see: http://bugs.eclipse.org/420746).

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum19665550/input.xml");
        Root root = (Root) unmarshaller.unmarshal(xml);

        System.out.println("foo was set:          " + (root.foo != null));
        System.out.println("bar was set:          " + (root.bar != null));
        System.out.println("foo value:            " + root.foo);
        System.out.println("bar value:            " + root.bar);
        System.out.println("foo unwrapped value:  " + JAXBIntrospector.getValue(root.foo));
        System.out.println("bar unwrapped value:  " + JAXBIntrospector.getValue(root.bar));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

input.xml /输出

在结果输出中,我们看到我们可以区分文档中缺少的元素和`xsi:nil =true的元素并且结果值仍为null。

In the resulting output we see that we can differentiate between an element being absent from the document and an element with `xsi:nil="true" and still have the resulting value be null.

foo was set:          false
bar was set:          true
foo value:            null
bar value:            javax.xml.bind.JAXBElement@4af42ea0
foo unwrapped value:  null
bar unwrapped value:  null
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>





生成XML架构



演示代码



GenerateSchema

下面是一些JAXB代码,它将从带注释的模型生成XML Schema。

Below is some JAXB code that will generate an XML Schema from the annotated model.

import java.io.IOException;
import javax.xml.bind.*;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

public class GenerateSchema {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);

        jc.generateSchema(new SchemaOutputResolver() {

            @Override
            public Result createOutput(String namespaceUri,
                    String suggestedFileName) throws IOException {
                StreamResult result = new StreamResult(System.out);
                result.setSystemId(suggestedFileName);
                return result;
            }

        });
    }

}

输出

以下是生成的XML Schema。你是正确的,它并不表示 foo bar 元素是可以为空的。

Here is the resulting XML Schema. You are correct that it doesn't indicate that the foo and bar elements are nillable.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="bar" type="xs:string"/>

  <xs:element name="foo" type="xs:string"/>

  <xs:element name="root" type="root"/>

  <xs:complexType name="root">
    <xs:sequence>
      <xs:element ref="foo" minOccurs="0"/>
      <xs:element ref="bar" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>






提供XML架构



您可以指向包含更多信息的现有XML Schema,而不是让JAXB从您的模型中派生XML Schema。


Providing an XML Schema

Instead of having JAXB derive an XML Schema from your model, you can point to your existing one that will contain more information.

package-info

这是通过在包级别指定 location 属性来完成的code> @XmlSchema 注释。

This is done by specifying the location property on the package level @XmlSchema annotation.

@XmlSchema(
    ...
    location="http://www.example.com/schema/root.xsd")
package forum19665550;

import javax.xml.bind.annotation.XmlSchema;

这篇关于JAXB元素既可选又可以为nillable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆