Подтвердить что ты не робот

Создание класса JAXB, который реализует интерфейс

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

Скажем, например, у меня есть два файла схемы, которые определяют XML с похожими тегами:

adult.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:element name="Person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Name" type="xs:string" />
      <xs:element name="Age" type="xs:integer" />
      <xs:element name="Job" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

kid.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:element name="Person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Name" type="xs:string" />
      <xs:element name="Age" type="xs:integer" />
      <xs:element name="School" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

Используя JAXB и XJC, я хотел бы сгенерировать два файла класса:

public class Adult implements Person {
    ...
    public String getName() { ... }
    public int getAge() { ... }
    public String getJob { ... }
}

public class Kid implements Person {
    ...
    public String getName() { ... }
    public int getAge() { ... }
    public String getSchool { ... }
}

где интерфейс Person определяет методы getName() и getAge().

Я просмотрел некоторые из документации для сопоставления интерфейсов, но это, по-видимому, относится только к ситуации, когда у вас уже есть классы Java, которые вы хотите сопоставить DOM.

Кроме того, я пытался использовать этот внешний плагин, но он не работает. Вот мой файл привязки xjb:

<jxb:bindings version="1.0" 
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
  xmlns:ext="http://xml.w-wins.com/xjc-plugins/interfaces"
  jxb:extensionBindingPrefixes="xjc">

    <jxb:bindings schemaLocation="xsd/adult.xsd" node="xs:schema/xs:complexType[@name='Person']">
        <ext:interface>mypackage.Hello</ext:interface> 
    </jxb:bindings>

</jxb:bindings>

но это дает следующую ошибку:

$ java -cp "lib/activation.jar;lib/InterfacesXJCPlugin.jar;lib/jaxb1-impl.jar;lib/jaxb-api.jar;lib/jaxb-xjc.jar;lib/jsr173_1.0_api.jar" com.sun.tools.xjc.XJCFacade -p mypackage.myxml -extension -Xinterfaces xsd/adult.xsd -b binding.xjb
parsing a schema...
[ERROR] XPath evaluation of "xs:schema/xs:complexType[@name='Person']" results in empty target node
  line 8 of file:/C:/dev/jaxb/jaxb-ri/binding.xjb

Failed to parse a schema.

Можно ли создать класс с JAXB, который реализует интерфейс?

Обновление

Я пробовал использовать плагин Interface Insertion, но по какой-то причине он не может заставить его работать. Это то, как я вызываю xjc, но это похоже на то, что плагин-плагин не получает из класса pathpath:

$ java -cp "lib/xjc-if-ins.jar;lib/jaxb-xjc.jar" com.sun.tools.xjc.XJCFacade -p mypackage -extension -Xifins myschema.xsd -b binding.xjb

Я получаю сообщение об ошибке:

unrecognized parameter -Xifins

Любые идеи?

4b9b3361

Ответ 1

К сожалению, похоже, что плагин внедрения интерфейса, упомянутый в некоторых других ответах, больше не поддерживается. На самом деле у меня проблемы с поиском JAR для загрузки.

К счастью, JAXB2 Basics Plugins предоставляет аналогичный механизм для добавления интерфейса к сгенерированным заглушкам JAXB (см. Плагин наследования).

В документации плагина Inheritance есть пример, показывающий, как может выглядеть файл схемы XML. Однако, поскольку вы не можете изменить схему, вместо этого вы можете использовать файл внешних привязок:

<?xml version="1.0"?>
<jxb:bindings version="1.0" 
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
  xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
  jxb:extensionBindingPrefixes="xjc">

    <jxb:bindings schemaLocation="xsd/adult.xsd">
      <jxb:bindings node="//xs:complexType[@name='Person']">
        <inheritance:implements>mypackage.Hello</inheritance:implements> 
      </jxb:bindings>
    </jxb:bindings>

</jxb:bindings>

Документация по плагинов JAXB2 Basics включает инструкции по использованию плагина с Ant и Maven. Вы также можете использовать его прямо из командной строки, но команда немного запутана (из-за количества банок, которые вы должны добавить в путь к классам):

java -jar jaxb-xjc.jar 
     -classpath jaxb2-basics-0.5.3.jar,jaxb2-basics-runtime-0.5.3.jar,
                jaxb2-basics-tools-0.5.3.jar,commons-beanutils-0.5.3.jar,
                commons-lang.jar,commons-logging.jar
     -p mypackage.myxml -extension -Xinheritance xsd/adult.xsd -b binding.xjb

JAXB2 Basics Plugins предоставляет ряд других утилит, которые вы также можете найти полезными (например, автогенерация методов equals, hashCode и toString).

Ответ 2

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

Вы бы объявили аспект в соответствии с:

public aspect MyAspect
{
    declare parents: 
        com.foo.generated.Adult
    implements com.foo.Person;

    declare parents: 
        com.foo.generated.Kid
    implements com.foo.Person;
}

Что добавит интерфейс com.foo.Person к классам com.foo.generated.Adult и com.foo.generated.Kid

Может быть, излишним для вашей цели, но это сработало для нас.

Ответ 3

Ответ, который работал у меня, - это пример использования JAXB2 Basics. Но связанная с ним документация больше не доступна, поэтому для справки, вот как я настроил плагин maven:

        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <version>0.8.2</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    </execution>
            </executions>
            <configuration>
                <extension>true</extension>
                <args>
                    <arg>-Xinheritance</arg>
                </args>
                <bindingDirectory>src/main/resources/xjb</bindingDirectory>
                <bindingIncludes>
                    <include>**.xml</include> <!-- This Should reference the binding files you use to configure the inheritance -->
                </bindingIncludes>
                <schemaDirectory>src/main/resources/xsd</schemaDirectory>
                <generateDirectory>${project.build.directory}/generated-sources/jaxb</generateDirectory>
                <generatePackage>mypackage</generatePackage>
                <plugins>
                    <plugin>
                        <groupId>org.jvnet.jaxb2_commons</groupId>
                        <artifactId>jaxb2-basics</artifactId>
                        <version>0.5.3</version>
                    </plugin>
                </plugins>
            </configuration>
        </plugin>

Ответ 4

Это можно сделать для этого простого случая без использования плагина третьей стороны, используя JAXB RI Vendor Extensions xjc: настройка суперинтерфейса. Следует отметить, что этот подход заставит все созданные классы реализовать интерфейс.

Пример файла привязок:

<jxb:bindings version="1.0" 
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
  jxb:extensionBindingPrefixes="xjc">
    <jxb:bindings schemaLocation="adult.xsd" node="/xs:schema">
    <jxb:globalBindings>
        <xjc:superInterface name="com.example.model.Person"/>
    </jxb:globalBindings>
    </jxb:bindings>
</jxb:bindings>

Вам просто нужно запустить xjc, указав файл привязки и установив флаг -extension. Гораздо быстрее/проще, чем приносить JAXB2Basics!

Я был скептически настроен, что это будет работать, поскольку документация гласит:

Настройка позволяет указать полное имя интерфейса Java, которое должно использоваться как корневой интерфейс всех созданных интерфейсов. Эта настройка не имеет эффекта, если вы специально не генерируете интерфейсы с помощью globalBindings generateValueclass= "false".

Но когда я попробовал это с привязками, подобными приведенному выше (без указания generateValueclass= "false" и генерации классов, а не интерфейсов), он дал мне требуемый результат - все мои сгенерированные классы реализовали общий интерфейс,

Ответ 5

В моем случае вызов командной строки через java -jar работает:

java -jar $somepath/jaxb-xjc.jar -classpath $somepath/xjc-if-ins.jar my.xsd -d $destdir -b $bindingconfig -p $desiredpackage -extension -Xifins

Однако при выполнении xjc ant -task ошибка остается. Сообщение об ошибке является раздражающим, поскольку в моем случае реальная причина - это неправильный номер версии в файле класса ant, который пытается загрузить (см. Таблицу ниже). Это правильное сообщение об ошибке появляется только при добавлении в ANT_OPTS следующего содержания: -Dcom.sun.tools.xjc.Options.findServices=true

[xjc] java.lang.UnsupportedClassVersionError: Bad version number in .class file
[xjc]     at java.lang.ClassLoader.defineClass1(Native Method)
[xjc]     at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
[xjc]     at org.apache.tools.ant.AntClassLoader.defineClassFromData(AntClassLoader.java:1134)
[xjc]     at org.apache.tools.ant.AntClassLoader.getClassFromStream(AntClassLoader.java:1320)
[xjc]     at org.apache.tools.ant.AntClassLoader.findClassInComponents(AntClassLoader.java:1376)
[xjc]     at org.apache.tools.ant.AntClassLoader.findClass(AntClassLoader.java:1336)
[xjc]     at org.apache.tools.ant.AntClassLoader.loadClass(AntClassLoader.java:1074)
[xjc]     at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
[xjc]     at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
[xjc]     at com.sun.tools.xjc.Options.findServices(Options.java:936)
[xjc]     at com.sun.tools.xjc.Options.getAllPlugins(Options.java:336)
[xjc]     at com.sun.tools.xjc.Options.parseArgument(Options.java:632)
[xjc]     at com.sun.tools.xjc.Options.parseArguments(Options.java:742)
[xjc]     at com.sun.tools.xjc.XJC2Task._doXJC(XJC2Task.java:444)
[xjc]     at com.sun.tools.xjc.XJC2Task.doXJC(XJC2Task.java:434)
[xjc]     at com.sun.tools.xjc.XJC2Task.execute(XJC2Task.java:369)
[xjc]     at com.sun.istack.tools.ProtectedTask.execute(ProtectedTask.java:55)
[xjc]     at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
[xjc]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[xjc]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[xjc]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[xjc]     at java.lang.reflect.Method.invoke(Method.java:585)
[xjc]     at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
[xjc]     at org.apache.tools.ant.Task.perform(Task.java:348)
[xjc]     at org.apache.tools.ant.Target.execute(Target.java:390)
[xjc]     at org.apache.tools.ant.Target.performTasks(Target.java:411)
[xjc]     at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1360)
[xjc]     at org.apache.tools.ant.Project.executeTarget(Project.java:1329)
[xjc]     at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[xjc]     at org.apache.tools.ant.Project.executeTargets(Project.java:1212)
[xjc]     at org.apache.tools.ant.Main.runBuild(Main.java:801)
[xjc]     at org.apache.tools.ant.Main.startAnt(Main.java:218)
[xjc]     at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
[xjc]     at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)
[xjc]
[xjc] failure in the XJC task. Use the Ant -verbose switch for more details

Ответ 6

Документация для плагина для вставки интерфейса предлагает следующее

[ Чтобы вызвать xjc с плагином вставки интерфейса из командной строки, вы можете написать:

java -cp $JAXB_HOME/share/lib/xjc-if-ins.jar -extension -Xifins schema

]

Я предполагаю, что вы вызываете основной метод неправильного класса - com.sun.tools.xjc.XJCFacade. Вероятно, вы должны повторить попытку с точным синтаксисом.

Вот ссылка на другой форум, в котором обсуждается аналогичная проблема. http://forums.java.net/jive/message.jspa?messageID=220686

  • Я бы разместил это как комментарий, но у меня недостаточно комментариев для комментариев.

Ответ 7

Что делать, если вы извлекаете тип в обычный XSD, импортированный в adult.xsd и kid.xsd? Или у вас есть существующий интерфейс, который вам нужно реализовать?

Ответ 8

Для тех, кто хотел бы помочь создать файлы привязки данных JAXB для более сложной схемы - новейшего инструмента XML с открытым исходным кодом - CAM Editor v2.2 теперь поддерживает это.

Вы можете получить доступ к ресурсам и загрузить сайт для пошагового руководства и просмотреть раздел загрузки на странице вверх для инструмента.

http://www.cameditor.org/#JAXB_Bindings

Enjoy.