Search code examples
hibernategrailsgrails-orm

Grails- Assigning associated domain objects into List vs ArrayList


I have this relationship:

User{
...
hasMany = [tags: Tag]

}

Tag{
...
}

Some where in my service I have this code:

List<Tag> tags = user.tags

But this does not work, I am getting this error:


org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[com.app.ext.Tag : 1]' with class 
'org.hibernate.collection.PersistentSet' to class 'java.util.List' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.List(com.app.ext.Tag)
    at ConsoleScript15.run(ConsoleScript15:6)

If I change my code to:

ArrayList<Tag> tags = user.tags

It works as expected! though ArrayList is subclass of List. Any explanation?

Grails version: 2.3.0


Solution

  • Take a look at Groovy's casting rules.

    When value which you try to cast is collection, constructor of the type you want to cast to is invoked. So, for ArrayList it implicitly invokes:

    ArrayList<Tag> tags = new ArrayList(users.tags)
    

    For List it would be something like new List(users.tags) which is incorrect since List is interface.

    The snippet below shows the same problem:

    Set<String> mySet = new HashSet<>(['A', 'B'])
    ArrayList<String> myList = mySet; // works okay
    List<String> myList = mySet; // fails with GroovyCastException
    

    But you can explicitly cast to ArrayList:

    List<String> myList = mySet as ArrayList;