For our example, we'll create a new datatype called SixDecimal, which stores a numerical value with 6 digit max precision. This class is essentially no different than BigDecimal, however we need to create a new datatype because UserTypes are associated with a specific class, and we want only to translate our new SixDecimal datatype using our UserType, not all BigDecimals in general.
class SixDecimal extends BigDecimal {
public SixDecimal (Double d) { super(d) }
public SixDecimal (java.math.BigDecimal bd) { super(bd.doubleValue()) }
}
Next we create the Hibernate UserType. The interface methods are described in the documentation. Of note is the SQL_TYPES definition. Originally, we intended to use Types.DECIMAL, as this translates into NUMBER(x,d) in Oracle, and would allow us to specify precision at the db level. However, this interferes with the Grails generation of the table for the domain class, so we resort to using Types.FLOAT, and handle the setting of precision in the custom property editor.
class SixDecimalUserType implements org.hibernate.usertype.UserType {
private static final SQL_TYPES = [Types.FLOAT] as int[]
public Object assemble(Serializable cached, Object owner) { cached }
public Object deepCopy(Object o) { o }
public Serializable disassemble(Object value) { value }
public boolean equals(Object x, Object y) { x.equals(y) }
public int hashCode(Object o) { o.hashCode() }
public boolean isMutable() { false }
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) {
def result = rs.getBigDecimal(names[0])
if (result) { return new SixDecimal((java.math.BigDecimal)result) }
else {return null}
}
public void nullSafeSet(PreparedStatement st, Object value, int index) {
st.setBigDecimal(index, (java.math.BigDecimal)value)
}
public Object replace(Object original, Object target, Object owner) { original }
public Class returnedClass() { SixDecimal }
public int[] sqlTypes() { SQL_TYPES }
}
Finally, we register our UserType with our new datatype. This can be accomplished system wide in Config.groovy
grails.gorm.default.mapping = {
'user-type'( type:SixDecimalUserType, class:SixDecimal )
}
or by field within a domain class
class MyDomain {
static mapping = {
interestRate type:SixDecimalUserType
}
SixDecimal interestRate
}
This is definitely where to start on this subject.
ReplyDelete