Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a JAXB class that implements an interface

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?

like image 669
Alex Spurling Avatar asked Aug 13 '09 13:08

Alex Spurling


People also ask

What is a JAXB class?

The JAXB compiler generates Java classes that map to constraints in the source XML schema. The classes implements get and set methods that you can use to obtain and specify data for each type of element and attribute in the schema. Process XML documents by instantiating the generated classes in a Java program.

What is XJC?

XJC is a Java SE tool that compiles an XML schema file into fully annotated Java classes. It is distributed within the JDK package and is located at /bin/xjc path.

How do I create an XSD class in Intellij?

Generate a Java class from an XML Schema using JAXB In the active editor tab, open the desired Schema . xsd file or an XML document, which contains the desired Schema. In the main menu, go to Tools | XML Actions | Generate Java Code From XML Schema Using JAXB.


2 Answers

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:

<?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):

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).

like image 151
Jim Hurne Avatar answered Sep 20 '22 15:09

Jim Hurne


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:

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

Might be overkill for your purpose, but it worked for us.

like image 42
Chris Avatar answered Sep 16 '22 15:09

Chris