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.
Say for example, I have two schema files which define XML with similar tags:
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>
Using JAXB and XJC I'd like to generate two class files:
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.
I've looked at some of the documentation for 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.
Also, I've tried to use this external plugin but it doesn't appear to work. Here is my xjb binding 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"
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?
Update
I've tried using the Interface Insertion plugin 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:
$ 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?
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.
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
Enjoy.
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.
Thankfully, the JAXB2 Basics Plugins provides a similar mechanism for adding an interface to the generated JAXB stubs (see the Inheritance plugin).
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:
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):
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).
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:
https://jaxb2-commons.dev.java.net/
In particular, this one:
https://jaxb2-commons.dev.java.net/interface-insertion/
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:
]
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.
Here is a link on another forum which discusses a similar issue. http://forums.java.net/jive/message.jspa?messageID=220686
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).
You'd declare an aspect along the lines of:
Which will add the interface
com.foo.Person
to the classescom.foo.generated.Adult
andcom.foo.generated.Adult
Might be overkill for your purpose, but it worked for us.
In my case the command-line call via java -jar works:
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