开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜