我在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,然后我没有问题,它运行正常。
答案 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处理数据源名称。只需在该域类中使用相同的签名声明它。如果您知道在任何域类中都不使用多个数据源,则可以删除所有逻辑。