JAXB - флаг 'обязательный' из XmlAttribute игнорируется на примитивных типах - PullRequest
10 голосов
/ 04 января 2012

У меня возникла проблема при попытке использовать инструмент schemagen из библиотеки JAXB для генерации схемы для моего проекта. Проблема в том, что аннотация @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() {
    }
}

Мой пакет-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>

Вот моя Задача Муравья

<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 Ответ

8 голосов
/ 05 января 2012

Нужны ли аннотации к классам для пространства имен, чтобы получить вывод правильно?

Возможно.Я создал настройку, аналогичную вашей.

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.)

Учитывая файлы выше SchemaGen XJC, дает желаемые результаты - если у меня есть обязательный атрибут, то он будет сгенерирован как таковой;если я установлю required=false, то не будет.

Главное здесь - аннотация @XmlType для класса Test.Вы просто не можете жить без этого, если вы создаете свои классы вручную.(@XmlRootElement не является обязательным, поэтому зависит от вашего варианта использования, хотите вы этого или нет.) Это сообщает JAXB, какое пространство имен делает класс Test (который представляет схему типа путь) принадлежит, когда SchemaGen обрабатывает его.

package-info.java служит почти той же цели, но на уровне схема .Если пакет содержит этот файл (и аннотации, показанные выше) и встречается SchemaGen, то он будет знать, что классы (типы схем) в этом пакете принадлежат пространству имен, указанному в аннотациях уровня пакета.(Опять же, если вы делаете что-то вручную, это обязательно.) Кроме этого, SchemaGen использует пространство имен, объявленное в этом файле, для отправки вывода в файл, указанный вами в <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>

Необязательные и обязательные атрибуты

В официальном руководстве JAXB есть короткий раздел *1081* по атрибутам, которыйк сожалению, ничего не говорится о примитивных типах Java и, в частности, типах XML-схем.

Недостаток, который вы испытываете, на мой взгляд, не является дефектом JAXB, скорее это явление Java oddity : примитивные типы не могут быть нулевыми, что хорошо и плохо одновременно.

Вы можете решить эту проблему, изменив свой атрибут примитива

@XmlAttribute
public int attribute;

@XmlAttribute
public Integer attribute;

(у меня естьнашла ветку списка рассылки , касающуюся этой же проблемы , может быть, она вам интересна.)

...