Ben*_*ley 10 java xml jax-ws jaxb
我重新格式化了这个问题,希望能让我的意图更加清晰.
架构
我正在编写一些Web服务,我将使用JAX-WS自行发布.我们已经使用了一段时间的过程是首先编写一个仅定义请求和响应对象的模式.这将被发送给客户以批准xml消息的结构.我不想自己编写整个wsdl,因为它比基本模式更复杂.
接下来,我使用JAXB命令xjc根据模式中的请求和响应类型生成类.然后,我将此类用作参数,并在JAX-WS带注释的端点类上返回类型.
现在这给了我一个我可以打电话的网络服务.它使我能够更好地控制发送和返回的xml,但也可以自动完成写入完整wsdl所需的重复.
问题
在模式中,我有一个这样的元素:
<xs:element name="myElement" type="xs:string" nillable="true" minOccurs="0" />
Run Code Online (Sandbox Code Playgroud)
所以我想区分用户设置null或空白.然后生成的类具有此属性.
@XmlElementRef(name = "myElement", namespace = "/mynamespace", type = JAXBElement.class)
protected JAXBElement<String> myElement;
Run Code Online (Sandbox Code Playgroud)
这样做的结果是元素既不是可填充的也不是可选的.JAX-WS作为wsdl的一部分写入的模式已将元素设置为必需而不是nillable,如果我关闭模式验证,我仍然无法将nil传递给我的对象.
事情尝试
如果我将其更改为必需和可用,那么我得到这个生成的代码.
@XmlElement(required = true, nillable = true)
protected String myElement;
Run Code Online (Sandbox Code Playgroud)
如果我将其更改为可选而不是nillable,那么我将获得此生成的代码.
protected String myElement
Run Code Online (Sandbox Code Playgroud)
因此,如果您使用JAXB,您可以使用或不是两者.完全令人失望!
我也尝试手动将生成的类更改为这样.
@XmlElementRef(name = "myElement", namespace = "/mynamespace", type = JAXBElement.class, required=false)
protected JAXBElement<String> myElement;
Run Code Online (Sandbox Code Playgroud)
这现在使元素可选,但我仍然无法将其设置为nil.这样做会导致JAXBElement的值为空字符串.只有当你关闭模式验证时才会这样做,因为生成的JAX-WS wsdl/schema没有将元素设置为nillable,因此它不是有效的请求.
总结
我相信这是JAXB的一个错误.@XmlElementRef注释具有将其设置为不需要的属性,但没有将该字段设置为可空的属性.
@XmlElement注释具有必需和可空的属性,但这些只会导致null对象,因此无法区分xml中未包含的元素或包含但为null的元素.这就是您需要将@XmlElementRef与JAXBElement一起使用的原因.
我认为这个bug包含两个问题.首先,xjc命令应生成required = false的元素.其次,@ xmlElementRef应该有一个属性来设置元素是否可以为空,这也应该设置.
有谁知道修复/解决方法?我试过谷歌搜索但只发现人们在没有答案的情况下问同样的问题.这通常意味着它不可能...... TIA.
另外
我使用的是jaxb 2.2.6,而maven插件是jaxb2-maven-plugin 1.5.
bdo*_*han 13
对于
@XmlElementRef(name="foo", required=false)
protected JAXBElement<String> foo;
Run Code Online (Sandbox Code Playgroud)
文档中缺少的节点将对应于该字段为空.本文档中使用一个XML元素xsi:nil="true"将对应于值是的一个实例JAXBElement用的值null.
您还可以提供XML模式,而不是让JAXB使用location包级别@XmlSchema注释上的属性生成一个模式.
@XmlSchema(
...
location="http://www.example.com/schema/root.xsd")
package forum19665550;
import javax.xml.bind.annotation.XmlSchema;
Run Code Online (Sandbox Code Playgroud)
根
这是一个具有两个字段的对象,可以表示可选和可空数据.
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;
}
Run Code Online (Sandbox Code Playgroud)
的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);
}
}
Run Code Online (Sandbox Code Playgroud)
演示
下面的演示代码将调查foo和的值的差异bar.您可以使用JAXBIntrospector该类来获取实例的实际值JAXBElement.EclipseLink JAXB(MOXy)中存在一个与解组JAXBElement包装空值的实例相关的错误(请参阅: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);
}
}
Run Code Online (Sandbox Code Playgroud)
input.xml中/输出
在结果输出中,我们看到我们可以区分文档中缺少的元素和"xsi:nil ="true"的元素,并且结果值仍为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"/>
Run Code Online (Sandbox Code Playgroud)
GenerateSchema
下面是一些JAXB代码,它将从带注释的模型生成XML Schema.
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;
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
产量
这是生成的XML Schema.你是正确的,它并不表示foo和bar元素是可以为空的.
<?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>
Run Code Online (Sandbox Code Playgroud)
您可以指向包含更多信息的现有XML Schema,而不是让JAXB从您的模型中派生XML Schema.
包信息
这是通过location在包级别@XmlSchema注释上指定属性来完成的.
@XmlSchema(
...
location="http://www.example.com/schema/root.xsd")
package forum19665550;
import javax.xml.bind.annotation.XmlSchema;
Run Code Online (Sandbox Code Playgroud)
小智 5
您可以通过以下方式自定义绑定
<jaxb:globalBindings generateElementProperty="false" />
Run Code Online (Sandbox Code Playgroud)
如自定义绑定中所述,对于您所询问的完全相同的情况。
我正在使用 Maven 插件org.jvnet.jaxb2.maven2:maven-jaxb2-plugin 的自定义绑定