Pourquoi graal jeter exception de pointeur null lors de l'accès à hasMany relation première fois?
J'ai un problème étrange.
J'ai deux classes de domaine User
et Post
avec les champs:
class User {
String name
static hasMany = [posts: Post]
static constraints = { }
}
et
class Post {
String content
long date = System.getTimeInMillis()
static constraints = { }
static belongsTo = [user: User]
static mapping = {
version: 'false'
}
}
le contrôleur et le code est:
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()
}
}
Pour la première fois lors de l'accès à l'url http://localhost:8080/test/user/addUser
, il jette exception de pointeur null, mais après cela fonctionne bien.
C'est l'exception, je suis
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)
et pour la deuxième fois, il imprime et rend fine comme un charme
Posts count: 0
Dans le domaine de l'utilisateur de la classe, coz de hasMany
relation pour posts
, posts
est une liste de Post
objets, il ne devrait pas être null pointer exception sur l'obtention de la taille de la liste est vide, il devrait plutôt être de zéro.
Toute aide appréciée
Vous devez vous connecter pour publier un commentaire.
Lorsque vous mappez une collection comme ça, le
hasMany
déclaration ajoute un champ de typeSet
avec le nom spécifié (dans ce casposts
) à votre classe. Il n'a pas d'initialiser l'ensemble, donc il est initialement nulle. Lorsque vous appelezaddToPosts
il vérifie si elle est null et crée un nouvel Ensemble vide si nécessaire, et ajoute le Post de la collection. Mais si vous n'appelez pasaddToPosts
ou explicitement initialiser l'ensemble, il sera nulle.Lorsque vous chargez un
User
à partir de la base de données, Hibernate va remplir tous les champs, et la collecte est inclus. Il crée un nouvel Ensemble (une modification conscient dePersistentSet
) qui est vide, et ajoute les cas, si il y a de tout. L'appel desave()
ne recharge pas l'instance de la base de données, donc la série null sera toujours null.Pour obtenir la classe à se comporter de la même manière quand il est nouveau et quand il est persistant, vous pouvez ajouter un champ à une classe Comme Rob a montré dans sa réponse, initialisé à un ensemble vide (
Set posts = []
)Vous pouvez éviter cela en déclarant explicitement votre collection de propriété (d'une valeur) à côté de votre cartographie:
Vous pouvez définir le type de collection dont vous avez besoin. La valeur par défaut est
Set
, mais si vous avez besoin pour maintenir l'ordre, vous pourriez envisager deList
ouSortedSet
.Set posts = []