为啥grails在第一次访问hasMany关系时抛出空指针异常?

Posted

技术标签:

【中文标题】为啥grails在第一次访问hasMany关系时抛出空指针异常?【英文标题】:Why grails throwing null pointer exception while accessing hasMany relationship first time?为什么grails在第一次访问hasMany关系时抛出空指针异常? 【发布时间】:2011-10-19 21:06:58 【问题描述】:

我有一个奇怪的问题。 我有两个域类 UserPost 字段:

class User 
  String name
  static hasMany = [posts: Post]
  static constraints =  

class Post 
  String content
  long date = System.getTimeInMillis()
  static constraints =  

  static belongsTo = [user: User]
  static mapping = 
    version: 'false'
  

控制器代码为:

class UserController 
  def addUser = 
    def user
    if (User.count() == 0) 
      user = new User()
      user.name = "Manish Zedwal"
      user.save(flush: true)
     else 
      user = User.get(1)
    
    println "Posts count: " + user.posts.size()
    render "post count: " + user.posts.size()
 

第一次访问 url http://localhost:8080/test/user/addUser 时,会抛出空指针异常,但之后就可以正常工作了。 这是我得到的例外

2011-08-04 15:41:25,847 [http-8080-1] ERROR errors.GrailsExceptionResolver  - Exception occurred when processing request: [GET] /test/user/addUser
Stacktrace follows:
java.lang.NullPointerException: Cannot invoke method size() on null object
        at test.UserController$_closure2.doCall(UserController.groovy:18)
        at test.UserController$_closure2.doCall(UserController.groovy)
        at java.lang.Thread.run(Thread.java:636)

第二次,它像魅力一样打印和渲染

Posts count: 0

在用户域类中,因为postspostshasMany 关系是Post 对象的列表,那么在获取空列表的大小时不应该出现空指针异常,而是应该为零。

任何帮助表示赞赏

【问题讨论】:

【参考方案1】:

当你像这样映射一个集合时,hasMany 声明会向你的类添加一个类型为 Set 且具有指定名称(在本例中为 posts)的字段。但是它不会初始化集合,所以它最初是空的。当您调用 addToPosts 时,它会检查它是否为 null,并在必要时创建一个新的空 Set,并将 Post 添加到集合中。但是如果你不调用addToPosts或者显式初始化set,它就会为null。

当您从数据库加载User 时,Hibernate 将填充所有字段,并且集合包含在其中。它创建一个新的空集(一个修改感知PersistentSet),如果有任何实例,它就会向它添加实例。调用save() 不会从数据库中重新加载实例,所以空集仍然是空的。

要让类在新类和持久类时表现相同,您可以向类中添加一个字段,就像 Rob 在他的回答中显示的那样,初始化为一个空集 (Set posts = [])

【讨论】:

【参考方案2】:

您可以通过在映射旁边显式声明您的集合属性(带有值)来防止这种情况:

class User 
    String name
    Set posts = []
    static hasMany = [posts: Post]

您可以定义您需要的集合类型。默认为Set,但如果需要维护秩序,可以考虑ListSortedSet

【讨论】:

是的,默认设置是 Set,但我使用 List,因为我将“posts”解释为具有排序的东西。不管怎样,SortedSet 可能更合适。

以上是关于为啥grails在第一次访问hasMany关系时抛出空指针异常?的主要内容,如果未能解决你的问题,请参考以下文章

grails中hasMany关系的选择性深度渲染

grails:脚手架为具有 hasMany 关系的域创建视图

Grails 默认排序的“hasMany”域属性

在 Grails 中扩展具有一对多关系的域类

Grails - 简单的 hasMany 问题 - 在 create.gsp 中使用 CheckBoxes 而不是 HTML Select

使用 hasmany 字符串查询 Grails / GORM 条件