简体   繁体   English

为什么域类中字段上的作用域修饰符会阻止验证?

[英]Why do scope modifiers on fields in domain classes prevent validation?

I'm just starting with Grails (coming from Rails) and I noticed that Grails really doesn't seem to like scope modifiers on fields in domain classes. 我只是从Grails(来自Rails)开始,我注意到Grails确实似乎并不喜欢域类中字段的作用域修饰符。

I had understood that all unscoped fields in a domain class were by default public, but if you actually declare it public, Grails won't validate it. 我了解到,默认情况下,域类中所有未作用域的字段都是public,但是如果您实际上将其声明为public,Grails将不会对其进行验证。

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

If you add a constraint, Grails will throw a NotReadablePropertyException exception when you call validate() 如果添加约束,则在调用validate()时,Grails将抛出NotReadablePropertyException异常。

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

  static constraints = {
     middleName nullable: true
  }
}

However if you take out the public declaration, everything works normally. 但是,如果您删除公共声明,则一切正常。

Can someone explain what's going on behind the scenes with the scoping in domain classes? 有人可以通过域类的作用域解释幕后发生的事情吗? Hard to understand why explicitly declaring something public which is already public would break the framework. 很难理解为什么显式声明已经公开的东西会破坏框架。 I'm guessing you wouldn't want to declare anything 'private' either, although it would be nice if there was away that a fields which shouldn't be manipulated directly could be hidden from consumers of the domain class. 我猜您也不想声明任何“私有”,尽管如果可以将不应该直接操作的字段隐藏在域类的使用者中,那将是很好的选择。

When you add a field to a Groovy class without a scope modifier, it's more that it's inferred to be public than being actually public. 当您将一个字段添加到没有范围修饰符的Groovy类中时,更多的是推断它是公开的,而不是实际公开的。 The compiler converts the field to a private field and generates a public getter and a setter for it, although it won't overwrite a getter or setter that you wrote. 编译器将字段转换为私有字段,并为其生成一个公共的getter和setter,尽管它不会覆盖您编写的getter或setter。 This is convenient because you can later write getters and/or setters to implement business logic and not affect the callers. 这很方便,因为您以后可以编写getter和/或setter来实现业务逻辑并且不影响调用方。

But a public field (declared as 'public') is just that - a public field. 但是,一个公共领域(被称为“公共”)就是一个公共领域。 There's no generated getter or setter. 没有生成的getter或setter。 I recommend using a decompiler to see this in action - create a simple POGO in src/groovy, eg 我建议使用反编译器来查看实际效果-在src / groovy中创建一个简单的POGO,例如

class Thing {
   String realProperty
   public String fieldButNotProperty
}

and open up the .class file with http://jd.benow.ca/ or another decompiler. 并使用http://jd.benow.ca/或其他反编译器打开.class文件。

GORM automatically assumes that typed properties are persistent unless you exclude some with the transients list. GORM会自动假定类型化属性是持久性的,除非您在transients列表中排除了某些属性。 The type is required so it knows how to persist the data, and properties like def name will be ignored. 该类型是必需的,因此它知道如何持久存储数据,并且诸如def name类的属性将被忽略。 Properties in this sense are similar to JavaBean properties - a matched getter/setter pair. 从这个意义上讲,属性类似于JavaBean属性-匹配的getter / setter对。

Hibernate has no support for Groovy and doesn't know what's going on under the hood - it just calls your getters and setters to set and access field data during persistence. Hibernate不支持Groovy,也不知道幕后情况-它只是在持久化过程中调用您的getter和setter来设置和访问字段数据。 So the Groovy compiler adding those in makes it easy for POGOs in Grails to be persisted by Hibernate. 因此,使用Groovy编译器添加这些代码后,Hibernate便可以轻松保留Grails中的POGO。 And you could do this yourself - add in a getter and setter with correct names and data type (eg String getName() and void setName(String name) and it will be treated as a persistent property, even if you do nothing with the values. 您可以自己执行此操作-添加具有正确名称和数据类型(例如String getName()void setName(String name)的getter和setter,即使您不使用值对它也将被视为持久属性。 。

The reason for the NotReadablePropertyException is that there's no getter to call for your 'property'. 出现NotReadablePropertyException的原因是,没有getter可以调用您的“属性”。 Even though your fields are perfectly accessible, you've effectively hidden them from GORM and Hibernate. 即使您的字段可以完全访问,您也已对GORM和Hibernate有效地隐藏了它们。

If you add a constraint, Grails will throw a NotReadablePropertyException exception when you call validate() 如果添加约束,则在调用validate()时,Grails将抛出NotReadablePropertyException异常。

Never noticed this before, sounds like a bug 以前从未注意到这一点,听起来像个bug

it would be nice if there was away that a fields which shouldn't be manipulated directly could be hidden from consumers of the domain class. 如果有一个不错的选择,那就是可以对域类的使用者隐藏不应直接操作的字段,那将是很好的选择。

If you want to prevent direct access to a property, simply add a getter and setter. 如果要防止直接访问属性,只需添加一个getter和setter即可。 In the (contrived) example below, I ensure that name is always read/written as an upper case string. 在下面的(人为)示例中,我确保始终将名称读/写为大写字符串。

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()
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM