|  |  |  | License Codehaus OpenEJB OpenJMS OpenORB Tyrex

Old releases
General
Release 1.3
Release 1.3rc1
Release 1.2

Main
Home
About
Features
Download
Dependencies
Reference guide
Publications
JavaDoc
Maven 2 support
Maven 2 archetypes
DTD & Schemas
Recent HTML changes
News Archive
RSS news feed
Project Wiki

Development/Support
Mailing Lists
SVN/JIRA
Contributing
Support
Continuous builds
Prof. services

Related projects
Spring ORM support
Spring XML factories
WS frameworks

XML
XML

XML Code Generator
XML Code Generator

JDO
Introduction
First steps
Using JDO
JDO Config
Types
JDO Mapping
JDO FAQ
JDO Examples
JDO HOW-TOs
Tips & Tricks
Other Features
JDO sample JAR

Tools
Schema generator

Advanced JDO
Caching
OQL
Trans. & Locks
Design
KeyGen
Long Trans.
Nested Attrs.
Pooling Examples
LOBs
Best practice

DDL Generator
Using DDL Generator
Properties
Ant task
Type Mapping

More
The Examples
3rd Party Tools
JDO Tests
XML Tests
Configuration

About
License
User stories
Contributors
Marketplace
Status, Todo
Changelog
Library
Contact
Project Name

## Type Support

Types
Castor XML
Castor JDO
Castor DAX
The Field Mapping
SQL Dates and Default Timezones
SQL Type Conversion
Parameterized Type Convertors
BLOB and CLOB Types

## Types

The Castor type mechanism assures proper conversion between Java types and external types.

### Castor XML

Castor XML converts all Java fields into XML element and attribute values.

### Castor JDO

Castor JDO converts Java fields into SQL columns which are persisted through the JDBC driver. Due to implementation details, the field type expected by the JDBC driver is not always the field type defined for the mapped object.

The most common occurrences of mistyping is when using fields of type `FLOAT`, `DOUBLE`, `NUMERIC`, and `DECIMAL`. SQL type `FLOAT` actually maps to Java type `java.lang.Double`. SQL types `NUMERIC` and `DECIMAL` map to Java type `java.math.BigDecimal`.

When such an inconsistency occurs, Castor JDO will throw an `IllegalArgumentException` during object persistence with a message indicating the two conflicting types.

In order to avoid runtime exceptions, we recommend explicitly specifying types in the mapping file using the SQL typing convention. See SQL Type Conversion.

### Castor DAX

Castor DAX converts all Java fields into LDAP attribute values. LDAP attribute values are always textual and are represented as the string value of the field, e.g. "5" or "true".

LDAP attributes may also contain binary values. When storing byte arrays or serialized Java objects, DAX will store them as byte arrays.

## The Field Mapping

The field element includes an optional attribute called type which can be used to specify the Java type of the field. This attribute is optional since Castor can always derive the exact Java type from the class definition.

We highly recommend that developers use the type field in their mapping file as a means to provide static type checking. When loading a mapping file, Castor will compare the actual Java type with the type specified in the mapping and will complain about inconsistencies.

The field type can be specified either given the full class name (e.g. `java.lang.Integer`) or using a short name. The following table lists all the acceptable short names and the Java types they represent:

short name | Primitive type? | Java Class
--- | --- | ---
big-decimal | N | java.math.BigDecimal
boolean | Y | java.lang.Boolean.TYPE
byte | Y | java.lang.Byte.TYPE
bytes | N | byte[]
char | Y | java.lang.Character.TYPE
chars | N | char[]
clob | N | java.sql.Clob
date | N | java.util.Date
double | Y | java.lang.Double.TYPE
float | Y | java.lang.Float.TYPE
integer | Y | java.lang.Integer.TYPE
locale | N | java.util.Locale
long | Y | java.lang.Long.TYPE
other | N | java.lang.Object
short | Y | java.lang.Short.TYPE
string | N | java.lang.String
strings | N | String[]
stream | N | java.io.InputStream

In addition, support for the following Castor-internal field types has been added:

short name | Primitive type? | Java Class
--- | --- | ---
duration | N | org.exolab.castor.types.Duration

## SQL Dates and Default Timezones

Castor will use the JDBC `ResultSet.getDate(int, Calendar)` and related methods which take a Calendar object to specify the timezone of the data retrieved from the database when the timezone information is not already specified in the data; this ensures that the "current" timezone is applied.

The default time zone can be configured in the castor.properties file; see the configuration section for details on how to configure Castor with information about your default time zone.

To change the timezone to a different timezone than the default, please set a (different) value on the `org.exolab.castor.jdo.defaultTimeZone` property:

    # Default time zone to apply to dates/times fetched from database fields,
    # if not already part of the data.  Specify same format as in
    # java.util.TimeZone.getTimeZone, or an empty string to use the computer's
    # local time zone.
    org.exolab.castor.jdo.defaultTimeZone=
    #org.exolab.castor.jdo.defaultTimeZone=GMT+8:00

## SQL Type Conversion

Castor JDO uses the JDBC `getObject/setObject` methods in order to retrieve and set fields. These methods do not perform automatic type conversion, often resulting in unexpected behavior. For example, when using a NUMERIC field with direct JDBC access, application developers tend to call `getInteger()` or `getFloat()`, but the Java object returned from a call to `getObject` is often a `java.math.BigDecimal`.

Castor JDO implements automatic type conversion between Java and SQL. For this mechanism to work, the mapping file must specify the SQL type being used for Castor to employ the proper convertor. If no SQL type is specified, no conversion will occur, possibly resulting in an `IllegalArgumentException` being thrown.

SQL types are specified with the sql-type attribute using either the default Java type returned by the JDBC driver (e.g. `java.lang.Integer` or the proper SQL type name (without precision). The following table lists the supported SQL type names and the corresponding Java types:

SQL Type | Java Type
--- | ---
bigint | java.lang.Long
binary | byte[]
bit | java.lang.Boolean
blob | java.io.InputStream
char | java.lang.String
clob | java.sql.Clob
decimal | java.math.BigDecimal
double | java.lang.Double
float | java.lang.Double
integer | java.lang.Integer
longvarbinary | byte[]
longvarchar | java.lang.String
numeric | java.math.BigDecimal
real | java.lang.Float
smallint | java.lang.Short
time | java.sql.Time
timestamp | java.sql.Timestamp
tinyint | java.lang.Byte
varbinary | byte[]
varchar | java.lang.String
other | java.lang.Object
javaobject | java.lang.Object

The following example illustrates how to specify SQL type in field mapping:

      <field name="prodId" type"integer">
        <sql name="prod_id" type="numeric"/>
      </field>

Please note that java.util.Date is not automatically converted into a java.sql.Date object; while it is in theory possible to do so, there are three different possible storage formats for date information: as a java.sql.Date, java.sql.Time, and java.sql.Timestamp. Rather than impose a possibly inappropriate data mapping on an entry, no automatic transformation will take place.

JDBC drivers which do not, themselves, perform a mapping between java.util.Date and the sql format specified on the database will throw an error when java.util.Date is passed to them on the prepared statement. Moreover, auto-conversion of java.util.Date is outside of the JDBC specification; it is not a supported auto-convert format.

Users wishing to store date information into the database should ensure that they set date, time, or timestamp as the sql type on the sql-type attribute.

## Parameterized Type Convertors

Some of the type convertors may have a string parameter, which changes the conversion algorithm. The parameter is specified in square brackets after the SQL type, for example:

      <field name="active" type="boolean">
        <sql name="acc_active" type="char[01]"/>
      </field>

where "0" is the character value for false and "1" is the character value for true.

In the above example the first of a bunch of parameterized type convertors is used, "boolean --> char" convertor. The parameter must have length 2, the first character is the value for false, the second character is the value for true. The default value is "FT". The actual SQL type should be char(1).

The second and third convertors are "boolean --> integer" and "boolean --> numeric". Its parameter must be + for +1 or - for -1 representing true. False is always converted to 0. For example:

      <field name="flagWithMinusOneForTrue" type="boolean">
        <sql name="flag" type="integer[-]"/>
      </field>

If the parameter is not specified, true is converted to +1.

The fourth convertor is "date --> char". Its parameter must be a correct pattern for SimpleDateFormat. For example:

      <field name="dateOfBirth" type="date">
        <sql name="pers_dob" type="char[MMM d, yyyy]"/>
      </field>

If the parameter is not specified, the conversion is performed using toString() method of the Date class.

The fifth and the sixth convertors are "date --> integer" and "date --> numeric". Their parameters are also patterns having syntax based on the SimpleDateFormat syntax, but repeated characters are eliminated. The following table shows the substitution rules that are used to obtain the SimpleDateFormat pattern from the parameter.

Y,y | yyyy | year
M | MM | month in year
D,d | dd | day in month
h,H | HH | hour in day (0~23)
m | mm | minute in hour
s | ss | second in minute
S | SSS | millisecond

For example, "YMD" parameter is expanded to "yyyyMMdd" SimpleDateFormat pattern, "YMDhmsS" parameter is expanded to "yyyyMMddHHmmssSSS" SimpleDateFormat pattern. The length of the expanded parameter gives the minimal number of decimal digits that the actual SQL type must support. The default value of the parameter is "YMD".

## BLOB and CLOB Types

BLOB and CLOB stand for binary and character large objects (or in Sybase, IMAGE and TEXT types, respectively). This means that most likely you don't want to load the whole objects into memory, but instead want to read and write them as streams. Usually these types are not comparable via the `WHERE` clause of a SQL statement. That is why you should disable dirty checking for such fields, e.g.

      <field name="text" type="string">
        <sql name="text" type="clob" dirty="ignore" />
      </field>

In this example CLOB field will be read as a String. This may cause OutOfMemoryError if the text is really large, but in many cases mapping CLOB to String is acceptable. The advantage of mapping to String is that we obtain a Serializable value that can be passed via RMI. Similarly you can map BLOB and CLOB to `byte[]` and `char[]` types, respectively:

      <field name="photo" type="bytes">
        <sql name="photo" type="blob" dirty="ignore" />
      </field>
      <field name="resume" type="chars">
        <sql name="resume" type="clob" dirty="ignore" />
      </field>

Now, assume that mapping to String is not acceptable. The natural Java type mapping for the BLOB type is `java.io.InputStream`, and this mapping is supported by Castor:

      <field name="cdImage" type="stream">
        <sql name="cd_image" type="blob" dirty="ignore" />
      </field>

The natural Java type mapping for the CLOB type is `java.io.Reader`, but this mapping is not supported by Castor because `java.io.Reader` doesn't provide information about the length of the stream and this information is necessary for JDBC driver (at least for the Oracle driver) to write the value to the database. This is why the CLOB type is mapped to `java.sql.Clob`:

      <field name="novel" type="clob">
        <sql name="novel" type="clob" dirty="ignore" />
      </field>

When you read data from the database, you can use the `getCharacterStream()` method to obtain a `java.io.Reader` from `java.sql.Clob`. When you write data to the database, you can either use the helper class `org.exolab.castor.jdo.engine.ClobImpl` to construct `java.sql.Clob` from `java.io.Reader` and the length:

      object.setClob(new ClobImpl(new FileReader(file), file.length());

or implement the `java.sql.Clob` interface yourself.

But be aware of the followng restriction: if you map BLOB to `java.io.InputStream` or CLOB to `java.sql.Clob`, then you should turn caching off for the Java class containing those values, e.g.:

      <class ...>
        <cache-type type="none"/>
          ...
          <field name="novel" type="clob">
            <sql name="novel" type="clob" dirty="ignore" />
          </field>
      </class>

Blob and Clob values cannot be cached, because they are alive only while the ResultSet that produced them is open. In particular, this means that you cannot use dirty checking for long transactions with such classes.

<notice> Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved. </notice>
<notice> Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners. </notice>