When using grails with a domain class hierarchy similar to the following:
abstract class Vehicle { ... }
class Car extends Vehicle { ... }
class Motorcycle extends Vehicle { ... }
and a service as the following:
class VehicleService {
def startRepairing(Car car) { ... }
def startRepairing(Motorcycle motorcycle) { ... }
}
We very frequently we face errors as the following in production:
No signature of method: VehicleService.startRepairing() is applicable for argument types: (Car_$$_javassist_156) values: [Id: 42343, Class: Car]. Possible solutions: startRepairing(Car)
We believe this happens because we retrieve the Vehicle
instance from a collection such as static hasMany = [vehicles: Vehicle]
, which causes the proxy to implement the abstract class Vehicle
but not the concrete class (Car
, Motorcycle
, etc).
We used to remove the argument type from the method as a solution, but we would rather have it - code is cleaner, method overload is possible, more IDE friendly...
One solution we thought about is to use the infamous GrailsHibernateUtil.unwrapIfProxy when the type doesn't match any other method:
class VehicleService {
def startRepairing(Vehicle vehicle) {
startRepairing(GrailsHibernateUtil.unwrapIfProxy(vehicle))
}
def startRepairing(Car car) {
/* actual business logic here */
}
def startRepairing(Motorcycle motorcycle) {
/* actual business logic here */
}
}
But then the question is, how can we test this? When running code in development we very rarely find the javassist problem, and even in production it seems to happen "randomly" (or more precisely, due to conditions that escape our knowledge :).
Is it possible to force an instance to be a javassist proxy? What would be a good strategy for these kind of problems in general?