У меня есть этот API с помощью JAXB, чтобы удобно использовать объектные модели, созданные из XML-схем компилятором XJC (XML-to-Java), через именованные ссылки. Он абстрагирует создание контекстов JAXB и отыскивает методы ObjectFactory всеми видами фоновой магии и отражения. Основная его суть состоит в том, что вы всегда определяете одну общую схему, а затем любое число (также может быть 0) схем, "расширяющих", общее, каждое из которых приводит к своей собственной модели данных. Общая схема содержит многоразовые определения, те, которые расширяют ее, используют их для составления собственных моделей.
Теперь я столкнулся с ситуацией, когда я хотел бы повторно использовать общую схему для нескольких проектов. Общие определения типов должны оставаться одинаковыми для всех проектов, и некоторый код будет создан против абстрактных классов, генерируемых из них. Поэтому мне нужно будет сначала генерировать классы для некоторой общей схемы, а затем генерировать те, которые распространяются и используются отдельно. Я использую Maven для моего процесса сборки.
Проблема, с которой я сталкиваюсь, заключается в разрешении определений типов из этой общей схемы в расширяющих схемах.
Предположим, что моя общая схема называется "general.xsd" и выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/general"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<!-- Element (will usually be root) -->
<xs:element name="transmission" type="gen:Transmission" />
<!-- Definition -->
<xs:complexType name="Transmission" abstract="true">
<xs:sequence>
<!-- Generic parts of a transmission would be in here... -->
</xs:sequence>
</xs:complexType>
</xs:schema>
Рядом с ним есть файл привязок, который выполняет некоторую настройку именования и устанавливает имя пакета для вывода:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for the general schema -->
<bindings schemaLocation="general.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.general"/>
</schemaBindings>
<bindings node="//xs:complexType[@name='Transmission']">
<!-- Some customization of property names here... -->
</bindings>
</bindings>
Тогда у меня будет следующий бит в POM этого проекта для генерации классов Java:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>true</episode>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
Как вы можете видеть, я использую плагин Maven JAXB2.1. Я установил вариант создания файла эпизода, созданного для пошаговой компиляции. Опция удаления предыдущего вывода была связана с обходом ошибки; все, что он делает, это убедиться, что все сначала очищено, поэтому перекомпиляция принудительно.
Пока все хорошо. Этот проект компилируется без сучка и задоринки. Следует отметить, что помимо генерируемых Java-классов я также упаковываю схемы в полученный файл jar. Таким образом, они доступны на пути к классам! Файл sun-jaxb.episode
находится в META-INF, как и должно быть.
Затем я начинаю с проекта, который использует схемы, которые будут расширять вышесказанное, сначала импортируя его. Один из "подтипов" может выглядеть так (я назову его sub.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/sub"
xmlns:sub="http://www.foobar.com/sub"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xs:import namespace="http://www.foobar.com/general" />
<!-- Definition -->
<xs:complexType name="SubTransmission">
<xs:complexContent>
<xs:extension base="gen:Transmission">
<xs:sequence>
<!-- Additional elements placed here... -->
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Опять же, есть файл привязок:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for sub type -->
<bindings schemaLocation="sub.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.sub"/>
</schemaBindings>
</bindings>
</bindings>
И вот бит из POM этого проекта, который заботится о генерации XJC:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>false</episode>
<catalog>${basedir}/src/main/resources/com/foobar/schemas/catalog.cat</catalog>
<episodes>
<episode>
<groupId>com.foobar</groupId>
<artifactId>foobar-general-models</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</episode>
</episodes>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
Первоначально все схемы были в одной папке, и у меня был атрибут schemaLocation
в наборе импорта general.xsd
, который работал нормально. Но теперь, когда вещи разделены между проектами, я сталкиваюсь с проблемами. Первая проблема заключалась в том, что другая схема не найдена. Я решил это, взяв атрибут schemaLocation
из элемента <xs:import />
, сохраняя только атрибут namespace
и добавляя файл каталога (catalog.cat
), который вы можете увидеть, упомянутый в приведенном выше извлечении POM. Его содержание:
PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"
Это похоже на работу, поскольку я больше не получаю сообщение об ошибке, указывающее, что схема не найдена. Но по какой-то причине разрешение фактических определений типов из импортированной схемы продолжает терпеть неудачу. Здесь исключение:
Error while parsing schema(s).Location [ file:/C:/NetBeans_groups/Test/SubModelBundle/src/main/resources/com/foobar/schemas/sub.xsd{...,...}].
org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'gen:Transmission' to a(n) 'type definition' component.
Вот что я пробовал до сих пор:
- Используйте файл каталога. Частично успешно, так как теперь можно найти импортированную схему.
- Попросите компиляцию для общей схемы создать файл эпизода и использовать его для компиляции подсхемы. Кажется, не имеет значения, хотя это должно играть только роль, когда тип был разрешен, поэтому я не думаю, что это еще важно.
- Используйте другую JAXP (примечание: не JAXB, JAXP). Он использовал другой, потому что я видел это в трассе стека исключений, но конечный результат тот же.
- Используйте
maven-jaxb22-plugin
вместо 21. Без разницы.
Оглядываясь в Интернете, кажется, что люди сталкиваются с этой проблемой с 2006 года, и это может быть связано с некоторыми проблемами с резольвером Xerces. Я надеюсь, что это не какая-то ошибка, которая скрывалась в течение 6 лет, и никто не заботился об этом. Есть ли у кого-то другие предложения? Может, кто-то столкнулся с той же проблемой и нашел решение? Единственным обходным решением, которое я могу придумать, является использование "svn: externals", чтобы перетащить общую схему в суб-проект и просто восстановить там классы, но он грязный и будет работать только тогда, когда вы сможете подключиться к нашему реестру svn.
Большое спасибо заранее за прочтение этого длинного сообщения. Имейте в виду, что я взял все вышеперечисленное из существующих проектов и заменил некоторые пространства имен и другие вещи для анонимности, поэтому возможны опечатки.