生成实现接口的JAXB类

Ale*_*ing 50 java xsd jaxb xjc jaxb2-basics

我目前正在使用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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

使用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 { ... }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

但是这会产生以下错误:

$ 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.
Run Code Online (Sandbox Code Playgroud)

是否可以使用实现接口的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
Run Code Online (Sandbox Code Playgroud)

我收到错误:

unrecognized parameter -Xifins
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Jim*_*rne 46

不幸的是,看起来在其他一些答案中提到的界面注入插件不再受到良好支持.事实上,我无法找到下载的JAR.

值得庆幸的是,JAXB2 Basics插件提供了一种类似的机制,用于向生成的JAXB存根添加接口(请参阅继承插件).

继承插件文档有一个示例,显示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>
Run Code Online (Sandbox Code Playgroud)

JAXB2 Basics插件文档包含有关使用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
Run Code Online (Sandbox Code Playgroud)

JAXB2 Basics插件提供了许多其他实用程序,您可能也会发现它们很有用(例如equals,hashCode和toString方法的自动生成).


小智 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;
}
Run Code Online (Sandbox Code Playgroud)

这将接口添加com.foo.Person到类com.foo.generated.Adultcom.foo.generated.Kid

可能会因你的目的而过度杀伤,但它对我们有用.


Ale*_*ing 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>
Run Code Online (Sandbox Code Playgroud)


Mal*_*ith 5

对于这个简单的情况,可以通过JAXB RI 供应商扩展xjc:superInterface 自定义来实现此目的,而无需使用第 3 方插件。应该注意的是,这种方法将导致所有生成的类都实现该接口。

绑定文件示例:

<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>
Run Code Online (Sandbox Code Playgroud)

然后,您只需运行xjc指定绑定文件并设置 -extension 标志。比引入 JAXB2Basics 更快/更简单!

我最初怀疑这是否有效,如文档所述:

自定义允许您指定要用作所有生成的接口的根接口的 Java 接口的完全限定名称。除非您专门使用 globalBindingsgenerateValueClass="false" 开关生成接口,否则此自定义无效。

但是,当我使用与上面类似的绑定进行尝试时(未指定generateValueClass =“false”,并生成类,而不是接口),它给了我所需的输出 - 我生成的所有类都实现了通用接口。

  • 这不是这个人所问的(通常也是大多数人想要的),因为正如您所说,这将使所有类实现相同的接口,而这在大多数情况下是无用的。 (4认同)
  • 是的,你是对的,所有生成的类都将实现该接口,正如我在答案的第二句中所述。有时这可能很有用,很容易实现,并且是OP所要求的。好的? (2认同)