2011/01/16 - Apache ObJectRelationalBridge has been retired.

For more information, please explore the Attic.

HomeDocumentation
 

JDBC Types

Mapping of JDBC Types to Java Types

OJB implements the mapping conversions for JDBC and Java types as specified by the JDBC 3.0 specification (see JDBC 3.0 specification Appendix B, Data Type Conversion Tables). See the table below for details.

If a sql-java type mapping is needed, that doesn't match the java types defined by the specification, e.g. a field in the persistent object class is of type int[] and the DB type is VARCHAR or a List field have to be mapped to VARCHAR a field-conversion class can be used.

JDBC Type Java Type
CHAR String
VARCHAR String
LONGVARCHAR String
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT boolean
BOOLEAN boolean
TINYINT byte
SMALLINT short
INTEGER int
BIGINT long
REAL float
FLOAT double
DOUBLE double
BINARY byte[]
VARBINARY byte[]
LONGVARBINARY byte[]
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp
CLOB Clob
BLOB Blob
ARRAY Array
DISTINCT mapping of underlying type
STRUCT Struct
REF Ref
DATALINK java.net.URL
JAVA_OBJECT underlying Java class

Type and Value Conversions - The FieldConversion Interface

Introduction

A typical problem with O/R tools is mismatching datatypes: a class from the domain model has an attribute of type boolean but the corresponding database table stores this attribute in a column of type BIT or int.

This example explains how OJB allows you to define FieldConversions that do the proper translation of types and values.

The source code of this example is included in the OJB source distribution and resides in the test package org.apache.ojb.broker.

The problem

The test class org.apache.ojb.broker.Article contains an attribute isSelloutArticle of type boolean:

public class Article implements InterfaceArticle
{
    protected int articleId;
    protected String articleName;

    // maps to db-column Auslaufartikel of type int
    protected boolean isSelloutArticle;

    ...
}

The coresponding table uses an int column ( Auslaufartikel) to store this attribute:

CREATE TABLE Artikel (
    Artikel_Nr         INT PRIMARY KEY,
    Artikelname        CHAR(60),
    Lieferanten_Nr     INT,
    Kategorie_Nr       INT,
    Liefereinheit      CHAR(30),
    Einzelpreis        DECIMAL,
    Lagerbestand       INT,
    BestellteEinheiten INT,
    MindestBestand     INT,
    Auslaufartikel     INT
  )

The Solution

OJB allows to use predefined (or self-written) FieldConversions that do the appropiate mapping. The FieldConversion interface declares two methods: javaToSql(...) and sqlToJava(...):

/**
 * FieldConversion declares a protocol for type and value
 * conversions between persistent classes attributes and the columns
 * of the RDBMS.
 * The default implementation does not modify its input.
 * OJB users can use predefined implementation and can also
 * build their own conversions that perform arbitrary mappings.
 * the mapping has to defined in the xml repository
 * in the field-descriptor.
 *
 * @author Thomas Mahler
 */
public interface FieldConversion extends Serializable
{
    /**
     * convert a Java object to its SQL
     * pendant, used for insert & update
     */
    public abstract Object javaToSql(Object source) throws ConversionException;

    /**
     * convert a SQL value to a Java Object, used for SELECT
     */
    public abstract Object sqlToJava(Object source) throws ConversionException;
}

The method FieldConversion.sqlToJava() is a callback that is called within the OJB broker when Object attributes are read in from JDBC result sets. If OJB detects that a FieldConversion is declared for a persistent classes attributes, it uses the FieldConversion to do the marshalling of this attribute.

For the above mentioned problem of mapping an int column to a boolean attribute we can use the predefined FieldConversion Boolean2IntFieldConversion. Have a look at the code to see how it works:

public class Boolean2IntFieldConversion implements FieldConversion
{
    private static Integer I_TRUE = new Integer(1);
    private static Integer I_FALSE = new Integer(0);

    private static Boolean B_TRUE = new Boolean(true);
    private static Boolean B_FALSE = new Boolean(false);

    /**
     * @see FieldConversion#javaToSql(Object)
     */
    public Object javaToSql(Object source)
    {
        if (source instanceof Boolean)
        {
            if (source.equals(B_TRUE))
            {
                return I_TRUE;
            }
            else
            {
                return I_FALSE;
            }
        }
        else
        {
            return source;
        }
    }

    /**
     * @see FieldConversion#sqlToJava(Object)
     */
    public Object sqlToJava(Object source)
    {
        if (source instanceof Integer)
        {
            if (source.equals(I_TRUE))
            {
                return B_TRUE;
            }
            else
            {
                return B_FALSE;
            }
        }
        else
        {
            return source;
        }
    }
}

There are other helpful standard conversions defined in the package org.apache.ojb.broker.accesslayer.conversions: Of course it is possible to map between java.sql.date and java.util.date by using a Conversion. A very interesting Conversion is the Object2ByteArrFieldConversion it allows to store inlined objects in varchar columns!

Coming back to our example, there is only one thing left to do: we must tell OJB to use the proper FieldConversion for the Article class. This is done in the XML repository file. The field-descriptor allows to define a conversion attribute declaring the fully qualified FieldConversion class:

<!-- Definitions for test.ojb.broker.Article -->
   <class-descriptor
         class="org.apache.ojb.broker.Article"
         proxy="dynamic"
         table="Artikel"
   >
      ...
      <field-descriptor
         name="isSelloutArticle"
         column="Auslaufartikel"
         jdbc-type="INTEGER"
         conversion="org.apache.ojb.broker.accesslayer.conversions.Boolean2IntFieldConversion"
      />
      ...
   </class-descriptor>

by Thomas Mahler, Armin Waibel