 |
Separate compilation in the JAXB RI 2.1
Posted by kohsuke on September 05, 2006 at 02:41 PM | Comments (17)
I just finished implementing the proposed separate compilation feature in the JAXB RI 2.1. So today I'm going to talk about how this proposed feature works, in the hope of getting more feedback for this proposal. You can play with this today by downloading the latest 2.1 continuous build of the JAXB RI.
The "separate compilation" that I'm talking about works like this. Alice has an extensible schema A and its corresponding JAXB classes:
@XmlType(namespace="A",name="myType")
class MyType {}
Maybe she wrote the schema and then generated the classes, or maybe she wrote classes and then generated the schema. Or maybe she wrote both by hand. It doesn't matter. Alice distributes this a.xsd and a.jar that contains these.
Now Bob has a schema B that refers to A. Maybe like this:
He wants to generate Java classes for this schema, and he wants the schema compiler to do this by reusing classes in a.jar and not generating a new MyType class. In 2.0, this was somewhere between hard to impossible. But in 2.1, this is going to be much easier.
Case 1: a.jar is generated by XJC
The first case to consider is when Alice wrote a.xsd and generated a.jar by XJC. In this case, when invoking XJC, Alice would do it like this:
$ xjc -episode a.episode a.xsd
This tells XJC to compile a.xsd and then also generate what I call an "episode" file, which contains information about what schema stuff produced what Java stuff. This generated file is actually just a JAXB customization file, although unfortunately this version uses SCD, which makes it non-portable (there are ways to make this portable --- more work ahead.)
Anyway, with this, Bob will compile b.xsd like the following, to generate classes that refer to existing classes in a.jar. The specified a.episode tells the compiler to do the right thing.
$ xjc b.xsd -b a.episode
Since distributing two things is tedious and error prone, Alice can also choose to put a.episode into a.jar in /META-INF/sun-jaxb.episode. With this, Bob can run XJC like this to achieve the same effect, but this time without worrying about the additional file:
$ xjc b.xsd a.jar
Case 2: a.xsd is generated by schemagen
It's really the same thing as in the above case. When Alice generates a.xsd, she'd do it like this (or use the @episode if you invoke schemagen via the ant task:)
$ schemagen -episode a.episode ....sourcefiles...
This tells schemagen to generate schema files as well as an episode file. Bob can then use this episode file, along with the schema, to refer to Alice's existing classes:
$ xjc b.xsd -b a.episode
Pretty easy, huh?
Case 3: a.xsd and a.jar are both manually written
You can manually write the episode file (if you look at a few of them, you'll find that it's pretty easy to do so), or you can run schemagen just to get the episode file and discard all the schemas.
Conclusion
So that's what' we are planning to do in 2.1. Let us know what you think, while we can still change things...
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Maybe I'm missing something here. Do you see my error?
Using latest snapshot, trying this out. here is common.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foo.bar"
xmlns:car="http://www.foo.bar"
elementFormDefault="qualified">
<xs:complexType name="carrotType">
</xs:complexType>
</xs:schema>
and here is carrotlist.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foo.bar"
xmlns:car="http://www.foo.bar"
elementFormDefault="qualified">
<xs:include schemaLocation="./common.xsd"/>
<xs:element name="carrotList" type="car:carrotListType"/>
<xs:complexType name="carrotListType">
<xs:sequence>
<xs:element name="carrot" type="car:carrotType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
here I go:
$ xjc.sh -d ./test/ -episode ./test/common.episode common.xsd
parsing a schema...
compiling a schema...
bar/foo/CarrotType.java
bar/foo/ObjectFactory.java
bar/foo/package-info.java
$ xjc.sh -d ./test/ ./carrotlist.xsd ./test/common.episode
parsing a schema...
[ERROR] s4s-elt-schema-ns: The namespace of element 'bindings' must be from the schema namespace, 'http://www.w3.org/2001/XMLSchema'.
line 2 of file:/home/me/test/common.episode
[ERROR] s4s-elt-invalid: Element 'bindings' is not a valid element in a schema document.
line 2 of file:/home/me/test/common.episode
[ERROR] schema_reference.4: Failed to read schema document 'file:/home/me/test/common.episode', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .
line 2 of file:/home/me/test/common.episode
Failed to parse a schema.
$
Posted by: grizel on October 05, 2006 at 03:18 PM
-
Please use the forum for the user support like this. Thank you!
Posted by: kohsuke on October 05, 2006 at 08:56 PM
-
This type of feature is exactly what I need. I am new to the world of XML/XSD/web services - but not new to SOA - and I was amazed to find that there was no easy way to reuse previously developed XSD and and associated classes.
Where I work we hope to have a repository of XSD and classes, probably with a mix of generated classes, generated XSD, and hand-built. These will form our data model at least. We may try to promote restful web service 'interfaces' to the repository as well.
I like the new feature and will definitely use it. It is too bad that an intermediate file (episodes) must be used. Esp. since it is non-standard.
Posted by: seanl on November 15, 2006 at 07:58 AM
-
In the 2.1EA release I have, I noticed the documentation for xjc does not include the -episode flag (but does mention /META-INF/sun-jaxb.episode).
Also, how about ant? is there an tag?
Posted by: seanl on November 30, 2006 at 12:12 PM
-
I found I could get ant to work with the following:
but I cannot seem to get any form of the
$ xjc b.xsd a.episode
to work. xjc seems to want to interpret the episode as an xsd. Here's my command:
~/jaxb-ri-20061115/bin/xjc.sh -d examples/jaxb2/src resources/hello.xsd example.episode
parsing a schema...
[ERROR] s4s-elt-schema-ns: The namespace of element 'bindings' must be from the schema namespace, 'http://www.w3.org/2001/XMLSchema'.
line 2 of file:/home/slandis/workspace/RestFramework/example.episode
[ERROR] s4s-elt-invalid: Element 'bindings' is not a valid element in a schema document.
line 2 of file:/home/slandis/workspace/RestFramework/example.episode
[ERROR] schema_reference.4: Failed to read schema document 'file:/home/slandis/workspace/RestFramework/example.episode', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .
line 2 of file:/home/slandis/workspace/RestFramework/example.episode
Failed to parse a schema.
Any suggestions?
Posted by: seanl on November 30, 2006 at 12:49 PM
-
Sorry, here's that output again>
~/jaxb-ri-20061115/bin/xjc.sh -d examples/jaxb2/src resources/hello.xsd example.episode
parsing a schema...
[ERROR] s4s-elt-schema-ns: The namespace of element 'bindings' must be from the schema namespace, 'http://www.w3.org/2001/XMLSchema'.
line 2 of file:/home/slandis/workspace/RestFramework/example.episode
[ERROR] s4s-elt-invalid: Element 'bindings' is not a valid element in a schema document.
line 2 of file:/home/slandis/workspace/RestFramework/example.episode
[ERROR] schema_reference.4: Failed to read schema document 'file:/home/slandis/workspace/RestFramework/example.episode', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .
line 2 of file:/home/slandis/workspace/RestFramework/example.episode
Failed to parse a schema.
Posted by: seanl on November 30, 2006 at 12:51 PM
-
Sorry, I was missing the crucial "-b" option. The blog updated accordingly.
Posted by: kohsuke on December 11, 2006 at 01:32 PM
-
In my case i have a common schema without a targetnamespace that needs to be included in 2 or more other schemas. What i first do is compile the common schema with the episode switch. When i subsequently compile the referencing schema giving it the episode file, i get following error:
SCD "x-schema::" didnt match any schema component
This is probably happening bcoz the common schema episode file doesn't have a targetnamespace in it. Do I have to it for this to work? I ideally don't want to include a targetnamespace coz the common schema i am using is external and i don't want to modify that. The author of the schema probably intentionally left the targetnamespace out of it so that it can be included in other schemas.
If this is a bug, let me know and i'll file it. If there's a work around to this problem, please let me know
Posted by: sjd00d on June 28, 2007 at 12:14 PM
-
Thanks for explaining this Kohsuke. I had been struggling for ages with this problem and I am glad it is being solved. Please could you update this blog with further news? I didn't understand your comments on SCD: "...unfortunately this version uses SCD, which makes it non-portable (there are ways to make this portable --- more work ahead.)"
Posted by: rogerp on July 19, 2007 at 09:53 AM
-
I couldn't find any documentation on how to get an episode file generated via the xjc ant task. I finally figured it out (use arg):
<xjc schema="src/foo.xsd"
package="com.foo.gen"
destdir="src/java"
removeOldOutput="true"
extension="true">
<arg value="-episode"/>
<arg value="foo.episode"/>
</xjc>
Posted by: cliffwd on September 21, 2007 at 10:09 AM
-
How can this feature be used while developing web service using GlassFish where user does not explicitly run schemagen tool? The problem I have is that I have developed a web service and hand written the custom Java classes that are used in the service interface. Those classes have JAXB annotations. When I deploy to GlassFish, the server generates the WSDL & the xsd and makes it available in a well known place. In the client side, if I want to reuse the server side Java classes, then I have to manually delete wsimport generated classes - which is painful.
Thanks,
Sahoo
Posted by: ss141213 on October 24, 2007 at 09:58 AM
-
I've updated the documentation on maven-jaxb2-plugin:
https://maven-jaxb2-plugin.dev.java.net/docs/guide.html#SeparateCompilation
Posted by: lexi on December 09, 2007 at 05:51 AM
-
Even using arg in xjc doesn't work. It throws "unrecognized parameter -episode' "
Is it possible to creat episode file using ant tasl?
Posted by: anuragpaliwal on January 25, 2008 at 05:58 AM
-
anuragpaliwal — Are you using 2.1?
Posted by: kohsuke on January 25, 2008 at 11:29 AM
-
Above you mentioned passing a jar that has META-INF/sun-jaxb.episode to xjc. How do you do this with the xjc ant task? Thanks in advance.
Posted by: ryokota on March 26, 2008 at 11:30 AM
-
ryokota — I believe nested element would do.
Posted by: kohsuke on March 31, 2008 at 11:36 AM
-
Works like a charm... thanks!
Just a question. I used three XSD to generate the episode file. If i use that episode file to generate new JAXB files i encounter the following:
-
I still need the physical .XSD files that were processed before. Is that right?
- If not all three namespaces (of the XSD's) are used in the other XSD's XJC will give an error.
[ERROR] SCD "x-schema::tns" didnt match any schema component
Should that happen?
I would really like it if XJC didn't need the previously processed XSD's and wouldn't 'error' on an unused bindings in the .episode.
Regards,
Robert
Posted by: willemsrb on May 07, 2008 at 06:42 AM
|