User type mappings
Since 3.2.2.
Sometimes we would like to have some custom Java type as a CMP field but store it in the database column as, for example, some kind of numerical or string value.
An example could be a constant enumeration colors. We have a CMP field of type ColorEnum which can have of the three possible values ColorEnum.RED, ColorEnum.GREEN or ColorEnum.BLUE.
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.test.cmp2.enum.ejb;
/**
* Enum implementations for colors.
*
* @author <a href="mailto:alex@jboss.org">Alex Loubyansky</a>
*/
public abstract class ColorEnum
{
private static int nextOrdinal = 0;
// Constants
private static final ColorEnum VALUES[] = new ColorEnum[3];
public static final ColorEnum RED = new Red("RED");
public static final ColorEnum GREEN = new Green("GREEN");
public static final ColorEnum BLUE = new Blue("BLUE");
// Attributes
private final Integer ordinal;
private final transient String name;
// Constructor
private ColorEnum(String name)
{
this.name = name;
this.ordinal = new Integer(nextOrdinal++);
VALUES[ordinal.intValue()] = this;
}
// Public
public Integer getOrdinal()
{
return ordinal;
}
public String toString()
{
return name;
}
public ColorEnum valueOf(int ordinal)
{
return VALUES[ordinal];
}
// Inner
private static final class Red extends ColorEnum
{
public Red(String name)
{
super(name);
}
}
private static final class Green extends ColorEnum
{
public Green(String name)
{
super(name);
}
}
private static final class Blue extends ColorEnum
{
public Blue(String name)
{
super(name);
}
}
}
But we want to store the field of ColorEnum type as interger in the database not a serialized Java object. We can do it by implementing the following interface:
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.ejb.plugins.cmp.jdbc;
/**
* Generally, implementations of this interface map instances of one Java type
* into instances of another Java type.
* Mappers can be used in cases when instances of "enum" types are used as CMP
* field values. In this case, a mapper represents a mediator and translates
* instances of "enum" to some id when the field is stored
* and back from id to "enum" instance when the data is loaded.
*
* @author <a href="mailto:alex@jboss.org">Alex Loubyansky</a>
*/
public interface Mapper
{
/**
* This method is called when CMP field is stored.
* @param fieldValue - CMP field value
* @return column value.
*/
Object toColumnValue(Object fieldValue);
/**
* This method is called when CMP field is loaded.
* @param columnValue - loaded column value.
* @return CMP field value.
*/
Object toFieldValue(Object columnValue);
}
An implementation for ColorEnum could be
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.test.cmp2.enum.ejb;
import org.jboss.ejb.plugins.cmp.jdbc.Mapper;
/**
* org.jboss.ejb.plugins.cmp.jdbc.Mapper implementation.
* Maps ColorEnum to Integer.
*
* @author <a href="mailto:alex@jboss.org">Alex Loubyansky</a>
*/
public class ColorMapper
implements Mapper
{
public Object toColumnValue(Object fieldValue)
{
return ((ColorEnum)fieldValue).getOrdinal();
}
public Object toFieldValue(Object columnValue)
{
int ordinal = ((Integer)columnValue).intValue();
return ColorEnum.RED.valueOf(ordinal);
}
}
Now, in jbosscmp-jdbc.xml we specify that we want to use our wrapper
<user-type-mappings> <user-type-mapping> <java-type>org.jboss.test.cmp2.enum.ejb.ColorEnum</java-type> <mapped-type>java.lang.Integer</mapped-type> <mapper>org.jboss.test.cmp2.enum.ejb.ColorMapper</mapper> </user-type-mapping> </user-type-mappings>
Now all the fields of type ColorEnum will use the ColorMapper.
The DTD for user-type-mapping in jbosscmp-jdbc_3_2.dtd is
<!-- Defines a mapping of a user type to a column providing a mapper class. Mapper is like a mediator: when storing, it takes an instance of the user type and translates it to a column value; when loading, it takes a column value and translates it to an instance of the user type. --> <!ELEMENT user-type-mapping (java-type, mapped-type, mapper, check-dirty-after-get?, state-factory?)>
Comments