Grails 将请求参数绑定到枚举

发布于 2024-08-12 07:44:03 字数 658 浏览 2 评论 0原文

我的 Grails 应用程序有大量的枚举,如下所示:

public enum Rating {
    BEST("be"), GOOD("go"), AVERAGE("av"), BAD("ba"), WORST("wo")
    final String id

    private RateType(String id) {
        this.id = id
    }

    static public RateType getEnumFromId(String value) {
        values().find {it.id == value }
    }   
}

如果我有一个如下所示的命令对象:

class MyCommand {
    Rating rating
}

我想(例如)自动将值为“wo”的请求参数转换为 Rating.WORST。

此处描述了定义自定义转换器的过程(在将字符串转换为日期的上下文中)。尽管此过程运行良好,但我不想为每个枚举创建一个实现 PropertyEditorSupport 的类。有更好的选择吗?

My Grails application has a large number of enums that look like this:

public enum Rating {
    BEST("be"), GOOD("go"), AVERAGE("av"), BAD("ba"), WORST("wo")
    final String id

    private RateType(String id) {
        this.id = id
    }

    static public RateType getEnumFromId(String value) {
        values().find {it.id == value }
    }   
}

If I have a command object such as this:

class MyCommand {
    Rating rating
}

I would like to (for example) automatically convert a request parameter with value "wo" to Rating.WORST.

The procedure for defining custom converters is described here (in the context of converting Strings to Dates). Although this procedure works fine, I don't want to have to create a class implementing PropertyEditorSupport for each of my enums. Is there a better alternative?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

没有伤那来痛 2024-08-19 07:44:03

我找到了一个令我非常满意的解决方案。

第 1 步: 创建 PropertyEditorSupport 的实现,以将文本与相关 Enum 相互转换

public class EnumEditor extends PropertyEditorSupport {

    private Class<? extends Enum<?>> clazz

    public EnumEditor(Class<? extends Enum<?>> clazz) {
        this.clazz = clazz
    }

    public String getAsText() {
        return value?.id
    }

    public void setAsText(String text) {
        value = clazz.getEnumFromId(text)
    }
}

第 2 步: 定义一个类,将 EnumEditor 注册为各种枚举类的转换器。要更改可通过 id 绑定的枚举类列表,只需修改 BINDABLE_ENUMS

public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

    private static final String REQUIRED_METHOD_NAME = 'getEnumFromId'

    // Add any enums that you want to bind to by ID into this list
    private static final BINDABLE_ENUMS = [Rating, SomeOtherEnum, SomeOtherEnum2]

    public void registerCustomEditors(PropertyEditorRegistry registry) {            

        BINDABLE_ENUMS.each {enumClass ->
            registerEnum(registry, enumClass)
        }
    }

    /**
     * Register an enum to be bound by ID from a request parameter
     * @param registry Registry of types eligible for data binding
     * @param enumClass Class of the enum
     */
    private registerEnum(PropertyEditorRegistry registry, Class<? extends Enum<?>> enumClass) {

        boolean hasRequiredMethod = enumClass.metaClass.methods.any {MetaMethod method ->
            method.isStatic() && method.name == REQUIRED_METHOD_NAME && method.parameterTypes.size() == 1
        }

        if (!hasRequiredMethod) {
            throw new MissingMethodException(REQUIRED_METHOD_NAME, enumClass, [String].toArray())
        }
        registry.registerCustomEditor(enumClass, new EnumEditor(enumClass))
    }
}

第 3 步: 通过在 中定义以下 Spring bean,让 Spring 识别上面的注册表grails-app/conf/spring/resources.grooovy

customPropertyEditorRegistrar(CustomPropertyEditorRegistrar)

I found a solution I'm pretty happy with.

Step 1: Create an implementation of PropertyEditorSupport to convert text to/from the relevant Enum

public class EnumEditor extends PropertyEditorSupport {

    private Class<? extends Enum<?>> clazz

    public EnumEditor(Class<? extends Enum<?>> clazz) {
        this.clazz = clazz
    }

    public String getAsText() {
        return value?.id
    }

    public void setAsText(String text) {
        value = clazz.getEnumFromId(text)
    }
}

Step 2: Define a class that registers EnumEditor as a converter for the various enum classes. To change the list of enum classes that are bindable by id, just modify BINDABLE_ENUMS

public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

    private static final String REQUIRED_METHOD_NAME = 'getEnumFromId'

    // Add any enums that you want to bind to by ID into this list
    private static final BINDABLE_ENUMS = [Rating, SomeOtherEnum, SomeOtherEnum2]

    public void registerCustomEditors(PropertyEditorRegistry registry) {            

        BINDABLE_ENUMS.each {enumClass ->
            registerEnum(registry, enumClass)
        }
    }

    /**
     * Register an enum to be bound by ID from a request parameter
     * @param registry Registry of types eligible for data binding
     * @param enumClass Class of the enum
     */
    private registerEnum(PropertyEditorRegistry registry, Class<? extends Enum<?>> enumClass) {

        boolean hasRequiredMethod = enumClass.metaClass.methods.any {MetaMethod method ->
            method.isStatic() && method.name == REQUIRED_METHOD_NAME && method.parameterTypes.size() == 1
        }

        if (!hasRequiredMethod) {
            throw new MissingMethodException(REQUIRED_METHOD_NAME, enumClass, [String].toArray())
        }
        registry.registerCustomEditor(enumClass, new EnumEditor(enumClass))
    }
}

Step 3: Make Spring aware of the registry above by defining the following Spring bean in grails-app/conf/spring/resources.grooovy

customPropertyEditorRegistrar(CustomPropertyEditorRegistrar)
绮筵 2024-08-19 07:44:03

因此,默认的数据绑定绑定在枚举名称上,而不是绑定在枚举的单独定义的属性上。您可以按照您提到的方式创建自己的PropertyEditor,或者执行类似于以下的解决方法这:

class MyCommand {
 String ratingId
    Rating getRating() {
     return Rating.getEnumFromId(this.ratingId)
    }
    static constraints = {
     ratingId(validator:{val, obj -> Rating.getEnumFromId(val) != null })
    }
}

So the default Databinding binds on the Enum name and not a separately defined property of the Enum. You can either create your own PropertyEditor as you have mentioned or do a work-around similar to this:

class MyCommand {
 String ratingId
    Rating getRating() {
     return Rating.getEnumFromId(this.ratingId)
    }
    static constraints = {
     ratingId(validator:{val, obj -> Rating.getEnumFromId(val) != null })
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文