propertyMissing of groovy不能用于grails3

时间:2017-10-13 17:40:29

标签: grails groovy

我在src/groovy

中创建了一个抽象类
abstract class BaseDomain {
    def storage = [:]
    def propertyMissing(String name, value) { storage[name] = value}
    def propertyMissing(String name) { storage[name] }
}

我创建了以下域类

class Student extends BaseDomain {
    String firstName
    String lastName
    //....
}

但是,当我试图将属性动态添加到学生对象时它会抛出异常,但它应该采用groovy作为动态编程语言的本质

我使用Groovy 2.4.10,Grails 3.2.9,IntelliJ

我错过了application.yml中的任何配置,这是我在Grails 3中做的第一个项目,早些时候我使用Grails 2.5.x,然后我没有问题,它运行正常。

1 个答案:

答案 0 :(得分:0)

Grails 3广泛使用traits来混合方法,基类和工件类(域类,控制器等)的接口,并且通常行为是相同或非常相似的,但有些情况如在这种情况下,幕后实施会影响一些事情的运作方式。

如果您使用反编译器或反射API,您可以看到您的域类实现了几个实际上是Groovy特征的接口,而这里感兴趣的是org.grails.datastore.gorm.GormEntity,因为它是一个源代码。 def propertyMissing(String name)的实施。这是为了支持多个数据源,例如如果有第二个名为"mongo"的数据源,那么您可以使用该数据源在从另一个数据源检索的实例上使用语法student.mongo.theMethodName(...)进行实例方法调用。由于该方法是在特征中定义的,因此将调用特征方法并忽略您的方法。

该特征可能会尝试调用您的方法,但不能保证在那里(并且在这种情况下甚至不可能,因为这不是常见的技术)因此需要仔细实施。 / p>

但是,当有多个方法具有来自不同来源的相同签名时,您可以利用Groovy中的逻辑来解决该问题。来自最后声明的特征的方法(在通过implements的类声明中)是被调用的方法。特征可以致电super.methodname(...)至"链"调用同样声明该方法的其他特征。

因此,将BaseDomain从抽象基类更改为特征:

package ...

import org.grails.datastore.gorm.GormEntity

trait DynamicProperties<D> implements GormEntity<D> {

   def dynamic = [:]

   def propertyMissing(String name, value) {
      if (!propertyIsDatasource(name)) {
         dynamic[name] = value
      }
   }

   def propertyMissing(String name) {
      if (propertyIsDatasource(name)) {
         super.propertyMissing(name)
      }
      else {
         dynamic[name]
      }
   }

   boolean propertyIsDatasource(String name) {
      false
   }
}

并实现它而不是扩展:

package ...

class Student implements DynamicProperties<Student> {
   String firstName
   String lastName
}

不幸的是GormEntity需要类名,所以你需要在你的具体类中冗余地包含它。

由于DynamicProperties扩展GormEntity,它将在&#34;链&#34;中更早,因此将首先调用它。

任何使用多个数据源的域类都需要使用自定义逻辑覆盖propertyIsDatasource方法,以确保GORM处理数据源名称。只需在该域类中使用相同的签名声明它。如果您知道在任何域类中都不使用多个数据源,则可以删除所有逻辑。