尝试使用JAXB库中的schemagen工具为我的项目生成模式时,我遇到一些问题。问题在于注释@XmlAttribute
没有被正确解析。
- src
- teste
- entity
因此,问题在于,对于某些类,schemagen任务会完全忽略
required
中的XmlAttribute
标志。我将在此处粘贴一些类和生成的模式的示例,以便您了解发生了什么
package teste.entity;
import javax.xml.bind.annotation.XmlAttribute;
public abstract class Class2 {
@XmlAttribute(required=false)
public String stringNotRequired;
@XmlAttribute(required=true)
public String stringRequired;
@XmlAttribute(required=false)
public int anotherIntNotRequired;
@XmlAttribute(required=true)
public int anotherIntRequired;
}
package teste.entity;
import javax.xml.bind.annotation.XmlAttribute;
public class Class1 extends Class2 {
@XmlAttribute(required=true)
public Integer integerRequired;
@XmlAttribute(required=false)
public Integer integerNotRequired;
@XmlAttribute(required=false)
public int intNotRequired;
@XmlAttribute(required=true)
public int intRequired;
public Class1() {
}
}
我的package-info.java
@XmlSchema(xmlns = @XmlNs(prefix = "t", namespaceURI = "http://test.com"),
namespace = "http://test.com",
elementFormDefault = XmlNsForm.UNQUALIFIED,
attributeFormDefault = XmlNsForm.UNQUALIFIED)
package teste.entity;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
当我运行
schemagen
任务时,得到以下输出:<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" version="1.0" targetNamespace="http://test.com" xmlns:t="http://test.com" xmlns:tns="http://test.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="class1">
<xs:complexContent>
<xs:extension base="tns:class2">
<xs:sequence/>
<xs:attribute name="integerRequired" type="xs:int" use="required"/>
<xs:attribute name="integerNotRequired" type="xs:int"/>
<xs:attribute name="intNotRequired" type="xs:int" use="required"/>
<xs:attribute name="intRequired" type="xs:int" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="class2" abstract="true">
<xs:sequence/>
<xs:attribute name="stringNotRequired" type="xs:string"/>
<xs:attribute name="stringRequired" type="xs:string" use="required"/>
<xs:attribute name="anotherIntNotRequired" type="xs:int" use="required"/>
<xs:attribute name="anotherIntRequired" type="xs:int" use="required"/>
</xs:complexType>
</xs:schema>
这是我的 Ant 任务
<target name="generate-schema" >
<path id="mycp">
<fileset dir="lib/jaxb/lib\">
<include name="*.jar"/>
</fileset>
<fileset dir="lib" >
<include name="*.jar"/>
</fileset>
<fileset dir="dist" >
<include name="*.jar"/>
</fileset>
</path>
<taskdef name="schemagen" classname="com.sun.tools.jxc.SchemaGenTask">
<classpath refid="mycp"/>
</taskdef>
<mkdir dir="schema"/>
<schemagen srcdir="src/teste/entity" destdir="schema" >
<classpath refid="mycp"/>
<schema namespace="http://test.com" file="full.xsd" />
</schemagen>
</target>
最佳答案
大概。我已经创建了一个与您相似的设置。Test.java
package test;
...
@XmlType(name = "test", namespace = "http://test.com", propOrder = "b")
@XmlRootElement(name = "test", namespace = "http://test.com")
public final class Test {
@XmlAttribute(required = false)
public String a;
@XmlElement
public String b;
public Test() {}
}
package-info.java
@XmlSchema(xmlns = @XmlNs(prefix = "tns", namespaceURI = "http://test.com"),
namespace = "http://test.com",
elementFormDefault = XmlNsForm.QUALIFIED,
attributeFormDefault = XmlNsForm.QUALIFIED)
package test;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
build.xml
(代码段,基于OP的输入)<schemagen srcdir="<path-to-test-package>" destdir=".">
<classpath refid="<classpath-refid>" />
<schema namespace="http://test.com" file="test.xsd" />
</schemagen>
test.xsd
(输出)<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema
attributeFormDefault="qualified"
elementFormDefault="qualified" version="1.0"
targetNamespace="http://test.com"
xmlns:tns="http://test.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="test" type="tns:test"/>
<xs:complexType name="test" final="extension restriction">
<xs:sequence>
<xs:element name="b" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute ref="tns:a"/>
</xs:complexType>
<xs:attribute name="a" type="xs:string"/>
</xs:schema>
(我使用了前缀
tns
,因为JAXB会生成并使用它而不是@XmlNs
中指定的任何前缀。)给定XJC的
SchemaGen
上方的文件会产生所需的结果-如果我具有必填属性,则将按此方式生成它;如果我设置required=false
,那么它不会。这里最主要的是
@XmlType
类上的Test
批注。如果您手工上课,那简直就是活不下去。 (不需要@XmlRootElement
,因此是否需要它取决于您的用例。)这告诉JAXB Test
处理SchemaGen
类(顺便表示模式类型)属于哪个 namespace 。package-info.java
的用途几乎相同,但在架构级别。如果程序包包含此文件(以及上面显示的注释)并且遇到SchemaGen
,则它将知道该程序包中的类(模式类型)属于程序包级别注释中指定的 namespace 。 (同样,如果您必须手工处理,则必须这样做。)除此之外,SchemaGen
使用此文件中声明的 namespace 将输出发送到<schema namespace="http://test.com" file="test.xsd" />
中指定的文件。没有它,生成的文件的名称将始终为schema1.xsd
(或类似名称)。多个包装
如果要将多个软件包中的多个类分组到一个命名空间中,则必须在所有软件包上应用相同的软件包级别注释(例如,在上面的
package-info.java
代码段中,由于存在以下原因,使用的命名空间前缀必须为tns
) (前面描述的JAXB限制)。当然,必须排序
schemagen
来编译这两个软件包。在build.xml
中,schemagen
任务的srcdir
应该包含两个软件包。如果您有与此类似的结构
.
|-- x
| |-- A.java # JAXB
| |-- B.java # POJO
| `-- package-info.java # http://test.com
`-- y
|-- C.java # JAXB
`-- package-info.java # http://test.com
您可以像这样告诉
schemagen
任务仅编译A
和C
<schemagen srcdir="." destdir="." >
<schema namespace="http://test.com" file="test.xsd" />
<include name="x/A.java" />
<include name="y/C.java" />
</schemagen>
可选和必填属性
在属性上有一个short section in the official JAXB tutorial,不幸的是,它并没有特别说明原始Java类型和XML Schema类型。
在我看来,您遇到的缺点不是JAXB缺陷,而是Java的怪异之处:原始类型不能为null,这同时有好有坏。
您可以通过更改原始属性来解决此问题
@XmlAttribute
public int attribute;
@XmlAttribute
public Integer attribute;
(我发现了mailing list thread regarding this same issue,也许您对此感兴趣。)