With Castor 1.2 and earlier releases it has already been possible to generate Java classes from an XML schema and use these classes for XML data binding without having to write a mapping file.
This is possible because the Castor XML code generator generated - in addition to the domain classes - a set of XML descriptor classes as well, with one descriptor class generated per generated domain class. It's this XML descriptor class that holds all the information required to map Java classes and/or field members to XML artifacts, as set out in the original XML schema definitions. This includes ....
artefact names
XML namespace URIs
XML namespace prefix
validation code
Starting with Castor 1.3, a mechanism has been added to the XML code generator that allows extension of these core offerings so that either additional content is added to the generated domain classes additonal descriptor classes are gernated.
With Castor 1.2 and previous releases it was already possible to generate Java classes from an XML schema and use these classes for XML data binding without having to write a mapping file.
This is possible because the Castor XML code generator generated - in addition to the domain classes - a set of XML descriptor classes as well, with one descriptor class generated per generated domain class. It's this XML descriptor class that holds all the information required to map Java classes and/or field members to XML artifacts, as set out in the original XML schema definitions. This includes ....
artefact names
XML namespace URIs
XML namespace prefix
validation code
In addition, it was already possible to use the generated set of domain classes in Castor JDO for object-/relational mapping purpose by supplying a (manually written) JDO-specific mapping file. Whilst technically not very difficult, this was still an error-prone task, especially in a context where tens or hundreds of classes were generated from a set of XML schemas.
The JDO extensions for the Castor XML code generator extend the code generator in such a way that a second set of descriptor classes is generated: the JDO descriptor classes. These new descriptor classes define the mapping between Java (domain) objects and database tables/columns, and as such remove the requirement of having to write a JDO-specific mapping file.
Note | |
---|---|
Please note that Castor JDO - upon startup - internally converts the information provided in the JDO mapping file to (JDO) descriptor classes. As such, the approach outlined above simply re-uses an existing code base and just automates the production of those descriptor classes. |
The following sections introduce the general principles, define the XML schema artifacts available to annotate an existing XML schema and highlight the usage of these artifacts by providing examples. At the same time, a limited set of current product limitations are spelled out.
With release 1.3 of Castor, the following limitations exist for the JDO extensions of the XML code generator:
The extensions currently can only be used in type mode of the XML code generator.
There's currently no support for key generators. There's work in progress to add this functionality, though.
There's currently no support for bidirectional relations, modelled through the use of <xs:id> and <xs:idref> constructs.
To facilitate the detailed explanations in the following sections, we now define a few <complexType> definitions that we want to map against an existing database schema, and the corresponding SQL statements to create the required tables.
<complexType name="bookType"> <sequence> <element name="isbn" type="xs:string" /> <element name="pages" type="xs:integer" /> <element name="lector" type="lectorType" /> <element name="authors" type="authorType" maxOccurs="unbounded" /> </sequence> </complexType> <complexType name="lectorType"> <sequence> <element name="siNumber" type="xs:integer" /> <element name="name" type="xs:string" /> </sequence> </complexType> <complexType name="authorType"> <sequence> <element name="siNumber" type="xs:integer" /> <element name="name" type="xs:string" /> </sequence> </complexType>
CREATE TABLE author_table ( sin INTEGER NOT NULL, name VARCHAR(20) NOT NULL ); CREATE TABLE lector_table ( sin INTEGER NOT NULL, name VARCHAR(20) NOT NULL ); CREATE TABLE book_table ( isbn VARCHAR(13) NOT NULL, pages INTEGER, lector_id INTEGER NOT NULL, author_id INTEGER NOT NULL );
To have the Castor XML code generator generate JDO class descriptors when processing a set of XML schemas, please use one of the following methods:
Table 8.1. Accessing options
Usage | Method | Description |
---|---|---|
SourceGenerator | setJdoDescriptorCreation(boolean) | Supply a value of true to enable this feature. |
SourceGeneratorMain | Flag -gen-jdo-desc | Set this optional flag to enable this feature. |
Ant task for XML code generator | generateJdoDescriptors option | Set this to a value of true . |
This section enlists the XML artifacts available to annotate an existing XML schema
with JDO extension-specific information. These constructs are defined themselves
in an XML schema jdo-extensions.xsd
that has a target
namespace of http://www.castor.org/binding/persistence
.
To enable proper validation of your XML schemas when editing JDO
annotations, and to enable XML completion in your preferred XML
editor, please add schemaLocation
information to
your XML schema definition as follows:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://your/target/namespace" xmlns:jdo="http://www.castor.org/binding/persistence" xmlns="http://your/target/namespace" xsi:schemaLocation="http://www.castor.org/binding/persistence http://www.castor.org/jdo-extensions.xsd"> ... </xs:schema>
where ...
The values supplied in the |
The <table> element allows you to map an <complexType>
definition to a database table within a database, and to specify the
identity (frequently referred to as primary key
),
as follows:
<xs:complexType name="authorType"> <xs:annotation> <xs:appinfo> <jdo:table name="author_table"> <jdo:primary-key> <jdo:key>siNumber</jdo:key> </jdo:primary-key> </jdo:table> </xs:appinfo> </xs:annotation> <xs:sequence> <xs:element name="siNumber" type="xs:integer" /> <xs:element name="name" type="xs:string" /> </xs:sequence> </xs:complexType>
where ...
The | |
The |
Above example maps the complex type authorType
to
the table author_table
, and specifies that the
member siNumber
be used as object identity.
The XML schema definition for the <table>
element is defined as follows:
<xs:element name="table"> <xs:complexType> <xs:sequence> <xs:element name="primaryKey" type="jdo:pkType"/> </xs:sequence> <xs:attribute name="name" type="xs:string" use="required"/> <xs:attribute name="accessMode" use="optional" default="shared"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="read-only"/> <xs:enumeration value="shared"/> <xs:enumeration value="exclusive"/> <xs:enumeration value="db-locked"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="detachable" type="xs:boolean" default="false"/> </xs:complexType> </xs:element> <xs:complexType name="pkType"> <xs:sequence> <xs:element name="key" type="xs:string" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType>
The <column> element allows you to map a member of content model of a <complexType> definition to a column within a database table.
<xs:complexType name="authorType"> <xs:annotation> <xs:appinfo> <jdo:table name="author_table"> <jdo:primary-key> <jdo:key>siNumber</jdo:key> </jdo:primary-key> </jdo:table> </xs:appinfo> </xs:annotation> <xs:sequence> <xs:element name="siNumber" type="xs:integer" > <xs:annotation> <xs:appinfo> <jdo:column name="sin" type="integer" /> </xs:appinfo> </xs:annotation> </xs:element> <xs:element name="name" type="xs:string" /> </xs:sequence> </xs:complexType>
where ....
Defines that the element definition |
Above example maps the element isNumber
to
the database column sin
, and specifies the database type
to be used for persistence (integer
, in this case).
The XML schema definition for <column>
is
defined as follows:
<xs:element name="column"> <xs:complexType> <xs:complexContent> <xs:extension base="jdo:readonlyDirtyType"> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="type" type="xs:string" use="required" /> <xs:attribute name="acceptNull" type="xs:boolean" use="optional" default="true" /> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element>
where the content is described as follows:
Table 8.2. <column> - Definitions
Name | Description |
---|---|
name | Name of the column |
type | JDO-type of the column |
acceptNull | Whether this field accepts NULL values or not |
The <one-to-one> element allows you to map a member of content model of a <complexType> definition to a 1:1 relation to another <complexType>.
<xs:complexType name="bookType"> <xs:annotation> <xs:appinfo> <jdo:table name="book_type_table"> <jdo:primary-key> <jdo:key>isbn</jdo:key> </jdo:primary-key> </jdo:table> </xs:appinfo> </xs:annotation> <xs:sequence> <xs:element name="isbn" type="xs:string" > <xs:annotation> <xs:appinfo> <jdo:column name="isbn" type="varchar" /> </xs:appinfo> </xs:annotation> </xs:element> <xs:element name="pages" type="xs:integer" > <xs:annotation> <xs:appinfo> <jdo:column name="pages" type="integer" /> </xs:appinfo> </xs:annotation> </xs:element> <xs:element name="lector" type="lectorType" > <xs:annotation> <xs:appinfo> <jdo:one-to-one name="lector_id" /> </xs:appinfo> </xs:annotation> </xs:element> <xs:element name="authors" type="authorType" maxOccurs="unbounded" > ... </xs:element> </xs:sequence> </xs:complexType>
where ....
Defines a 1:1 relation to another <complexType>, additionally providing the necessary foreign key column at the database level. |
Above example maps the element lector
to a
1:1 relation to the complex type lectorType
, and
specifies the (column name of the) foreign key to be used
(lector_id
in this case).
The XML schema definition for <one-to-one>
is defined as follows:
<xs:element name="one-to-one"> <xs:complexType> <xs:complexContent> <xs:extension base="jdo:readonlyDirtyType"> <xs:attribute name="name" type="xs:string"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element>
where the content is described as follows:
Table 8.3. <one-to-one> - Definitions
Name | Description |
---|---|
name | Name of the column that represents the foreign key of this relation |
The <one-to-many> element allows you to map a member of the content model of a <complexType> definition as part of a 1:M relation to another <complexType>.
<xs:complexType name="bookType"> <xs:annotation> <xs:appinfo> <jdo:table name="book_type_table"> <jdo:primary-key> <jdo:key>isbn</jdo:key> </jdo:primary-key> </jdo:table> </xs:appinfo> </xs:annotation> <xs:sequence> <xs:element name="isbn" type="xs:string" > <xs:annotation> <xs:appinfo> <jdo:column name="isbn" type="varchar" /> </xs:appinfo> </xs:annotation> </xs:element> <xs:element name="pages" type="xs:integer" > <xs:annotation> <xs:appinfo> <jdo:column name="pages" type="integer" /> </xs:appinfo> </xs:annotation> </xs:element> <xs:element name="lector" type="lectorType" > <xs:annotation> <xs:appinfo> <jdo:one-to-one name="lector_id" /> </xs:appinfo> </xs:annotation> </xs:element> <xs:element name="authors" type="authorType" maxOccurs="unbounded" > <xs:annotation> <xs:appinfo> <jdo:one-to-many name="book_id" /> </xs:appinfo> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType>
where ....
Defines a 1:M relation to another <complexType>, additionally providing the necessary foreign key column for the many member at the database level. |
Above example maps the element authors
as part of a
1:M relation to the complex type authorType
, and
specifies the (column name of the) foreign key of the many member
to be used (book_id
in this case).
The XML schema definition for <one-to-many>
is given as follows:
<xs:element name="one-to-many"> <xs:complexType> <xs:complexContent> <xs:extension base="jdo:readonlyDirtyType"> <xs:attribute name="name" type="xs:string" /> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element>
with the following details applying:
Table 8.4. <one-to-many> - Definitions
Name | Description |
---|---|
name | Name of the column that represents the (many) foreign key of this relation |
Once you have generated domain classes and descriptor classes (both XML and JDO) from your set of XML schemas, you'll be able to use them as are. There's a few minor changes, which we are going to highlight below, but the main benefit is that you not have to write a JDO mapping file.
As you have already generated JDO descriptor classes for each of your domain objects, you won't have to supply mappings for those classes anymore. As such, your mapping file will stay empty, as shown:
<?xml version="1.0"?> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd"> <mapping> <!-- no mappings required --> </mapping>
Note | |
---|---|
Please note that you can of course supply mappings for those classes that stand outside of the generation process from your XML schemas. It is possible, too, to match both modes. In other words, a domain class mapped manually will be able to refer to a domain class as generated. |
In order for Castor to be able to access the generated (JDO) class
descriptors and to load those classes from the file system,
you will have to configure an instance of
JDOClassDescriptorResolver
and pass it to your
JDOManager
instance when loading the JDO
configuration.
The following example shows how to configure Castor JDO so that the classes generated from the sample XML schema above can be used with CASTOR JDO seamlessly.
JDOClassDescriptorResolver resolver = new JDOClassDescriptorResolverImpl(); resolver.addClass(org.castor.jdo.extension.sample.BookType.class); resolver.addClass(org.castor.jdo.extension.sample.LectorType.class); resolver.addClass(org.castor.jdo.extension.sample.AuthorType.class); InputSource jdoConfiguration = ....; JDOManager.loadConfiguration(jdoConfiguration, null, null, resolver); JDOManager jdoManager = JDOManager.createInstance("jdo-extensions"); ...
Alternatively, if the classes generated from the sample
XML schema shown above reside in the same package, you can
configure the JDOClassDescriptorResolver
as follows:
JDOClassDescriptorResolver resolver = new JDOClassDescriptorResolverImpl(); resolver.addPackage("org.castor.jdo.extension.sample"); ...
Tip | |
---|---|
For the latter approach to work, you will have to make sure that the
|
With Castor 1.2 and previous releases it was already possible to generate Java classes from an XML schema and use these classes for XML data binding without having to write a mapping file.
This is possible because the Castor XML code generator generated - in addition to the domain classes - a set of XML descriptor classes as well, with one descriptor class generated per generated domain class. It's this XML descriptor class that holds all the information required to map Java classes and/or field members to XML artifacts, as set out in the original XML schema definitions. This includes ....
artefact names
XML namespace URIs
XML namespace prefix
validation code
The SOLRJ extensions for the Castor XML code generator
extend the code generator in such a way that the set of domain classes is
augmented with SOLRJ-specific @Field
annotations.
The following sections introduce the general principles, define the XML schema artifacts available to annotate an existing XML schema and highlight the usage of these artifacts by providing examples.
To facilitate the detailed explanations in the following sections, we now define a few <complexType> definitions that we want to be able to store in a SOLR index in addition to vanilla XML data binding funtionality.
This section enlists the XML artifacts available to annotate an existing XML schema
with SOLRJ extension-specific information. These constructs are defined themselves
in an XML schema solrj-extensions.xsd
that has a target
namespace of http://www.castor.org/binding/solrj
.
To enable proper validation of your XML schemas when editing SOLRJ
annotations, and to enable XML completion in your preferred XML
editor, please add schemaLocation
information to
your XML schema definition as follows:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://your/target/namespace" xmlns:solr="http://www.castor.org/binding/solrj" xmlns="http://your/target/namespace" xsi:schemaLocation="http://www.castor.org/binding/solrj http://www.castor.org/solrj-extensions.xsd"> ... </xs:schema>
where ...
The values supplied in the |
The <field> element allows you to map a member of the content model
of a <complexType>
definition to SOLRJ field.
<complexType name="bookType"> <sequence> <element name="isbn" type="xs:string"> <xs:annotation> <xs:appinfo> <solrj:field name="id" /> </xs:appinfo> </xs:annotation> </element> <element name="pages" type="xs:integer"> <xs:annotation> <xs:appinfo> <solrj:field /> </xs:appinfo> </xs:annotation> </element> </sequence> </complexType>
where ....
Defines that the element definition | |
Defines that the element definition |
Above example maps the element isbn
to
the SOLR index field id
, and the element
name
to the identically-named SOLR index
field. Please note that a SOLR index field name does not have
to be specified if the field name and the Java property name
are identical.
Above complex type definition will be transformed to the corresponding Java property definitions (within a class):
public class BookType { @Field("id") private String isbn; @Field private long pages; }
The XML schema definition for <field>
is
defined as follows:
<xs:element name="field"> <xs:annotation> <xs:documentation> Element 'field' is used to specify the use of the SOLRJ @Field annotation. </xs:documentation> </xs:annotation> <xs:complexType> <xs:attribute name="name" type="xs:string" use="optional"> <xs:annotation> <xs:documentation> Attribute 'name' is used to specify the name of the index field to be mapped against; if not used, the name of the Java property will be used as filed name. </xs:documentation> </xs:annotation> </xs:attribute> </xs:complexType> </xs:element>
where the content is described as follows: