2

I would like to intersect two lists of instances of a specific domain class using grails 1.3.7.

The problem is, that the instances of one list are created by javasisst so that the result of the intersection is always an empty list.

Here are my domains:

class User {
    ...
    static hasMany = [foos : Foo]
    ...
} 

class Foo {
    ...
    static hasMany = [bars : Bar]
    ...
}

class Bar {
    ...
    static hasMany = [localizedTitles : LocalizedTitle]
    ...
}

I get the list of all Bar instances of the user like this:

def allBarsOfUser = userInstance.foos.bars.flatten()

And try to intersect with another list of Bar instances:

def intersectedBars = bars.intersect(allBarsOfUser)

The problem is, that the type of elements of allBarsOfUser ist Bar_$$_javassist_139 and the the type of the elememts of bars is Bar so that intersectedBars is always [].

I solved my problem by doing the following - but I don't like the solution:

def allBarsOfUser = userInstance.foos.bars.flatten().collect{Bar.get(it.id)}

What would be a better solution?

How could I cast Bar_$$_javassist_139 to Bar so that intersect() works fine?

aiolos
  • 4,387
  • 1
  • 19
  • 27

1 Answers1

1

It depends what you're actually trying to do. The intersect method ultimately relies on equals, so if you implement equals and hashCode in Bar then it will do what you want. But you shouldn't generally implement equals in terms of the object ID, as IDs are only assigned when an object is saved so you wouldn't be able to compare a newly-created object with a previously-saved one. Hibernate recommends that you implement it based on a business key (something that isn't the generated ID but which is stable and unlikely to change throughout the lifetime of the object)

class UserAccount {
  String username
  String realname

  public boolean equals(that) {
    return ((that instanceof UserAccount)
        && (this.username == that.username))
  }

  public int hashCode() {
    username.hashCode()
  }
}

So if you do want an ID comparison then it's clearer to do that explicitly.

def userBarIds = allBarsOfUser*.id
def intersectedBars = bars.findAll { it.id in userBarIds }
Ian Roberts
  • 114,808
  • 15
  • 157
  • 175
  • The ID comparison is sufficient here. It is nevertheless possible to cast a javassist class? – aiolos Jul 26 '12 at 12:44
  • 5
    The javassist proxy _is_ an `instanceof Bar`, the point is that a proxy for the `Bar` with id 5 isn't the same object (`==` in the Java sense) as `Bar.get(5)`. There is `GrailsHibernateUtil.unwrapIfProxy` but you shouldn't unwrap proxies explicitly unless you really have to, as doing so will cause an additional SQL query against the database. – Ian Roberts Jul 26 '12 at 13:02