Java JMX JAXB Outsourcing System Architecture
 


The No.1 i-Technology Magazine in the World !
   
 
Mailing List
««
July 2009
»»
SM
T
WTFS
    1234
567891011
12131415161718
19202122232425
262728293031

J. Steven Perry

This is it. The most important blog you will ever read.

(Believe it.)

Customizing JAXB generated packages based on target namespace

Here's a little tip I thought I'd pass along about customizing JAXB to generate stuff to different packages based on target namespace. There are two ways to do it...


Here are the schemas we'll be looking at:


common.xsd:


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="
http://www.test.com/common" targetNamespace="http://www.test.com/common" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">


 <xs:element name="aString" type="aString_Type"/>
 <xs:element name="aInteger" type="aInteger_Type"/>
 <xs:element name="aLong" type="aLong_Type"/>
 
 <xs:simpleType name="aString_Type">
  <xs:restriction base="xs:string"/>
 </xs:simpleType>
 <xs:simpleType name="aInteger_Type">
  <xs:restriction base="xs:integer"/>
 </xs:simpleType>
 <xs:simpleType name="aLong_Type">
  <xs:restriction base="xs:long"/>
 </xs:simpleType>
 
</xs:schema>


 




 A.xsd:


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="
http://www.test.com/A" targetNamespace="http://www.test.com/A" xmlns:common="http://www.test.com/common" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">


<xs:import namespace="http://www.test.com/common" schemaLocation="common.xsd"/>


<xs:element name="A" type="A_Type"/>


<xs:complexType name="A_Type">
 <xs:sequence>
  <xs:element ref="common:aString"/>
  <xs:element ref="common:aInteger" minOccurs="0"/>
  <xs:element ref="common:aLong" minOccurs="0"/>
 </xs:sequence>
</xs:complexType>
</xs:schema>


 




 B.xsd:


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.test.com/B" targetNamespace="http://www.test.com/B" xmlns:common="http://www.test.com/common" xmlns:a="http://www.test.com/A" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">


<xs:import namespace="http://www.test.com/common" schemaLocation="common.xsd"/>
<xs:import namespace="http://www.test.com/A" schemaLocation="A.xsd"/>


<xs:element name="B" type="B_Type"/>


<xs:complexType name="B_Type">
 <xs:sequence>
  <xs:element ref="common:aString"/>
  <xs:element ref="a:A"/>
  <xs:element ref="common:aLong" maxOccurs="unbounded"/>
 </xs:sequence>
</xs:complexType>


</xs:schema>


 




 I use Windoze for my desktop client, so I created a command file to run the JAXB schema binding compiler:


 gen-jaxb.cmd:


@set JAVA_HOME=C:\j2sdk1.4.2_05
@set JWSDP_HOME=C:\jwsdp-1.4
@set SCHEMA_DIR=.
@set DEST_DIR=.\gen-src


@rem Use the below to let JAXB derive package name based on targetNamespace


%JAVA_HOME%\bin\java -jar -Xmx512m -Xss2m %JWSDP_HOME%\jaxb\lib\jaxb-xjc.jar %SCHEMA_DIR%\B.xsd -d %DEST_DIR%


@rem Use the below to customize package name using an external binding file


%JAVA_HOME%\bin\java -jar -Xmx512m -Xss2m %JWSDP_HOME%\jaxb\lib\jaxb-xjc.jar %SCHEMA_DIR%\B.xsd -d %DEST_DIR% -b binding.xjb


 




 And I use an external binding file, so customizations are outside of my schema file. This has two distinct advantages: First, since oftentimes I don't have the luxury of modifying a schema, my binding customizations are externalized. Second, if I want to use a different binding compiler my schema (along with the aforementioned schema files I may or may not be allowed to modify) remain unchanged.


binding.xjb:


<jxb:bindings version="1.0" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:com.fnf="http://www.fnf.com/xes">
    <!-- Customize the package name that is generated for each schema.
  -->
    <jxb:bindings schemaLocation="A.xsd" node="/xs:schema">
        <jxb:schemaBindings>
            <jxb:package name="com.test.customized.a"/>
        </jxb:schemaBindings>
    </jxb:bindings>
    <jxb:bindings schemaLocation="B.xsd" node="/xs:schema">
        <jxb:schemaBindings>
            <jxb:package name="com.test.customized.b"/>
        </jxb:schemaBindings>
    </jxb:bindings>
    <jxb:bindings schemaLocation="common.xsd" node="/xs:schema">
        <jxb:schemaBindings>
            <jxb:package name="com.test.customized.common"/>
        </jxb:schemaBindings>
    </jxb:bindings>
</jxb:bindings>


 




 Okay, so all the pieces are in place. Now let's look at the two scenarios for the package name of our generated code.


 




 Scenario 1: Let JAXB derive package where generated classes will reside based on targetNamespace attribute


JAXB can derive the package name based on the targetNamespace attribute of each schema file. The rules for doing so are outlined in the spec, so I won't include them here. But here's a link to it: http://java.sun.com/xml/downloads/jaxb.html. When I run the binding compiler using the first line of binding.xjb (make sure to comment out the second line or it will overwrite the generated code from the first line, and that will be, well, plain confusing!), I get code generated to packages:



  • com.test.common

  • com.test.a

  • com.test.b


Take another look at the targetNamespace attributes of each schema above and see if you can follow how the binding compiler derived the name of each corresponding package.


 




 Scenario 2: Use a customization to choose the package to which the generated classes will reside


In this scenario, I comment out the first line in the gen-jaxb.cmd file and uncomment the second to force a customization of the package for each namespace and get the following packages generated:



  • com.test.customized.common

  • com.test.customized.a

  • com.test.customized.b


 




 Enjoy!


 


 

Stéphane made this comment,
Interesting article.

Is the binding works also if I replace <xs:import> by <xs:include> ?

comment added :: 20th February 2006, 10:26 GMT-06
J. Steven Perry made this comment,
I'm afraid I don't completely understand your question. The point of the example is to show that for different targetNamespaces, JAXB can be customized to generate to any package (per namespace) that you like.

Can you elaborate on your question, please?

Thanks.

--steve

comment added :: 20th February 2006, 19:53 GMT-06 :: http://blog.jstevenperry.com
Stéphane made this comment,
I have many schemas which are included (not imported) in a global schema. The target namespaces are the same for all schemas.

I would like to generate different java packages by schemas included (or by root elements), not by namespace.

Stéphane

comment added :: 21st February 2006, 07:00 GMT-06
J. Steven Perry made this comment,
I don't believe there is a way to do that. The natural mapping of an XML namespace is to a package. That being so, if all schema documents are in the same namespace, it really doesn't make much sense from an XML standpoint. Since you are wanting to use different constructs in your Java code from different packages, you really should take a look at your schema design and see if this tendency could be reflected there, so that it matches up with your Java code.

You should post this question to the JAXB users forum (send a message to users@jaxb.dev.java.net) and see what other replies you get.

--steve

comment added :: 22nd February 2006, 07:17 GMT-06
sid made this comment,
i think i understand why stephane wants to generate a different package for the same namespace. Many a times schema authors make a list of reusable types which they use across differenct schemas with the same namespace and this list of reusuable types probably need to be in a com.company.schema.'types' package
comment added :: 24th July 2006, 15:50 GMT-06

This blog is created and maintained by the author of the page and in no way associated with SYS-CON Media or JDJ. The author of the blog assumes all liability and responsibility personally for the content of the page. JavaTM, J2EE, J2ME, J2SE, and other Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON and JDJ are independent of Sun Microsystems.
www.blog-n-play.com is a registered trademark (78553120) of SYS-CON Media.