maven-jaxb2-plugin повторное использование обычных XSD в одном проекте

У меня есть проект, у которого есть схемы A и B, оба в одном пространстве имен. Оба импортируют схему C, которая также использует одно и то же пространство имен. Как я могу сгенерировать классы JAXB для A и B для разделения пакетов, повторно используя классы JAXB из C, сгенерированные в общий пакет?

Я уже знаю, что мне, вероятно, следует использовать эпизоды и использовать эпизод, сгенерированный для схемы C, в качестве файла привязки для раздельного выполнения схем A и B. Проблема в том, что я не знаю, как ссылаться на этот сгенерированный файл эпизода.

Вот пример:

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.12.3</version>
    <executions>
        <execution>
            <id>generate-sources-C</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <generatePackage>com.mymodel.commons</generatePackage>
                <generateDirectory>${project.build.directory}/generated-sources/xjc-commons</generateDirectory>
                <schemas>
                    <schema><url>src/main/resources/xsd/mymodel/c.xsd</url></schema>
                </schemas>
            </configuration>
        </execution>
        <execution>
            <id>generate-sources-A</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <generatePackage>com.mymodel.a</generatePackage>
                <schemas>
                    <schema><url>src/main/resources/xsd/mymodel/a.xsd</url></schema>
                </schemas>
            </configuration>
        </execution>
        <execution>
            <id>generate-sources-B</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <generatePackage>com.mymodel.b</generatePackage>
                <schemas>
                    <schema><url>src/main/resources/xsd/mymodel/b.xsd</url></schema>
                </schemas>
            </configuration>
        </execution>
    </executions>
</plugin>

Это приводит к созданию файла эпизода в:

target/generated-sources/xjc-commons/META-INF/sun-jaxb.episode

Как я могу ссылаться на этот файл эпизода / привязок при казнях для A и B? Использование эпизодов упоминает только то, как ссылаться на файл эпизода из других jar-зависимостей (или я просто не понял, что более вероятно).

Я видел более старый ответ, предлагающий передать его как параметр -b в XJC, но это, похоже, не сработало. что-нибудь для меня. Я все еще получаю один и тот же класс из C, сгенерированный три раза.


person Benny Bottema    schedule 04.05.2018    source источник


Ответы (1)


Отказ от ответственности: я являюсь автором maven-jaxb2-plugin.

TL; DR - это тестовый проект, демонстрирующий как это сделать.

Это возможно, но это немного непросто, так что, пожалуйста, потерпите меня.

Если a.xsd, b.xsd и c.xsd находятся в одном пространстве имен, a.xsd и b.xsd не могут импортировать c.xsd, они могут только включить его. Мы хотим сгенерировать каждый из XSD в отдельном пакете, например test.a, test.b и test.c, и сделать это в одном и том же проекте Maven.

Для этого нам потребуются три отдельных выполнения maven-jaxb2-plugin, каждое из которых настроено со своей собственной схемой и целевым пакетом. Например:

        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <executions>
                <execution>
                    <id>xjc-a</id>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                        <generatePackage>test.a</generatePackage>
                        <generateDirectory>${project.build.directory}/xjc-a</generateDirectory>
                        <schemaIncludes>
                            <includes>a.xsd</includes>
                        </schemaIncludes>
                    </configuration>
                </execution>
                <!-- xjc-b and xjc-c follow -->
            </executions>
        </plugin>

Важно использовать разные целевые каталоги для раздельного исполнения.

Хорошо, это создаст три целевых каталога с тремя целевыми пакетами. Следующая проблема заключается в том, что классы из c.xsd будут сгенерированы в test.a и test.b, чего мы хотим избежать.

Для этого мы должны указать XJC использовать классы из test.c для типов из c.xsd. Именно для этого и предназначен файл эпизода. Этот файл обычно создается под META-INF\sun-jaxb.episode и содержит привязки для всех типов в обрабатываемой схеме. Вот пример, созданный для c.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" if-exists="true" version="2.1">
  <bindings xmlns:tns="urn:test" if-exists="true" scd="x-schema::tns">
    <schemaBindings map="false">
      <package name="test.c"/>
    </schemaBindings>
    <bindings if-exists="true" scd="~tns:CType">
      <class ref="test.c.CType"/>
    </bindings>
  </bindings>
</bindings>

Файл эпизода - это на самом деле обычный файл привязок. Таким образом, вы можете напрямую использовать его при компиляции:

                <execution>
                    <id>xjc-a</id>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                        <generatePackage>test.a</generatePackage>
                        <generateDirectory>${project.build.directory}/xjc-a</generateDirectory>
                        <schemaIncludes>
                            <includes>a.xsd</includes>
                        </schemaIncludes>
                        <bindings>
                            <binding>
                                <fileset>
                                    <directory>${project.build.directory}/xjc-c/META-INF</directory>
                                    <includes>
                                        <include>sun-jaxb.episode</include>
                                    </includes>
                                </fileset>
                            </binding>
                        </bindings>
                    </configuration>
                </execution>

Осталась только одна крохотная проблема. Файлы эпизодов, сгенерированные XJC, также содержат этот фрагмент:

    <schemaBindings map="false">
      <!-- ... -->
    </schemaBindings>

Он фактически говорит: «не генерировать код для схемы в данном пространстве имен». Это не было бы проблемой, если бы a.xsd или b.xsd находились в другом пространстве имен. Но поскольку они находятся в одном пространстве имен, этот фрагмент фактически отключит генерацию кода для a.xsd или b.xsd.

Чтобы обойти это, мы можем постобработать sun-jaxb.episode, который был сгенерирован для c.xsd. Это можно сделать с помощью простого XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="jaxb:schemaBindings"/>
</xsl:stylesheet>

Этот XSLT следует запускать после кода для c.xsd, но до создания кода для a.xsd и b.xsd. Этого можно достичь, поместив эти исполнения в разные фазы (generate-sources, process-sources, generate-resources).


Ниже полный pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>divide</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.2.11</version>
        </dependency>
        <!-- JUnit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
            <version>4.12</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>xml-maven-plugin</artifactId>
                <version>1.0.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>transform</goal>
                        </goals>
                        <phase>process-sources</phase>
                    </execution>
                </executions>
                <configuration>
                    <transformationSets>
                        <transformationSet>
                            <dir>${project.build.directory}/xjc-c/META-INF</dir>
                            <outputDir>${project.build.directory}/xjc-c/META-INF</outputDir>
                            <includes>
                                <include>sun-jaxb.episode</include>
                            </includes>
                            <stylesheet>src/main/xslt/removeJaxbSchemaBindings.xslt</stylesheet>
                        </transformationSet>
                    </transformationSets>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.13.3</version>
                <executions>
                    <execution>
                        <id>xjc-c</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <generatePackage>test.c</generatePackage>
                            <generateDirectory>${project.build.directory}/xjc-c</generateDirectory>
                            <schemaIncludes>
                                <includes>c.xsd</includes>
                            </schemaIncludes>
                        </configuration>
                    </execution>
                    <execution>
                        <id>xjc-a</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <generatePackage>test.a</generatePackage>
                            <generateDirectory>${project.build.directory}/xjc-a</generateDirectory>
                            <schemaIncludes>
                                <includes>a.xsd</includes>
                            </schemaIncludes>
                            <bindings>
                                <binding>
                                    <fileset>
                                        <directory>${project.build.directory}/xjc-c/META-INF</directory>
                                        <includes>
                                            <include>sun-jaxb.episode</include>
                                        </includes>
                                    </fileset>
                                </binding>
                            </bindings>
                        </configuration>
                    </execution>
                    <execution>
                        <id>xjc-b</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <generatePackage>test.b</generatePackage>
                            <generateDirectory>${project.build.directory}/xjc-b</generateDirectory>
                            <schemaIncludes>
                                <includes>b.xsd</includes>
                            </schemaIncludes>
                            <bindings>
                                <binding>
                                    <fileset>
                                        <directory>${project.build.directory}/xjc-c/META-INF</directory>
                                        <includes>
                                            <include>sun-jaxb.episode</include>
                                        </includes>
                                    </fileset>
                                </binding>
                            </bindings>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
person lexicore    schedule 04.05.2018
comment
Я не ожидал этого. Думаю, я пытаюсь сделать что-то совершенно нестандартное. Большое вам спасибо за то, что изучили это. Думаю, вам тоже пришлось немного поиграться с этим, учитывая шаг XSLT: D - person Benny Bottema; 06.05.2018
comment
@BennyBottema Это необычно. Обычно это одно пространство имен - один пакет. Вам нужно одно пространство имен - три пакета. Если бы c.xsd имел собственное пространство имен, это было бы намного проще (без XSLT). - person lexicore; 06.05.2018
comment
Да, так и думал. К сожалению, я работаю с ограничениями набора устаревших систем, которые привязаны к этому шаблону пакета. Еще раз спасибо за прояснение этого вопроса! - person Benny Bottema; 06.05.2018
comment
По-видимому, это не работает, если схема входа представляет собой WSDL, который импортирует соответствующие XSD. Если я обращаюсь непосредственно к XSD, эта настройка работает. Я не уверен, нужен ли мне здесь WSDL, но есть ли способ обойти это? - person Benny Bottema; 07.05.2018
comment
@BennyBottema У меня нет большого опыта работы с WSDL. Наверное, да, привязки + каталоги обладают большой силой, но без экспериментов сложно сказать. - person lexicore; 07.05.2018
comment
Просто чтобы добавить, я думаю, что его потрясающий лексикон скрывается за stackoverflow и отвечает на эти вопросы jaxb ... Я бы отдал больше голосов, но у меня только один;). - person ; 14.12.2018
comment
Большое спасибо за этот ответ и за предоставление полного файла pom.xml. У меня была точно такая же проблема (кроме 11 (!) Схем вместо 2 включенных в общую схему). Один намек: для generateDirectory мне пришлось использовать $ {project.build.directory} / generated-sources / xjc-b вместо просто $ {project.build.directory} / xjc-b, чтобы сгенерированные исходники также были скомпилированы . - person stefitz; 23.01.2020