Почему grails выдает исключение нулевого указателя при первом обращении к связи hasMany? - PullRequest
20 голосов
/ 04 августа 2011

У меня странная проблема.
У меня есть два класса домена User и Post с полями:

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

В классе пользовательского домена, coz из hasMany отношение для posts, posts представляет собой список Post объектовтогда не должно быть исключения нулевого указателя при получении размера пустого списка, скорее это должно быть ноль.

Любая помощь приветствуется

Ответы [ 2 ]

30 голосов
/ 04 августа 2011

Когда вы отображаете коллекцию подобным образом, объявление hasMany добавляет поле типа Set с указанным именем (в данном случае posts) в ваш класс.Хотя он не инициализирует набор, поэтому изначально он нулевой.Когда вы вызываете addToPosts, он проверяет, является ли он пустым, и создает новый пустой набор, если необходимо, и добавляет сообщение в коллекцию.Но если вы не вызовете addToPosts или явно инициализируете набор, он будет нулевым.

Когда вы загружаете User из базы данных, Hibernate заполнит все поля, и коллекция будет включена.в этом.Он создает новый Set (с учетом модификации PersistentSet), который пуст, и добавляет в него экземпляры, если таковые имеются.Вызов save() не перезагружает экземпляр из базы данных, поэтому нулевой набор будет по-прежнему нулевым.

Чтобы заставить класс вести себя таким же образом, когда он новый и когда он постоянен, вы можете добавитьполе для вашего класса, как Роб показал в своем ответе, инициализированный пустым набором (Set posts = [])

11 голосов
/ 04 августа 2011

Вы можете предотвратить это, явно объявив свойство коллекции (со значением) вместе с отображением:

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

Вы можете определить необходимый тип коллекции. По умолчанию Set, но если вам нужно поддерживать порядок, вы можете рассмотреть List или SortedSet.

...