#java #xsd #jaxb
#java — язык #xsd #jaxb #java
Вопрос:
У меня есть 2 служебных XSD-файла AService.xsd и BService.xsd, каждый с разным пространством имен целей. Оба они используют общий XSD, называемый common.xsd. Я использую плагин JAXB Maven для генерации классов. Вот как,
<execution>
<id>generate-package</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<extension>true</extension>
<schemaIncludes>
<include>schema/Aservice.xsd</include>
<include>schema/Bservice.xsd</include>
</schemaIncludes>
<bindingIncludes>
<include>schema/*.xjb</include>
</bindingIncludes>
<generatePackage>com.schema</generatePackage>
<generateDirectory>src/main/java</generateDirectory>
</configuration>
</execution>
Когда я пытаюсь запустить это, я получаю следующую ошибку. ValidationType
определяется в common.xsd
org.xml.sax.SAXParseException: A class/interface with the same name "com.schema.ValidationType" is already in use. Use a class customization to resolve this conflict.
..........
org.xml.sax.SAXParseException: (Relevant to above error) another "ValidationType" is generated from here.
......
com.sun.istack.SAXParseException2: Two declarations cause a collision in the ObjectFactory class.
Если я запускаю 2 служебных xsd в двух разных исполнениях, генерирующих в 2 разных пакетах, я получаю один и тот же ValidationType
класс в 2 разных пакетах.
Есть какие-нибудь идеи о том, как заставить JAXB распознавать общие схемы?
Ответ №1:
Вы сталкиваетесь с так называемой «схемой хамелеона», которая считается плохой практикой. К сожалению, хорошего решения не существует из-за природы JAXB. Аннотация JAXB привязывает свойства компонента к элементам XML и атрибутам в определенных пространствах имен (определяется во время компиляции схемы). Итак, как только ваша схема скомпилирована, нет официального хорошего способа изменить пространства имен элементов и атрибутов, к которым привязаны ваши свойства.
Однако это именно то, чего вы хотите достичь с помощью схем «хамелеон». Классы, производные от «common.xsd», должны каким-то волшебным образом отображаться в пространство имен A, если используются в классах A, и в пространство имен B, если используются в классах B. Я могу представить эту магию, но никогда не видел в реальной жизни.
Поскольку вы, по сути, хотите, чтобы A / common и B / common были «одним и тем же», один из способов решить эту проблему — сгенерировать A и B (оба с помощью common) в двух исполнениях и заставить общие классы реализовать определенный «общий» интерфейс. Тогда ваше программное обеспечение могло бы обрабатывать A / common и B / common одним и тем же способом, независимо от того факта, что на самом деле это классы из разных пакетов.
Обновить:
Из комментария я вижу, что у вас нет схемы chameleon, а просто обычный импорт. Тогда это просто, просто скомпилируйте common, A и B отдельно. Смотрите Отдельную компиляцию схемы для maven-jaxb2-plugin.
Комментарии:
1. Common.xsd находится в своем собственном пространстве имен и импортируется в то же пространство имен в AService.xsd и BService.xsd. Нет необходимости изменять пространства имен после генерации..
2. Ваш подход тоже сработает, я сам добавил ответ, описывающий, как я пришел к решению. Спасибо за ответ.
Ответ №2:
Я настроил пакеты, как описано здесь. So common.xsd
входит com.common.schema
и совместно используется AService.xsd
и BService.xsd
, которые сами находятся в разных пакетах, поскольку они находятся в разных пространствах имен.
generatePackage
Удален из конфигурации maven и выглядит следующим образом,
<execution>
<id>generate-package</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<extension>true</extension>
<schemaIncludes>
<include>schema/Aservice.xsd</include>
<include>schema/Bservice.xsd</include>
</schemaIncludes>
<bindingIncludes>
<include>schema/*.xjb</include>
</bindingIncludes>
<generateDirectory>src/main/java</generateDirectory>
</configuration>
</execution>