【问题标题】:Defining global constraints in a Grails plugin在 Grails 插件中定义全局约束
【发布时间】:2013-10-28 20:27:08
【问题描述】:

在 Grails 中,您可以像这样在项目的 Config.groovy 文件中定义全局约束

grails.gorm.default.constraints = {
    myShared(nullable: false, blank: false)
}

并在域内像这样使用它们

static constraints = {
    name(shared: "myShared")
}

由于我们的领域类在多个 Grails 项目中被重用,它们被拆分为插件。插件的 Config.groovy 文件被排除在外,因此在那里定义全局约束将不起作用。因此,我创建了一个 Constraints.groovy 文件,该文件被合并到包含域类的插件的插件描述符内的应用程序配置中。这可行,但我仍然在运行主项目(grails run-app)时遇到以下异常:

Caused by GrailsConfigurationException: Property [test.plugin.TestDomain.name] references shared constraint [myShared:null], which doesn't exist!

在 Grails 核心中进行一些调试后,我发现在运行插件描述符之前,域类已经使用共享约束进行了初始化。

public DefaultGrailsDomainClass(Class<?> clazz, Map<String, Object> defaultConstraints)

构造函数中的映射包含共享约束。如果我将全局约束放在主项目的 Config.groovy 文件中,它包含定义的约束并且一切正常。但是,如果我将它们合并到插件描述符中,则此映射为空并引发异常。

我的问题是是否可以在 Grails 插件中以某种方式定义全局约束?我可能错过了什么? 将全局约束复制到每个 Grails 项目中不应成为解决方案。此外,首选不使用其他插件来定义约束的解决方案。

顺便说一句,我们使用的是 Grails 2.2.4。

【问题讨论】:

  • Config.groovy 被排除在外,但您可以创建另一个以 Config 结尾的文件,例如MyPluginConfig.groovy。你能检查一下共享约束是否有效吗?无需在您的应用程序中手动合并它们。
  • 感谢您的回复。我按照您的建议尝试了,但这也不起作用。您确定通过像您建议的那样命名它们来包含配置吗?我以为这只适用于 UrlMappings?
  • 是的,你是对的。 Grails Platform Core plugin add's a doWithConfig closure,您可以使用它。
  • 使用 doWithConfig-Closure 合并配置工作正常,感谢您指向插件。尽管如此,全局约束的问题仍然存在,因为 doWithConfig 在域类使用约束初始化后也会被调用。

标签: grails groovy


【解决方案1】:

由于 Grails 在 doWithSpring 闭包中初始化约束,我认为你不能使用配置文件来完成。

但如果您查看DomainClassGrailsPlugin,您可以访问配置对象。

def doWithSpring = {
  def config = application.config
  def defaultConstraintsMap = getDefaultConstraints(config)
  ...
}

所以我认为你可以做类似的事情(未测试)

def loadBefore = ['domainClass']

def doWithSpring = {
  def config = application.config
  config.grails.gorm.default.constraints = {
    myShared(nullable: false, blank: false)
  }
}

【讨论】:

    【解决方案2】:

    我在考虑 Sérgio 的回答后进一步调试,并提出了一个可能适用于某些项目而对某些项目不起作用的解决方案。不幸的是,我们工作中的 Grails 项目属于后一组项目……但首先要做的是。这就是我所做的。

    我设置了一个完全空的 Grails 项目和 Grails 插件项目。该插件是内嵌的,以反映我们在 Grails 项目中的工作情况。

    我在插件的 conf 目录中创建了一个文件 Constraints.groovy,如问题中所述。

    grails.gorm.default.constraints = {
        myShared(nullable: false, blank: false)
    }
    

    为了让这些共享约束可用于插件内的测试,我将此文件添加到 Config.groovy 中的配置位置。

    grails.config.locations = [Constraints]
    

    现在是使这些约束可用于主项目的部分。这是通过在插件描述符中添加一些行来实现的。

    def loadBefore = ['domainClass']
    

    按照 Sérgio 的建议,我更改了加载顺序。虽然我不确定这是否真的有必要。更多关于我为什么不确定的详细信息。

    def doWithSpring = {
        ConstraintEvalUtils.clearDefaultConstraints()
    
        mergeConfig(application)
    }
    
    protected mergeConfig(application) {
        application.config.merge(loadConfig(application))
    }
    
    protected loadConfig(application) {
        new ConfigSlurper(Environment.current.name).parse(application.classLoader.loadClass("Constraints"))
    }
    

    这两个方法负责将 Constraints.groovy 的内容加载并合并到应用程序配置中。但真正的诀窍是在合并之前调用ConstraintEvalUtils.clearDefaultConstraints()

    /**
     * Looks up the default configured constraints from the given configuration
     */
    public static Map<String, Object> getDefaultConstraints(ConfigObject config) {
        def cid = System.identityHashCode(config)
        if (defaultConstraintsMap == null || configId != cid) {
            configId = cid
            def constraints = config?.grails?.gorm?.default?.constraints
            if (constraints instanceof Closure) {
                defaultConstraintsMap = new ClosureToMapPopulator().populate((Closure<?>) constraints);
            }
            else {
                defaultConstraintsMap = Collections.emptyMap()
            }
        }
        return defaultConstraintsMap
    }
    

    此方法(也在ConstraintEvalUtils 中)被调用以加载共享约束。如您所见,结果缓存在defaultConstraintsMap 中。因此,如果在第一次调用此方法时共享约束为空,它总是返回一个空映射。所以我调试了这个方法来找出这个方法实际被调用的时间。它总是返回一个空地图。即使我在插件描述符中将loadBefore 设置为core,该方法已经在插件描述符之前被调用(不止一次)。正如我已经提到的,ConstraintEvalUtils.clearDefaultConstraints() 在清理缓存的约束时起作用,并且可以从我将约束合并到的配置中重新加载默认约束。

    差不多就是这样。实际上需要添加的行并不多。它适用于我的测试项目,可能也适用于其他项目,但不适用于我们正在工作的 Grails 项目。如果我也能在那里工作,我会更新我的答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-27
      • 1970-01-01
      相关资源
      最近更新 更多