Файл привязки JAXB: XmlAdapters и имя пакета

У меня есть такой файл привязки

<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <jxb:bindings schemaLocation="example.xsd" node="/xs:schema">
    <jxb:schemaBindings>
        <jxb:package name="example" />
    </jxb:schemaBindings>
    <jxb:globalBindings>
        <jxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
            printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
        <jxb:javaType name="java.util.Calendar" xmlType="xs:date"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
            printMethod="javax.xml.bind.DatatypeConverter.printDate" />
        <jxb:javaType name="java.util.Calendar" xmlType="xs:time"
            parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
            printMethod="javax.xml.bind.DatatypeConverter.printTime" />
    </jxb:globalBindings>

  </jxb:bindings>
</jxb:bindings>

Класс схемы генерируется в "примере" (правильно), но XmlAdapters в "org.w3._2001.xmlschema" (неправильно). Как я могу это исправить?

5 ответов

Решение

У меня тоже была эта проблема, я решил ее.

Для пользователей Apache CXF самым чистым способом является использование -p вариант, предлагаемый wsdl2java,

-p [wsdl-namespace=]PackageName

Задает ноль или более имен пакетов для использования в сгенерированном коде. Опционально указывает пространство имен WSDL для сопоставления имен пакетов.

В нашем случае

-p http://www.w3.org/2001/XMLSchema=org.acme.foo

Если вы используете плагин cxf-codegen-plugin, просто добавьте еще одну пару <extraarg>,

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
        [...]
    <extraarg>-p</extraarg>
    <extraarg>http://www.w3.org/2001/XMLSchema=org.acme.foo</extraarg>
        [...]
</plugin>

Нет необходимости в targetNamespace, указывающем на зарезервированное пространство имен XSD, и нет необходимости связывать все пакеты jaxb.

Лучший способ использовать GlobalBinding - это указать явный адаптер вместо использования этой пары синтаксический анализ / печать. Например, вместо следующего:

<jaxb:javaType name="java.lang.Long" xmlType="xs:long"
                      parseMethod="com.mypackage.myclass.parseLong"
                  printMethod="com.mypackage.myclass.print"/>

Вместо этого вы должны:

<xjc:javaType name="java.lang.Long" xmlType="xs:long"
                  adapter="com.mypackage.LongAdapter"/>

Не забудьте добавить пространство имен для xjc:

xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
          jxb:extensionBindingPrefixes="xjc"

Класс LongAdapter будет выглядеть так:

public class LongAdapter
extends XmlAdapter<String, Long>
{


public Long unmarshal(String value) {
    return your_util_class.parseLong(value);
}

public String marshal(Long value) {
    return your_util_class.print(value);
}

}

Таким образом, поскольку вы явно указали классы адаптеров, jaxb не будет генерировать адаптеры по умолчанию с именем пакета по умолчанию org.w3._2001.xmlschema.

Очень важно избегать использования имени пакета по умолчанию org.w3._2001.xmlschema. Возьмем один пример, если у вас есть один проект A и один проект B, и у них обоих есть некоторые схемы и привязки. По старинке оба они генерируют адаптеры с одинаковыми полными именами, например, org.w3._2001.xmlschema.Adapter1. Тем не менее, этот адаптер может быть для Long в проекте A и для Integer в проекте B. Тогда, скажем, у вас есть нижестоящий проект C, использующий как A, так и B. Теперь проблема становится неприятной. Если C необходимо использовать Adapter1, вы не можете предсказать, что использованный адаптер - от A для Long или от B для Integer. Тогда ваше приложение C может нормально работать через какое-то время, но может не получиться странным образом в некоторых других ситуациях. Если это произойдет, исключение типа будет выглядеть так:

org.w3._2001.xmlschema.Adapter1 is not applicable to the field type java.lang.Double...

Решение, упомянутое Roy Truelove, кажется, не работает, когда я попробовал его в своей среде с помощью maven-jaxb2-plugin, даже если теория верна.

org.w3._2001.xmlschema пакет создается здесь, потому что XJC должен генерировать класс, который расширяет javax.xml.bind.annotation.adapters.XmlAdapter, который в свою очередь вызывает ваши синтаксические разбор / печать статических методов. По какой-то причине он помещает их в этот пакет, а не куда-то более полезный.

Вы не сказали, какую реализацию JAXB вы используете, но RI JAXB имеет расширение к javaType настройка привязки, которая позволяет указать подкласс XmlAdapter напрямую, а не parseMethod/printMethod пар. Это устраняет необходимость генерировать синтетические XmlAdapter бридж класс. Посмотрите документы RI для того, как это сделать.

Я предполагаю, что EclipseLink/Moxy имеет что-то похожее на это, но я не уверен, способен ли XJC, который поставляется с Java6, на это (Sun, кажется, удалил половину полезных вещей из RI, когда они принесли его в JRE),

Используйте встроенные конвертеры для распространенных типов данных.

<jxb:javaType name="java.lang.Integer" xmlType="xs:integer"              
parseMethod="javax.xml.bind.DatatypeConverter.parseInt"                  
printMethod="javax.xml.bind.DatatypeConverter.printInt" />
Другие вопросы по тегам