JAXB - 在原始类型上忽略XmlAttribute中的'required'标记

时间:2012-01-04 19:40:04

标签: java jaxb xsd

我在尝试使用JAXB库中的schemagen工具为我的项目生成Schema时遇到了一些问题。问题是注释@XmlAttribute没有被正确解析。

- src
 - teste
  - entity

所以,问题是对于某些类,required中的标志XmlAttribute被schemagen任务完全忽略。

我将在这里粘贴一些类和生成的模式的示例,以便您可以了解正在发生的事情

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>

1 个答案:

答案 0 :(得分:8)

  

我是否需要对命名空间的类进行注释才能正确输出?

可能。我创建了一个类似于你的设置。

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处理它。

package-info.java提供几乎相同的目的,但是在架构级别。如果包中包含此文件(以及上面显示的注释)和SchemaGen遇到,则它会知道该包中的类(模式类型)属于包级别注释中指定的命名空间。 (同样,如果你手工完成这是必须的。)除此之外,SchemaGen使用此文件中声明的命名空间将输出发送到您在<schema namespace="http://test.com" file="test.xsd" />中指定的文件。没有它,生成的文件名称始终为schema1.xsd(或类似)。

多个包

如果要将位于多个包中的多个类组合到一个名称空间中,那么您必须在所有包上应用相同的包级别注释(例如{{ 1}}上面使用的名称空间前缀必须是package-info.java,因为前面描述了JAXB限制。

tns当然需要命令编译两个包。在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 任务只编译schemagenA这样

C

可选和必需的属性

有一个short section in the official JAXB tutorial个属性,遗憾的是,它们并没有特别说明原始Java类型和XML Schema类型。

在我看来,您遇到的缺点不是JAXB缺陷,而是Java 奇怪:原始类型不能为空,这是好的和坏的同时。

您可以通过更改原始属性

来解决此问题
<schemagen srcdir="." destdir="." >
  <schema namespace="http://test.com" file="test.xsd" />
  <include name="x/A.java" />
  <include name="y/C.java" />
</schemagen>

(我找到了一个mailing list thread regarding this same issue,也许您对此感兴趣。)