Skip to content

Instantly share code, notes, and snippets.

@iamnoah
Created December 8, 2009 20:42
Show Gist options
  • Save iamnoah/251982 to your computer and use it in GitHub Desktop.
Save iamnoah/251982 to your computer and use it in GitHub Desktop.
DWR converter for Grails ORM classes. Uses the hasMany map to determine the type of collections so we can convert them inbound.
package com.noahsloan.grails.dwr;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import org.directwebremoting.convert.BeanConverter;
import org.directwebremoting.convert.CollectionConverter;
import org.directwebremoting.extend.InboundContext;
import org.directwebremoting.extend.Property;
import org.directwebremoting.extend.TypeHintContext;
import org.directwebremoting.util.Logger;
import com.sun.tools.jdi.LinkedHashMap;
/**
* Converter for Grails ORM classes. Uses the hasMany map to determine the type
* of collections so we can convert them inbound.
*
* @author noah
*
*/
@SuppressWarnings("unchecked")
public class DwrGormConverter extends BeanConverter {
private static final Logger LOG = org.directwebremoting.util.Logger
.getLogger(DwrGormConverter.class);
protected TypeHintContext createTypeHintContext(InboundContext inctx,
final Property property) {
// check collections
if (Collection.class.isAssignableFrom(property.getPropertyType())) {
final Class type = getCollectionType(property);
if (type != null) {
return createHint(property.getSetter(), type);
}
}
return super.createTypeHintContext(inctx, property);
}
/**
* Pulled out for readability. Creates a type hint for the
* {@link CollectionConverter} with the given type.
*
* @param setter TODO is this necessary?
* @param type
* @return
*/
protected TypeHintContext createHint(final Method setter,
final Class type) {
return new TypeHintContext(converterManager, setter, 0) {
public TypeHintContext createChildContext(int newParameterNumber) {
return new TypeHintContext(converterManager, setter, 0) {
public Class getExtraTypeInfo() {
return type;
}
};
}
};
}
protected static Map<Class, Map<String, Class>> _cache = new LinkedHashMap();
/**
* Determines the type of the collection by examining the declaring class'
* static hasMany property.
*
* @param property
* @return the type of the elements of the collection property.
*/
protected Class getCollectionType(Property property) {
// determine the class the collection is attached to by examining
// the setter (which is the domain class)
Method setter = property.getSetter();
if (setter == null) {
// XXX in theory this should not happen because BeanConverter should
// always provide PropertyDescriptionPropertys
LOG.error("setter for "
+ property.getName() + " is null."
+ " Property is not a PropertyDescriptionProperty.");
return null;
}
Class gormType = setter.getDeclaringClass();
if (_cache.containsKey(gormType)) {
Map<String, Class> map = _cache.get(gormType);
return map == null ? null : map.get(property.getName());
}
try {
Field field = gormType.getDeclaredField("hasMany");
Map<String, Class> map = null;
if (field != null) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
map = ((Map<String, Class>) field.get(null));
}
_cache.put(gormType, map);
return map == null ? null : map.get(property.getName());
} catch (Exception e) {
LOG.error("Exception getting GORM collection type info.", e);
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment