为什么域类中字段的范围修饰符会阻止验证?

时间:2014-09-09 00:16:35

标签: grails gorm grails-2.0 grails-domain-class

我刚开始使用Grails(来自Rails),我注意到Grails似乎不喜欢域类中字段的范围修饰符。

我已经理解域类中的所有未编码字段都是默认公开的,但如果您实际声明它是公开的,Grails将不会对其进行验证。

class Person {
  public String firstName
  public String middleName
  public String lastName
}

如果添加约束,Grails将在调用validate()时抛出NotReadablePropertyException异常

class Person {
  public String firstName
  public String middleName
  public String lastName

  static constraints = {
     middleName nullable: true
  }
}

但是如果你拿出公开声明,一切正常。

有人可以通过域类中的范围来解释幕后发生的事情吗?很难理解为什么明确宣布已经公开的公开会破坏框架。我猜你也不想宣布任何“私有”,尽管如果有一些不应该被直接操作的字段可以从域类的消费者中隐藏它会很好。

2 个答案:

答案 0 :(得分:4)

当你在没有范围修饰符的情况下向Groovy类添加字段时,它被推断为公开而不是实际公开。编译器将字段转换为私有字段并为其生成公共getter和setter,尽管它不会覆盖您编写的getter或setter。这很方便,因为您以后可以编写getter和/或setter来实现业务逻辑,而不会影响调用者。

但是公共领域(宣称为' public')就是这样 - 一个公共领域。没有生成的getter或setter。我建议使用反编译器来实现这一点 - 在src / groovy中创建一个简单的POGO,例如。

class Thing {
   String realProperty
   public String fieldButNotProperty
}

并使用http://jd.benow.ca/或其他反编译器打开.class文件。

GORM会自动假定类型属性是持久的,除非您使用transients列表排除某些属性。该类型是必需的,因此它知道如何持久保存数据,并且将忽略def name之类的属性。这种意义上的属性类似于JavaBean属性 - 匹配的getter / setter对。

Hibernate不支持Groovy并且不知道幕后发生了什么 - 它只是调用你的getter和setter在持久性期间设置和访问字段数据。因此,添加这些内容的Groovy编译器使得Grails中的POGO很容易被Hibernate持久化。你可以自己做 - 添加一个具有正确名称和数据类型的getter和setter(例如String getName()void setName(String name),它将被视为持久属性,即使你对值没有做任何事情也是如此

NotReadablePropertyException的原因是,您的“'”财产没有任何吸气者。即使您的字段完全可访问,您也可以有效地将它们隐藏在GORM和Hibernate中。

答案 1 :(得分:0)

  

如果添加约束,Grails将在调用validate()时抛出NotReadablePropertyException异常

之前从未注意到这一点,听起来像一个错误

  

如果不存在不应该直接操作的字段可能会被域类的消费者隐藏,那将是很好的。

如果要阻止直接访问属性,只需添加getter和setter即可。在下面的(设计)示例中,我确保始终将名称作为大写字符串进行读/写。

class Person {
  public String firstName
  public String middleName
  public String lastName

  public void setFirstName(String name) {
    this.firstName = name.toUpperCase()
  }

  public String getFirstName() {
    return this.firstName.toUpperCase()
  }
}