Monday, February 22, 2010

Grails-Hibernate Custom Data Type Mapping

Since the underlying ORM technology used by Grails is Hibernate, it is possible to manually specify how to persist datatypes by using Hibernate's UserType interface -- the class that establishes how to translates between a Java object and the db. This ability, in combination with custom property editors, provides a simple method of saving information from UI text input to domain objects to db and back.

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
}

Tuesday, February 16, 2010

Grails - XML Conversion

Grails provides some effortless features for converting objects into XML, but some care is necessary when using them.

By default, the XML representation of an object is shallow - this means any reference to another domain object will be represented by the id in the xml document. If the xml document should contain the full object tree, a flag in the converter needs to be set.

Adding the following line to Config.groovy will set the default for the system
grails.converters.xml.default.deep = true

or if you prefer, you can do the same thing programatically
grails.converters.XML.use('deep')

in either case, you can test it out with the following code
def converter = new grails.converters.XML(myInstance)
converter.render(new java.io.FileWriter("c:\\output.xml"))
// or
def xmlStr = myInstance as XML


One issue we had with deep converters was that it was including too much information - our User domain class contained a (cleartext) password field which was being displayed in the resulting xml.

We can customize the behavior for transforming an object into xml by using the registerObjectMarshaller method. This method is passed a class name and a closure which handles writing the XML output. The closure has implicit access to both the instance of the encountered class and the converter used to transform it.
class User {
String login
String name
String password
}

def converter = new XML(aUser)
converter.registerObjectMarshaller(User, {user, conv ->
conv.build {
login(user.login)
name(user.name)
}
})

or you could set the converter for the entire system by putting the same code in Bootstrap.groovy
grails.converters.XML.registerObjectMarshaller(User) { user, converter ->
// same implementation as above...
}

Monday, February 15, 2010

Input for One-to-Many Relationships

One of the requirements we have on this project is to have a dynamic list of values that another domain object has a relationship with - the parent domain object would have a list of selected child values. While this could be accomplished relatively easily using multiple select boxes, things get a little more complicated when each selected value has a separate field associated with it.

Now, that wasn't exactly the most coherent explanation of the problem, so let's have an example. Suppose we have a 401k management system that has allows the user to choose among a list of available funds, and a percentage to allocate to each selected fund. All input should be present on a single page.

The list for available funds is dynamic, so it has its own domain class (and default generated grails pages). It also doesn't make sense to have a field for allocation % to this domain class, as every user would have a different percentage.
class Fund {
String name
BigDecimal netAssetValue
}


We solve the problem of where to put the allocation percentage by creating a second domain class which effectively maps a Fund with a percent value. We also establish the one-to-many relationship between this new class our main domain class.
class SelectedFund {
static belongsTo = [portfolio:Portfolio]

Fund fund
Double allocationPercentage

static constraints = {
fund(nullable:false)
allocationPercentage(nullable:false, min:0d)
}
}


We complete the one-to-many relationship in our main domain Portfolio class
class Portfolio {
static hasMany = [selectedFund:SelectedFund]

String name
String ssn
BigDecimal balance

static constraints = {
balance(nullable:false, min:0d)
}
}


Simple enough, but now comes a second problem - tying into the Grails validation and data binding framework. We want the validations to kick off for both the Portfolio class and SelectedFund classes. We also would like the nice highlighting of errored fields that Grails provides. Unfortunately, this is easier said than done, and manual work is required both on the controller and on the gsp side.

First, the controller. There is no automatic way to construct our SelectedFund objects, so this is our first task. We can imagine the UI as a checkbox for each Fund and an associated textfield for the allocation value.

The first step is to clear the portfolio object of any previously SelectedFunds. Note the double loop - we cannot simply iterate over the selectedFund and remove them, as that causes a ConcurrentModification exception. It appears the underlying collection grails uses to store associations is not synchronized.
if (portfolio.selectedFund) {
for (Object fund : Fund.findAll()) {
for (Object sf : portfolio.selectedFund) {
if (sf.fund.id == fund.id) {
portfolio.removeFromSelectedFund(sf)
}
}
}
}


The second step is to collect the list of Funds selected. Note the inline comments
// if only one cbox is selected, html returns a String
// if multiple cboxes are selected, a list is returned
def idList = params['fundIds']
if (idList instanceof String) {
idList = []
idList << params['fundIds']
}

def fundList = idList.collect{Fund.get(it)}


Finally we construct a SelectedFund object for each selected Fund. The second line of the closure is particularly interesting. The right of the = is some gui Grails magic - Grails will only bind to the object parameters prefixed with the passed string. Also, by assigning object field values using '.properties' we hook into the Grails validation lifecycle.
fundList.each {
def sf = new SelectedFund(fund:it)
sf.properties = params['fundIds'+it.id]
portfolio.addToSelectedFund(sf)
}


Separate to building objects from input fields but just as important, is the validation of the SelectedFund object. I was hoping that any errors encountered during object construction would propagate to the parent Portfolio object, but this was not the case. As a result, when we save we must check each SelectedFund for errors manually. Note - this is only handles errors encountered during data binding (i.e. - passing alpha characters to a numerical field), something we'll examine in further detail later when we implement the view.
def hasErrors = false
for (Object o: portfolio.selectedFund) {
if (o.hasErrors()) {
hasErrors = true
break
}
}
return hasErrors



There are also manual steps needed on gsp side - our solution is to use a custom tag. For the sake of brevity, we will skip the code for rendering the html checkbox and textfield elements, which is relatively straightforward, if not tedious. What is interesting is handling errors encountered during validation.

From the documentation, we learn that there are two phases of validation. The first is during data binding, the second during execution of declared constraints. Unfortunately for us, errors encountered during each phase are put onto the errorList of different objects - for data binding, it is on the SelectedFund object, for constraints, it is on the Portfolio object. The manual validation we provided in the controller will ensure that all validations are performed, but some steps are necessary on the view to display errors on the UI.

Finding a binding error is simple - the following code snippet assumes the custom tag has been passed the portfolio object, and is looping over each portfolio.selectedFund object.
def itemHasErrors = false

if (aSelectedFund?.hasErrors()) { itemHasErrors = true }

Finding errors on the Portfolio bean is not as simple. We must iterate over over every error and determine if the error is for a SelectedFund. We take advantage of portfolio.errors, which is an instance of the Spring Errors interface, where each error in the list is an instance of ObjectError.
else if (portfolio.errors?.allErrors) {
for (Object o: portfolio.errors.allErrors) {
if (o.getArgument[1] == SelectedFund.class) { itemHasErrors = true }
}
}


we can now use the itemHasErrors value to determine the stylesheet class to use for the html objects.

One drawback immediately evident, is the formatting of the allocation percentage. If we had created a property editor as described in an earlier post, there is no way of using it, as we are setting the value manually in the custom tag.

Wednesday, February 10, 2010

Setting a global default for Grails date format

Simply modify ./grails-app/i18n/messages.properties

default.date.format=MM/dd/yyyy

Tuesday, February 2, 2010

Custom Grails Property Editor

Grails uses Spring's mechanism for binding the html (String) representation of an object with the object representation on the server side. I wanted all my currency fields (which are BigDecimal) to be formatted with dollar signs so I declared a CustomPropertyEditorRegistrar to modify how the BigDecimal conversion.

1. Added this to my resources.groovy
configurer(org.springframework.beans.factory.config.CustomEditorConfigurer) {
propertyEditorRegistrars = [ref("registrar")]
}

registrar(com.sungard.stallion.format.CustomPropertyEditorRegistrar)
2. Create a class that implements PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;

public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(java.math.BigDecimal.class, new CurrencyPropertyEditor());
}
}


3. It seems like this could have been done in a single step... but also define the class that the Registrar adds which implements PropertyEditor. Spring provides a helper class, PropertyEditorSupport, that the custom editor can extend:

import java.math.BigDecimal;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;

public class CurrencyPropertyEditor extends PropertyEditorSupport implements PropertyEditor {

public void setAsText(String text) {
setValue(... parsing goes here...);
}

public String getAsText() {
Object value = getValue();
if (value instanceof BigDecimal) {
return ... formatting goes here...;
}
return ("" + value);
}

}

- Ben Hidalgo

Custom Constraints

Grails constraints are short circuited when a field is declared nullable:true. This means if an attribute starts out nullable, say when the instance is in "Draft" status, but becomes required later, say when the user "Submits", the validator constraint can be used. Since validator takes a closure it can be invoked by reference or in-line. Or... pass arguments to make it more generic by wrapping the closure in a method like this:

    static Object requiredIfStatusEqual(status) {
// return a closure that will perform the validation
return {value, paf ->
// if the status is equal, the field is not required
if(status != paf.status) { return true }

// if the status is not equal, the value must be populated
return value ? true : 'default.blank.message'
}
}


Then, call the method in the static constraints block


static constraints = {
status( inList:[DRAFT, SUBMITTED])
shortTitle( validator:requiredIfStatusEqual(SUBMITTED))
}
- Ben Hidalgo

Override Default Grails Constraints

The defaults for nullable, blank and the other gorm constraints can be configured in Config.groovy by adding a snippet such as:

grails.gorm.default.constraints = {
'*'(nullable:true,blank:true)
}