openxava / documentación / Capítulo 5: Mapeo objeto/relacional XML (clásico)

1.Introducción XML | 2.Modelo XML | 3.Vista XML | 4.Tab XML | 5.Mapeo XML | 6.Aspectos XML

Tabla de contenidos

Capítulo 5: Mapeo objeto/relacional XML (clásico)
Mapeo de entidad
Mapeo propiedad
Mapeo referencia
Mapeo propiedad multiple
Mapeo de referencias a agregados
Mapeo de agregados usados en colecciones
Conversores por defecto
Mapeo por defecto (nuevo en v2.1.3)
Filosofia del mapeo objeto-relacional
Con el mapeo objeto relacional declaramos en que tablas y columnas de nuestra base de datos relacional se guarda la información de nuestro componente.
Para los que estén familiarizado con herramientas O/R decir que esta información se usa para generar el código y archivos xml necesarios para el mapeo. Actualmente se genera código para:
Para los que no estén familiarizados con herramientas O/R decir que una herramienta de este tipo nos permite trabajar con objetos, en vez de con tablas y columnas y genera automáticamente el código SQL necesario para leer y actualizar la base de datos.
OpenXava genera un conjunto de clases java que representa la capa del modelo de nuestra aplicación (los conceptos de negocio con sus datos y funcionalidad). Nosotros podemos usar estos objetos directamente sin necesidad de acceder directamente a la base de datos con SQL, pero para eso tenemos que definir con precisión como se mapean nuestras clases a nuestras tablas, y eso es lo que se hace en la parte del mapeo.

Mapeo de entidad

La sintaxis para mapear la entidad principal es:
<mapeo-entidad tabla="tabla">             <!-- 1 -->
    <mapeo-propiedad ... /> ...           <!-- 2 -->
    <mapeo-referencia ... /> ...          <!-- 3 -->
    <mapeo-propiedad-multiple ... /> ...  <!-- 4 -->
</mapeo-entidad>
  1. tabla (obligado): Para relacionar la entidad principal del componente con esa tabla.
  2. mapeo-propiedad (varios, opcional): Mapea una propiedad con una columna de la tabla de base de datos.
  3. mapeo-referencia (varios, opcional): Mapea una referencia con una o más columna de la tabla de base de datos.
  4. mapeo-propiedad-multiple (varios, opcional): Mapea una propiedad con varias columnas de la tabla de base de datos. Para cuando propiedad corresponde a varias columnas.
Un ejemplo sencillo de mapeo puede ser:
<mapeo-entidad tabla="XAVATEST@separator@TIPOALBARAN">
    <mapeo-propiedad propiedad-modelo="codigo" columna-tabla="CODIGO"/>
    <mapeo-propiedad propiedad-modelo="descripcion" columna-tabla="DESCRIPCION" />
</mapeo-entidad>
Nada más fácil.
Vemos como en el nombre de tabla la ponemos calificada (con el nombre de colección/esquema delante). También vemos que como separador en lugar de un punto ponermos @separator@, esto es útil porque podemos dar valor a separator en nuestro build.xml y así una misma aplicación puede ir contra bases de datos que soportan y no soportan las colecciones o esquemas.

Mapeo propiedad

La sintaxis para mapear una propiedad es:
<mapeo-propiedad
    propiedad-modelo="propiedad"  <!-- 1 -->
    columna-tabla="columna"       <!-- 2 -->
    tipo-cmp="tipo"               <!-- 3 -->
    formula="formula">            <!-- 4  New in v3.1.4 -->
    <conversor ... />             <!-- 5 -->
</mapeo-propiedad>
  1. propiedad-modelo (obligada): El nombre de una propiedad definida en la parte del modelo.
  2. columna-tabla (opcional desde v3.1.4): Nombre de la columna de la tabla. Si se omite se asume el nombre de la propiedad.
  3. tipo-cmp (opcional): Indica el tipo Java que usará internamente nuestro objeto para guardar la propiedad. Esto nos permite usar tipos Java más cercanos a lo que tenemos en la base de datos sin ensuciar nuestro modelo. Se suele usar en combinación con un conversor.
  4. formula (opcional): (Nuevo en v3.1.4) Para calcular el valor de la propiedad usando la base de datos. Tiene que ser un fragmento válido de SQL. No funciona con EntityBeans CMP2.
  5. conversor (uno, opcional): Permite indicar nuestra propia lógica para convertir del tipo usado en Java al tipo de la db.
Hemos visto ya ejemplos de un mapeo sencillo de propiedad con columna. Un caso más avanzado sería el uso de un conversor. Un conversor se usa cuando el tipo de Java y el tipo de la base de datos no coincide, en ese caso usar un conversor es una buena idea. Por ejemplo supongamos que en la base de datos el código postal es de tipo VARCHAR mientras que en Java nos interesa que sea un int. Un int de Java no se puede asignar directamente a una columna VARCHAR de base de datos, pero podemos poner un conversor para convertir ese int en un String. Veamos:
<mapeo-propiedad
    propiedad-modelo="codigoPostal"
    columna-tabla="CP"
    tipo-cmp="String">
    <conversor clase="org.openxava.converters.IntegerStringConverter"/>
</mapeo-propiedad>
Con tipo-cmp indicamos el tipo al que convertirá nuestro conversor y es el tipo que tendrá el atributo interno de la clase generada, ha de ser un tipo cercano (asignable directamente con JDBC) al de la columna de la tabla.
El código del conversor será:
package org.openxava.converters;
 
/**
 * In java an int and in database a String.
 *
 * @author Javier Paniza
 */
public class IntegerStringConverter implements IConverter {      // 1
 
    private final static Integer ZERO = new Integer(0);
 
    public Object toDB(Object o) throws ConversionException {    // 2
        return o==null?"0":o.toString();
    }
 
    public Object toJava(Object o) throws ConversionException {  // 3
        if (o == null) return ZERO;
        if (!(o instanceof String)) {
            throw new ConversionException("conversion_java_string_expected");
        }
        try {
            return new Integer((String) o);
        }
        catch (Exception ex) {
            ex.printStackTrace();
            throw new ConversionException("conversion_error");
        }
    }
 
}
Un conversor ha de implementar IConverter (1), esto le obliga a tener un método toDB() (2), que recibe el objeto del tipo que usamos en Java (en este caso un Integer) y devuelve su representación con otro tipo más cercano a la base de datos (en este caso String y por ende asignable a una columna VARCHAR). El método toJava() tiene el cómetido contrario, coge el objeto en el formato de la base de datos y tiene que devolver un objeto del tipo que se usa en Java.
Ante cualquier problemas podemos lanzar una ConversionException.
Vemos como este conversor está en org.openxava.converters, es decir es un conversor genérico que viene incluido en la distribución de OpenXava. Otro conversor genérico bastante útil es ValidValuesLetterConverter, que permite mapear las propiedades de tipo valores-posibles. Por ejemplo podemos tener una propiedad como ésta:
<entidad>
...
    <propiedad nombre="distancia">
        <valores-posibles>
            <valor-posible valor="local"/>
            <valor-posible valor="nacional"/>
            <valor-posible valor="internacional"/>
        </valores-posibles>
    </propiedad>
...
</entidad>
Los valores-posibles generan una propiedad Java de tipo int donde el 0 se usa para indicar un valor vacío, el 1 será 'local', el 2 'nacional' y el 3 'internacional'. ¿Pero que ocurre si en la base de datos se almacena una L para local, una N para nacional y una I para internacional? Podemos hacer lo siguiente en el mapeo:
<mapeo-propiedad
    propiedad-modelo="distancia" columna-tabla="DISTANCIA" tipo-cmp="String">
    <conversor clase="org.openxava.converters.ValidValuesLetterConverter">
        <poner propiedad="letters" valor="LNI"/>
    </conversor>
</mapeo-propiedad>
Al poner 'LNI' como valor para letters, hace corresponder la L con 1, la N con 2 y la I con 3. Vemos como el que se puedan configurar propiedades del conversor (como se hacía con los calculadores, validadores, etc) nos permite hacer conversores reutilizables.

Usando el atributo formula (nuevo en v3.1.4) podemos definir un cálculo para nuestra propiedad. Este cálculo se expresa usando SQL, y es ejecutado en la propia base de datos, en vez de por Java. Simplemente hemos de escribir un fragmento válido de SQL:
<mapeo-propiedad propiedad-modelo="precioUnitarioConIVA" formula="PRECIOUNITARIO * 1.16"/>
El uso es simple. Hemos de poner el cálculo como lo hariamos si lo tuvieramos que poner en una sentencia SQL.
Las propiedades con formula son propiedades de solo lectura. Cuando el objeto es leído de la base de datos se hace el cálculo por la misma base de datos y se rellena la propiedad con el resultado.
Esto es una alternativa a las propiedades calculadas. Tiene la ventaja de que el usuario puede filtrar por esta propiedad en modo lista, y la desventaja de que hemos de usar SQL en vez de Java, y no se recalcula el valor en vivo.

Mapeo referencia

La sintaxis para mapear una referencia es:
<mapeo-referencia
    referencia-modelo="referencia"        <!-- 1 -->
>
    <detalle-mapeo-referencia ... /> ...  <!-- 2 -->
</mapeo-referencia>
  1. referencia (obligada): La referencia que se quiere mapear.
  2. detalle-mapeo-referencia (varias, obligada): Para mapear una columna de la tabla con un propiedad de la clave para obtener la referencia. Si la clave del objeto referenciado es múltiple habrá varios detalle-mapeo-referencia.
Hacer un mapeo de una referencia es sencillo. Por ejemplo si tenemos una referencia como ésta:
<entidad>
    ...
    <referencia nombre="factura" modelo="Factura"/>
    ...
</entidad>
Podemos mapearla de esta forma:
<mapeo-entidad tabla="XAVATEST@separator@ALBARAN">
    <mapeo-referencia referencia-modelo="factura">
        <detalle-mapeo-referencia
            columna-tabla="FACTURA_AÃ?O"
            propiedad-modelo-referenciado="año"/>
        <detalle-mapeo-referencia
            columna-tabla="FACTURA_NUMERO"
            propiedad-modelo-referenciado="numero"/>
    </mapeo-referencia>
    ...
</mapeo-entidad>
FACTURA_NUMERO y FACTURA_AÑO son columnas de la tabla ALBARAN que nos permiten acceder a su factura, digamos que es la clave ajena, aunque el que esté declarada como tal en la base de datos no es preceptivo. Estas columnas las tenemos que relacionar con las propiedades clave en Factura, como sigue:
<entidad>
    <propiedad nombre="año" tipo="int" clave="true" longitud="4" requerido="true">
        <calculador-valor-defecto
            clase="org.openxava.calculators.CurrentYearCalculator"/>
    </propiedad>
    <propiedad nombre="numero" tipo="int"
        clave="true"    longitud="6" requerido="true"/>
    ...
Si tenemos una referencia a un modelo cuyo clave incluye referencia para definirlo en el mapeo lo hacemos como sigue:
<mapeo-referencia referencia-modelo="albaran">
    <detalle-mapeo-referencia
        columna-tabla="ALBARAN_FACTURA_AÑO"
        propiedad-modelo-referenciado="factura.año"/>
    <detalle-mapeo-referencia
        columna-tabla="ALBARAN_FACTURA_NUMERO"
        propiedad-modelo-referenciado="factura.numero"/>
    <detalle-mapeo-referencia
        columna-taba="ALBARAN_TIPO"
        propiedad-modelo-referenciado="tipo.codigo"/>
    <detalle-mapeo-referencia
        columna-tabla="ALBARAN_NUMERO"
        propiedad-modelo-referenciado="numero"/>
</mapeo-referencia>
Como se ve al indicar la propiedad del modelo referenciado podemos calificarla.
También es posible usar conversores cuando mapeamos referencias:
<mapeo-referencia referencia="permisoConducir">
    <detalle-mapeo-referencia
        columna-tabla="PERMISOCONDUCIR_TIPO"
        propiedad-modelo-referenciado="tipo"
        tipo-cmp="String">  <!-- 1  En esta caso esta linea puede ser omitida -->
        <conversor clase="org.openxava.converters.NotNullStringConverter"/>  <!-- 2 -->
    </detalle-mapeo-referencia>
    <detalle-mapeo-referencia
        columna-tabla="PERMISOCONDUCIR_NIVEL"
        propiedad-modelo-referenciado="nivel"/>
</mapeo-referencia>
Podemos usar el conversor igual que en el caso de una propiedad simple (1). La diferencia en el caso de las referencias es que si no asignamos conversor no se usa ningún conversor por defecto, esto es porque aplicar de forma indiscriminada conversores sobre información que se usa para buscar puede ser problemático. Podemos usar tipo-cmp (1) (nuevo en v2.0) para indicar que tipo para el atributo es usado internamente en nuestro objeto para almacenar el valor. Esto nos permite usar un tipo Java más cercano al de la base de datos; tipo-cmp no es necesario si el tipo de la base de datos es compatible con el tipo Java.

Mapeo propiedad multiple

Con <mapeo-propiedad-multiple/> podemos hacer que varias columnas de la tabla de base de datos correspondan a una propiedad en Java. Esto es útil, por ejemplo cuando tenemos propiedades cuyo tipo Java son clases definidas por nosotros que tienen a su vez varias propiedades susceptibles de ser almacenadas, y también se usa mucho cuando nos enfrentamos a esquemas de bases de datos legados.
La sintaxis de este tipo de mapeo es:
<mapeo-propiedad-multiple
    propiedad-modelo="propiedad"  <!-- 1 -->
>
    <conversor ... />             <!-- 2 -->
    <campo-cmp ... /> ...         <!-- 3 -->
</mapeo-propiedad-multiple>
  1. propiedad-modelo (obligada): Nombre de la propiedad que se quiere mapear.
  2. conversor (uno, obligado): Clase con la lógica para hacer la conversión de Java a base de datos y viceversa. Ha de implementar IMultipleConverter.
  3. campo-cmp (varios, obligado): Hace corresponder cada columna de la base de datos con una propiedad del conversor.
Un ejemplo típico sería usar el conversor genérico Date3Converter, que permite almacenar en la base de datos 3 columnas y en Java una propiedad java.util.Date.
<mapeo-propiedad-multiple propiedad-modelo="fechaEntrega">
    <conversor clase="org.openxava.converters.Date3Converter"/>
    <campo-cmp
        propiedad-conversor="day" columna-tabla="DIAENTREGA" tipo-cmp="int"/>
    <campo-cmp
        propiedad-conversor="month" columna-tabla="MESENTREGA" tipo-cmp="int"/>
    <campo-cmp
        propiedad-conversor="year" columna-tabla="AÑOENTREGA" tipo-cmp="int"/>
</mapeo-propiedad-multiple>
DIAENTREGA, MESENTREGA y AÑOENTREGA son las tres columnas que en la base de datos guardan la fecha de entrega, y day, month y year son propiedades que podemos encontrar en Date3Converter. Y aquí Date3Converter:
package org.openxava.converters;
 
import java.util.*;
 
import org.openxava.util.*;
 
/**
 * In java a <tt>java.util.Date</tt> and in database 3 columns of
 * integer type. <p>
 *
 * @author Javier Paniza
 */
public class Date3Converter implements IMultipleConverter {           // 1
 
    private int day;
    private int month;
    private int year;
 
    public Object toJava() throws ConversionException {               // 2
        return Dates.create(day, month, year);
    }
 
    public void toDB(Object objetoJava) throws ConversionException {  // 3
        if (objetoJava == null) {
            setDay(0);
            setMonth(0);
            setYear(0);
            return;
        }
        if (!(objetoJava instanceof java.util.Date)) {
            throw new ConversionException("conversion_db_utildate_expected");
        }
        java.util.Date fecha = (java.util.Date) objetoJava;
        Calendar cal = Calendar.getInstance();
        cal.setTime(fecha);
        setDay(cal.get(Calendar.DAY_OF_MONTH));
        setMonth(cal.get(Calendar.MONTH) + 1);
        setYear(cal.get(Calendar.YEAR));
    }
 
    public int getYear() {
        return year;
    }
 
    public int getDay() {
        return day;
    }
 
    public int getMonth() {
        return month;
    }
 
    public void setYear(int i) {
        year = i;
    }
 
    public void setDay(int i) {
        day = i;
    }
 
    public void setMonth(int i) {
        month = i;
    }
 
}
El conversor tiene que implementar IMultipleConverter (1) lo que le obliga a tener un método toJava() (2) que a partir de lo contenido en sus propiedades (en este caso year, month y day) ha de devolver un objeto Java con el valor de la propiedad mapeada (en nuestro ejemplo el valor de la fechaEntrega); y el método toDB() (3) que recibe el valor de la propiedad Java (el de fechaEntrega) y tiene que desglosarlo para que se queda almacenado en las propiedades del conversor (year, month y day).

Mapeo de referencias a agregados

Una referencia a un agregado contiene información que en el modelo relacional se guarda en la misma tabla que la entidad principal. Por ejemplo si tenemos un agregado Direccion asociado a un Cliente, los datos de la dirección se guardan en la misma tabla que los del cliente. ¿Cómo se expresa eso en OpenXava? Es muy sencillo. En el modelo nos encontramos:
<entidad>
    ...
    <referencia nombre="direccion" modelo="Direccion" requerido="true"/>
    ...
</entidad>
 
<agregado nombre="Direccion">
    <implementa interfaz="org.openxava.test.ejb.IConMunicipio"/>
    <propiedad nombre="calle" tipo="String" longitud="30" requerido="true"/>
    <propiedad nombre="codigoPostal" tipo="int" longitud="5" requerido="true"/>
    <propiedad nombre="municipio" tipo="String" longitud="20" requerido="true"/>
    <referencia nombre="provincia" requerido="true"/>
</agregado>
Sencillamente una referencia a un agregado, y para mapearlo lo hacemo así:
<mapeo-entidad tabla="XAVATEST@separator@CLIENTE">
    ...
    <mapeo-propiedad propiedad-modelo="direccion_calle" columna-tabla="CALLE"/>
    <mapeo-propiedad
        propiedad-modelo="direccion_codigoPostal"
        columna-tabla="CP" tipo-cmp="String">
        <conversor clase="org.openxava.converters.IntegerStringConverter"/>
    </mapeo-propiedad>
    <mapeo-propiedad
        propiedad-modelo="direccion_municipio" columna-tabla="MUNICIPIO"/>
    <mapeo-referencia referencia-modelo="direccion_municipio">
        <detalle-mapeo-referencia
            columna-tabla="PROVINCIA" propiedad-modelo-referenciado="codigo"/>
    </mapeo-referencia>
</mapeo-entidad>
Vemos como los miembros del agregado se mapean en el mapeo de la entidad que lo contienen, solo que ponemos como prefijo el nombre de la referencia a agregado con un subrayado (en esta caso direccion_). Podemos observar como podemos mapear referencias y propiedades y usar conversores.

Mapeo de agregados usados en colecciones

En el caso de que tengamos una colección de agregados, supongamos las líneas de una factura, obviamente la información de las líneas se guarda en una tabla diferente que la información de cabecera de la factura. En este caso los agregados han de tener su propio mapeo. Veamos el ejemplo de las líneas de una factura.
En la parte de modelo del componente Factura tenemos:
<entidad>
    ...
    <coleccion nombre="lineas" minimo="1">
        <referencia modelo="LineaFactura"/>
    </coleccion>
    ...
</entidad>
 
<agregado nombre="LineaFactura">
    <propiedad nombre="oid" tipo="String" clave="true" oculta="true">
        <calculador-valor-defecto
            clase="org.openxava.test.calculadores.CalculadorOidLineaFactura"
            al-crear="true"/>
    </propiedad>
    <propiedad nombre="tipoServicio">
        <valores-posibles>
            <valor-posible valor="especial"/>
            <valor-posible valor="urgente"/>
        </valores-posibles>
    </propiedad>
    <propiedad nombre="cantidad" tipo="int" longitud="4" requerido="true"/>
    <propiedad nombre"precioUnitario" estereotipo="DINERO" requerido="true"/>
    <propiedad nombre="importe" estereotipo="DINERO">
        <calculador clase="org.openxava.test.calculadores.CalculadorImporteLinea">
            <poner propiedad="precioUnitario"/>
            <poner propiedad="cantidad"/>
        </calculador>
    </propiedad>
    <referencia modelo="Producto" requerido="true"/>
    <propiedad nombre="fechaEntrega" tipo="java.util.Date">
        <calculador-valor-defecto
            clase="org.openxava.calculators.CurrentDateCalculator"/>
    </propiedad>
    <referencia nombre="vendidoPor" modelo="Comercial"/>
    <propiedad nombre="observaciones" estereotipo="MEMO"/>
</agregado>
Vemos una colección de LineaFactura que es un agregado, LineaFactura se ha de mapear así:
<mapeo-agregado agregado="LineaFactura" tabla="XAVATEST@separator@LINEAFACTURA">
    <mapeo-referencia referencia="factura">  <!-- 1 -->
        <detalle-mapeo-referencia
            columna-tabla="FACTURA_AÑO"
            propiedad-modelo-referenciado="año"/>
        <detalle-mapeo-referencia
            columna-tabla="FACTURA_NUMERO"
            propiedad-modelo-referenciado="numero"/>
    </mapeo-referencia>
    <mapeo-propiedad propiedad-modelo="oid" columna-tabla="OID"/>
    <mapeo-propiedad propiedad-modelo="tipoServicio" columna-tabla="TIPOSERVICIO"/>
    <mapeo-propiedad
        propiedad-modelo="precioUnitario" columna-tabla="PRECIOUNITARIO"/>
    <mapeo-propiedad propiedad-modelo="cantidad" columna-tabla="CANTIDAD"/>
    <mapeo-referencia referencia="producto">
        <detalle-mapeo-referencia
            columna-tabla="PRODUCTO_CODIGO"
            propiedad-modelo-referenciado="codigo"/>
    </mapeo-referencia>
    <mapeo-propiedad-multiple propiedad-modelo="fechaEntrega">
        <conversor clase="org.openxava.converters.Date3Converter"/>
        <campo-cmp
            propiedad-conversor="day"
            columna-tabla="DIAENTREGA" tipo-cmp="int"/>
        <campo-cmp
            propiedad-conversor="month"
            columna-tabla="MESENTREGA" tipo-cmp="int"/>
        <campo-cmp
            propiedad-conversor="year"
            columna-tabla="AÑOENTREGA" tipo-cmp="int"/>
    </mapeo-propiedad-multiple>
    <mapeo-referencia referencia="vendidoPor">
        <detalle-mapeo-referencia
            columna-tabla="VENDIDOPOR_CODIGO"
            propiedad-modelo-referenciado="codigo"/>
    </mapeo-referencia>
    <mapeo-propiedad
        propiedad-modelo="observaciones" columna-tabla="OBSERVACIONES"
</aggregate-mapping>
Los mapeos de agregado se ponen a continuación del mapeo de entidad, y debe haber tantos como agregados usados en colecciones. El mapeo de un agregado tiene exactamente las misma posibilidades que el mapeo de entidad ya visto, con la salvedad de que necesitamos definir el mapeo de la referencia al objeto contenedor aunque ella no esté en el modelo. Esto es aunque nosotros no definamos en LineaFactura una referencia a Factura, el OpenXava la añade automáticamente y por ende nosotros en el mapeo tenemos que reflejarlo (1).

Conversores por defecto

Vemos como podemos declarar un conversor a cada mapeo de propiedad. Pero ¿qué pasa cuando no declaramos conversor? En realidad en OpenXava todas las propiedades (a excepción de las que son clave) tienen un conversor aunque no se indique explícitamente. Los conversores por defecto están definidos en el archivo OpenXava/xava/default-converters.xml, que tiene un contenido como este:
<?xml version = "1.0" encoding = "ISO-8859-1"?>
 
<!DOCTYPE converters SYSTEM "dtds/converters.dtd">
 
<!--
In your project use the name 'converters.xml' or 'conversores.xml'
-->
 
<converters>
 
    <for-type type="java.lang.String"
        converter-class="org.openxava.converters.TrimStringConverter"
        cmp-type="java.lang.String"/>
 
    <for-type type="int"
        converter-class="org.openxava.converters.IntegerNumberConverter"
        cmp-type="java.lang.Integer"/>
 
    <for-type type="java.lang.Integer"
        converter-class="org.openxava.converters.IntegerNumberConverter"
        cmp-type="java.lang.Integer"/>
 
    <for-type type="boolean"
        converter-class="org.openxava.converters.Boolean01Converter"
        cmp-type="java.lang.Integer"/>
 
    <for-type type="java.lang.Boolean"
        converter-class="org.openxava.converters.Boolean01Converter"
        cmp-type="java.lang.Integer"/>
 
    <for-type type="long"
        converter-class="org.openxava.converters.LongNumberConverter"
        cmp-type="java.lang.Long"/>
 
    <for-type type="java.lang.Long"
        converter-class="org.openxava.converters.LongNumberConverter"
        cmp-type="java.lang.Long"/>
 
    <for-type type="java.math.BigDecimal"
        converter-class="org.openxava.converters.BigDecimalNumberConverter"
        cmp-type="java.math.BigDecimal"/>
 
    <for-type type="java.util.Date"
        converter-class="org.openxava.converters.DateUtilSQLConverter"
        cmp-type="java.sql.Date"/>
 
</converters>
Si usamos una propiedad de un tipo que no tenemos definido aquí por defecto se le asigna el conversor NoConversionConverter, que es un conversor tonto que no hace nada.
En el caso de las propiedades clave no se asigna conversor en absoluto, aplicar conversor a las propiedades claves puede ser problemático en ciertas circunstancias, pero si aun así lo queremos podemos declarar explicitamente en nuestro mapeo un conversor para una propiedad clave y se le aplicará.
Si queremos modificar el comportamiento de los conversores por defecto para nuestra aplicación no debemos modificar este archivo sino crear uno llamado converters.xml o conversores.xml en el directorio xava de nuestro proyecto. Podemos asignar también conversor por defecto a un estereotipo (usando <para-estereotipo/> o <for-stereotype/>).

Mapeo por defecto (nuevo en v2.1.3)

Desde la versión 2.1.3 OpenXava permite definir componentes sin mapeo, y se asume un mapeo por defecto para él. Por ejemplo, podemos escribir:
<?xml version="1.0" encoding="ISO-8859-1"?>
 
<!DOCTYPE componente SYSTEM "dtds/componente.dtd">
 
<componente nombre="Alumno">
 
    <entidad>
        <propiedad nombre="numero" tipo="int" clave="true"
            longitud="2" requerido="true"/>
        <propiedad nombre="nombre" tipo="String"
            longitud="40" requerido="true"/>
        <referencia nombre="profesor"/>
    </entidad>
 
</componente>
Este componente está mapeado a la tabla Alumno, y las propiedades numero y nombre están mapeadas a las columnas numero y nombre. La referencia profesor está mapeada a una columna llamada profesor_numero (si la propiedad clave de Profesor se llama numero).

Filosofia del mapeo objeto-relacional

OpenXava ha nacido y se ha desarrollado en un entorno en el que nos hemos visto obligados a trabajar con bases de datos existentes sin poder modificar su estructura, esto hace que:
Otras característica importante del mapeo de OpenXava es que las aplicaciones son 100% portables entre JBoss CMP2 y Websphere CMP2 sin tener que reescribir nada por parte del desarrollador. Además, la portabilidad entre Hibernate, JPA y EJB2 de una aplicación es muy alta, los mapeos y todos los controladores automáticos son portables al 100%, obviamente el código propio escrito con EJB2, JPA o Hibernate no lo es tanto.