Grails bind collection enum
In my grails app, I have this enum:
public enum RelationshipStatus{
Single_Never_Married,
Separated,
Divorced,
Widowed;
}
I've defined this command object:
class MyCommand {
List<RelationshipStatus> relationshipStatuses
}
which I use in one of my controller actions
def myAction = {MyCommand myCommand ->
}
when I submit a request to this action with parameters
user.relationshipStatuses=Separated&user.relationshipStatuses=Divorced
I expect that myCommand.relationshipStatuses
will contain RelationshipStatus.Separated
and RelationshipStatus.Divorced
, but in fact it is null.
My understanding is t开发者_运维技巧hat Grails automatically performs request param -> enum conversion based on the enum's name. Just it case it doesn't, I tried defining a property editor that does this conversion:
class RelationshipStatusEnumEditor extends PropertyEditorSupport {
public String getAsText() {
value.name()
}
public void setAsText(String text) {
RelationshipStatus.valueOf(text)
}
}
I registered this editor with Grails/Spring and tried again, but the result was the same. Is it possible to bind request parameters to a Collection of Enum?
Using the databinder introduced in Grails 2.3, I came up with the following solution for converting request params to collection of enums. For example, given these enums
enum Gender {
MALE, FEMALE
}
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
and this command object
class MyCommand {
Collection<Gender> genders
Collection<Season> seasons
}
and assume we want to convert strings like "MALE,FEMALE"
and "SPRING,SUMMER,WINTER"
to the corresponding enum collections. Firstly, provide an implementation of FormattedValueConverter
that does the conversion
class EnumCollectionConverter implements FormattedValueConverter {
/**
* To make other enums bindable, just add them to this list
*/
private static final List<Class<Enum>> convertableEnums = [Gender, Season]
@Override
Object convert(value, String format) {
Class<Enum> targetEnumClass = convertableEnums.find { it.simpleName == format }
if (targetEnumClass) {
List<String> enumConstantNames = value.toString().tokenize(',')
return enumConstantNames.collect { targetEnumClass.valueOf(it) }
}
value
}
@Override
Class<?> getTargetType() {
// this class converts to a Collection<T extends Enum<T>> but the return value
// of this method can't be any more specific than Collection due to type erasure
Collection
}
}
Then register EnumCollectionConverter
as a Spring bean in resources.groovy
- it doesn't matter what name you choose for the bean. Then to use the class above to convert a comma-separated string to an num collection, annotate the relevant properties with
class MyCommand {
@BindingFormat('Gender')
Collection<Gender> genders
@BindingFormat('Season')
Collection<Season> seasons
}
The value passed to the @BindingFormat
should be the simple name of the enum type that will be stored in the bound collection.
As I know grails isn't filling List properties by default, if it's empty. Only if it's already exists, and indexes of items are passed.
Try to define this property as:
import org.apache.commons.collections.ListUtils
import org.apache.commons.collections.Factory
class MyCommand {
List<RelationshipStatus> relationshipStatuses = ListUtils.lazyList([],{new RelationshipStatus()} as Factory)
}
and submit parameters as:
user.relationshipStatuses[0]=Separated&user.relationshipStatuses[1]=Divorced
精彩评论