Java 生成实现接口的 JAXB 类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1271980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generating a JAXB class that implements an interface
提问by Alex Spurling
I'm currently using JAXB to generate java classes in order to unmarshall XML. Now I would like to create a new schema very similar to the first and have the classes that are generated implement the same interface.
我目前正在使用 JAXB 生成 java 类以解组 XML。现在我想创建一个与第一个非常相似的新模式,并让生成的类实现相同的接口。
Say for example, I have two schema files which define XML with similar tags:
例如,我有两个模式文件,它们定义了具有相似标签的 XML:
adult.xsd
成人.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
孩子.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>
Using JAXB and XJC I'd like to generate two class files:
使用 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 { ... }
}
where the Person interface defines the getName()
and getAge()
methods.
其中 Person 接口定义了getName()
和getAge()
方法。
I've looked at some of the documentationfor mapping interfaces but this appears to only be for the situation when you already have java classes that you want to map to a DOM.
我已经查看了一些关于映射接口的文档,但这似乎仅适用于您已经拥有要映射到 DOM 的 Java 类的情况。
Also, I've tried to use this external pluginbut it doesn't appear to work. Here is my xjb binding file:
另外,我尝试使用这个外部插件,但它似乎不起作用。这是我的 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>
but this gives the following error:
但这给出了以下错误:
$ 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.
Is it possible to generate a class with JAXB that implements an interface?
是否可以使用实现接口的 JAXB 生成类?
Update
更新
I've tried using the Interface Insertionplugin but for some reason can't get it to work. This is how I'm calling xjc yet it is as if the plugin jar is not getting picked up from the classpath:
我试过使用接口插入插件,但由于某种原因无法让它工作。这就是我调用 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
I get the error:
我收到错误:
unrecognized parameter -Xifins
Any ideas?
有任何想法吗?
采纳答案by Jim Hurne
Unfortunately, it looks like the interface-injection plugin mentioned in some of the other answers is no longer well-supported. In fact, I'm having trouble finding the JAR for download.
不幸的是,其他一些答案中提到的接口注入插件似乎不再得到很好的支持。事实上,我很难找到要下载的 JAR。
Thankfully, the JAXB2 Basics Pluginsprovides a similar mechanism for adding an interface to the generated JAXB stubs (see the Inheritance plugin).
幸运的是,JAXB2 Basics Plugins提供了一种类似的机制来向生成的 JAXB 存根添加接口(请参阅继承插件)。
The Inheritance plugin documentation has an example showing what the XML schema file might look like. However, since you cannot modify the schema, you can use an external bindings file instead:
继承插件文档有一个示例,展示了 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>
The JAXB2 Basics Plugins documentation includes instructions for using the plugin with Ant and Maven. You can also use it straight from the command line, but the command is a bit messy (due to the number of jars you have to add to the classpath):
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
The JAXB2 Basics Plugins provides a number of other utilities which you might also find useful (such as autogeneration of equals, hashCode, and toString methods).
JAXB2 Basics Plugins 提供了许多其他实用程序,您可能也会发现它们很有用(例如自动生成 equals、hashCode 和 toString 方法)。
回答by skaffman
An XJC plygin of some description is the answer to your problem, it's just a matter of finding one that works. The best source for them is here:
某种描述的 XJC plygin 是您问题的答案,这只是找到一个有效的问题。他们的最佳来源在这里:
https://jaxb2-commons.dev.java.net/
https://jaxb2-commons.dev.java.net/
In particular, this one:
特别是这个:
回答by Thimmayya
The documentation for the interface-insertion plugin suggests the the following
接口插入插件的文档建议如下
[ To call xjc with the Interface Insertion Plugin from the command line, you may write:
[ 要从命令行使用接口插入插件调用 xjc,您可以编写:
java -cp $JAXB_HOME/share/lib/xjc-if-ins.jar -extension -Xifins schema
]
]
I am guessing that you are calling the main method of the wrong class - com.sun.tools.xjc.XJCFacade. You should probably retry with the exact syntax.
我猜你正在调用错误类的主要方法 - com.sun.tools.xjc.XJCFacade。您可能应该使用确切的语法重试。
Here is a link on another forum which discusses a similar issue. http://forums.java.net/jive/message.jspa?messageID=220686
这是另一个论坛上讨论类似问题的链接。 http://forums.java.net/jive/message.jspa?messageID=220686
- I would have posted this as a comment, but I do not have enough points to comment.
- 我会将此作为评论发布,但我没有足够的积分来评论。
回答by Chris
It might be overkill for your situation, but I have done this using AspectJ (we were already using aspects on that project so we already had the dependency and the exposure).
对于您的情况,这可能有点矫枉过正,但我已经使用 AspectJ 完成了这项工作(我们已经在该项目中使用了方面,因此我们已经有了依赖和暴露)。
You'd declare an aspect along the lines of:
您将按照以下方式声明一个方面:
public aspect MyAspect
{
declare parents:
com.foo.generated.Adult
implements com.foo.Person;
declare parents:
com.foo.generated.Kid
implements com.foo.Person;
}
Which will add the interface com.foo.Person
to the classes com.foo.generated.Adult
and com.foo.generated.Kid
这会将接口添加com.foo.Person
到类com.foo.generated.Adult
和com.foo.generated.Kid
Might be overkill for your purpose, but it worked for us.
对你的目的来说可能有点矫枉过正,但它对我们有用。
回答by cfsh
In my case the command-line call via java -jar works:
在我的情况下,通过 java -jar 的命令行调用有效:
java -jar $somepath/jaxb-xjc.jar -classpath $somepath/xjc-if-ins.jar my.xsd -d $destdir -b $bindingconfig -p $desiredpackage -extension -Xifins
java -jar $somepath/jaxb-xjc.jar -classpath $somepath/xjc-if-ins.jar my.xsd -d $destdir -b $bindingconfig -p $desiredpackage -extension -Xifins
However when executing the xjc ant-task the error remains. The error message given is irritating as the real reason in my case is a bad version number in a class file ant tries to load (see stacktrace below). This correct error message only appears when you add the following to ANT_OPTS:
-Dcom.sun.tools.xjc.Options.findServices=true
但是,在执行 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
回答by user841942
For those who would like help building JAXB data binding files for more complex schema - the latest open source XML tool - CAM Editor v2.2 now supports this.
对于那些希望帮助为更复杂的模式构建 JAXB 数据绑定文件的人——最新的开源 XML 工具——CAM Editor v2.2 现在支持这一点。
You can access the resources and download site for the step by step guide and to see downloads section at page top for the tool.
您可以访问分步指南的资源和下载站点,并在页面顶部查看该工具的下载部分。
http://www.cameditor.org/#JAXB_Bindings
http://www.cameditor.org/#JAXB_Bindings
Enjoy.
享受。
回答by Alex Spurling
The answer that worked for me was Jim Hurne's example of using the JAXB2 Basics plugin. But the documentation he linked appears to be no longer available so for reference, this is how I configured the maven plugin:
对我有用的答案是 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>
回答by Malcolm Smith
It is possible to achieve this for this simple case without using a 3rd Party plugin using the JAXB RI Vendor Extensionsxjc:superInterface customization. It should be noted this approach will cause all generated classes to implement the interface.
对于这个简单的案例,可以使用JAXB RI Vendor Extensionsxjc:superInterface 自定义,在不使用 3rd Party 插件的情况下实现这一点。需要注意的是,这种方法会导致所有生成的类都实现该接口。
Example bindings file:
示例绑定文件:
<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>
You then just need to run xjcspecifying the binding file and setting the -extension flag. Much quicker/simpler than bringing in JAXB2Basics!
然后您只需要运行xjc指定绑定文件并设置 -extension 标志。比引入 JAXB2Basics 更快/更简单!
I was initially sceptical that this would work as the documentation states:
我最初怀疑这是否会如文档所述那样工作:
The customization allows you to specify the fully qualified name of the Java interface that is to be used as the root interface of all the generated interfaces. This customization has no effect unless you are specifically generating interfaces with the globalBindings generateValueClass="false" switch.
自定义允许您指定 Java 接口的完全限定名称,该名称将用作所有生成的接口的根接口。除非您使用 globalBindings generateValueClass="false" 开关专门生成接口,否则此自定义不会产生任何影响。
But when I tried it out with a bindings similar to the one above (without specifying generateValueClass="false", and generating classes, not interfaces), it gave me the output I required - all my generated classes implemented the common interface.
但是当我尝试使用类似于上面的绑定(没有指定 generateValueClass="false",并生成类,而不是接口)时,它给了我所需的输出 - 我生成的所有类都实现了公共接口。