55

我目前正在使用 JAXB 生成 java 类以解组 XML。现在我想创建一个与第一个非常相似的新模式,并让生成的类实现相同的接口。

例如,我有两个模式文件,它们定义了具有相似标签的 XML:

成人.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>

孩子.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()方法。

我查看了一些有关映射接口的文档,但这似乎仅适用于您已经拥有要映射到 DOM 的 java 类的情况。

另外,我尝试使用这个外部插件,但它似乎不起作用。这是我的 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 的方式,但好像插件 jar 没有从类路径中获取:

$ 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

有任何想法吗?

4

7 回答 7

53

不幸的是,其他一些答案中提到的接口注入插件似乎不再得到很好的支持。事实上,我很难找到要下载的 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 Plugins 文档包含将插件与 Ant 和 Maven 一起使用的说明。您也可以直接从命令行使用它,但是命令有点混乱(由于您必须添加到类路径中的 jar 数量):

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 方法)。

于 2011-02-13T12:06:29.560 回答
8

对于您的情况,这可能有点过头了,但我已经使用 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.Adultcom.foo.generated.Kid

对于您的目的来说可能有点矫枉过正,但它对我们有用。

于 2009-08-18T01:24:34.807 回答
5

对我有用的答案是 Jim Hurne 的使用 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>
于 2012-10-18T13:05:35.060 回答
3

对于这个简单的案例,可以通过JAXB RI Vendor Extensions xjc:superInterface 自定义来实现这一点,而无需使用 3rd Party 插件。需要注意的是,这种方法会导致所有生成的类都实现接口。

示例绑定文件:

<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",并生成类,而不是接口),它给了我所需的输出 - 我生成的所有类都实现了公共接口。

于 2012-10-26T13:03:32.557 回答
1

在我的情况下,通过 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
于 2010-08-18T12:41:38.310 回答
0

interface-insertion 插件的文档建议如下

[ 要从命令行使用接口插入插件调用 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

  • 我会将此作为评论发布,但我没有足够的评论点。
于 2009-08-18T01:11:03.273 回答
-3

某种描述的 XJC plygin 是您问题的答案,这只是找到一个有效的问题。他们的最佳来源在这里:

https://jaxb2-commons.dev.java.net/

特别是这个:

https://jaxb2-commons.dev.java.net/interface-insertion/

于 2009-08-13T13:38:05.330 回答