Grails FindBy* with an inteface property - grails

I have a class like
class Account {
BigDecimal balance = 0
SortedSet transactions
AccountOwner owner
static constraints = {
}
static hasMany = [transactions:Transaction]
}
when I try to query the Account like
def account = Account.findByOwner(user)
I get this error
| Failure: testSave(br.com.fisgo.financial.AccountControllerTests)
| org.springframework.dao.InvalidDataAccessResourceUsageException: Cannot query [br.com.fisgo.financial.Account] on non-existent property: owner
at org.grails.datastore.mapping.simple.query.SimpleMapQuery.getValidProperty(SimpleMapQuery.groovy:706)
at org.grails.datastore.mapping.simple.query.SimpleMapQuery.executeSubQueryInternal(SimpleMapQuery.groovy:644)
at org.grails.datastore.mapping.simple.query.SimpleMapQuery.executeSubQuery(SimpleMapQuery.groovy:630)
at org.grails.datastore.mapping.simple.query.SimpleMapQuery.executeQuery(SimpleMapQuery.groovy:63)
at org.grails.datastore.mapping.query.Query.list(Query.java:486)
at org.grails.datastore.gorm.finders.AbstractFindByFinder.invokeQuery(AbstractFindByFinder.java:34)
at org.grails.datastore.gorm.finders.AbstractFindByFinder$1.doInSession(AbstractFindByFinder.java:26)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:301)
at org.grails.datastore.gorm.finders.AbstractFinder.execute(AbstractFinder.java:40)
at org.grails.datastore.gorm.finders.AbstractFindByFinder.doInvokeInternal(AbstractFindByFinder.java:24)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:151)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:352)
at org.grails.datastore.gorm.GormStaticApi.methodMissing(GormStaticApi.groovy:108)
at br.com.fisgo.financial.AccountController.buyLead(AccountController.groovy:17)
at br.com.fisgo.financial.AccountControllerTests.testSave(AccountControllerTests.groovy:92)
| Completed 1 unit test, 1 failed in 5414ms
| Tests FAILED - view reports in target\test-reports
Using this interface
package br.com.fisgo.financial;
public interface AccountOwner {
}
I'm using mocked object for testing
Thanks

Since findBy* are handled by GORM and GORM doesn't handle interfaces I don't think it's going to work. Could you make AccountOwner an abstract class?

Related

grails4 migration Traits lazy load issue - HHH000142: Bytecode enhancement failed

I have migrated my application from Grails-3.x to Grails-4.1.1
Most of my Domain classes implemented the following Traits class (DynamicProperties), which has an implementation of GormEntity for some reason - to override the propertyMissing method.
trait DynamicProperties<D> implements GormEntity<D> {
def dynamic = [:]
def propertyMissing(String name, value) {
if (!propertyIsDatasource(name)) {
dynamic[name] = value
}
}
def propertyMissing(String name) {
if (propertyIsDatasource(name)) {
super.propertyMissing(name)
} else {
dynamic[name]
}
}
boolean propertyIsDatasource(String name) {
false
}
}
The above trait has been implemented by many domain classes like this
class Customer implements DynamicProperties<Customer> {
String customerCode
String customerName
Address address
....
}
Now, when I run my application, It is throwing the following exception
HHH000142: Bytecode enhancement failed: com.apps.billing.Customer.
Caused by: java.lang.NullPointerException
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:37)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:75)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
at **com.apps.billing.common.DynamicProperties$Trait$Helper.$init$**(DynamicProperties.groovy:7)
It used to work fine with Grails3.x
I had a similar problem when migrating a project to Grails 4.0.13.
I tracked the trigger of this problem down to having default values for member variables in a trait class. I see you have the same with the property dynamic being initialized with the empty map.
I recommend lazy initializing it in one of your propertyMissing methods.

Grails default value for domain class attribute of user defined type

I have a domain class Plan which is like:
class Plan{
String name
static constraints={
name(unique:true,nullable:false)
}
}
Another domain class is User:
class User{
// Other attribures and code
// ....
Plan plan
static constraints = {
// other constraints..
plan(nullable:false, defaultValue: Plan.findByName("default"))
}
}
Above code gives me error:
Caused by: java.lang.IllegalStateException: Method on class [mypackage.Plan] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
at mypackage.User$__clinit__closure1.doCall(User.groovy:31)
The line above in error is
plan(nullable:true,defaultValue: Plan.findByName("default"))
Also I have defined the default plan in BootStrap.groovy:
if(!Plan.findByName("default")){
new Plan(name: "default",brandPartner: null,secRole: null).save(failOnError: true, flush: true)
log.info("initPlans: No default plan found, hence created a new default plan!")
}
So how should I set the default value for plan attribute(which is of user defined type)?
Use an interceptor instead of constraint:
class User{
Plan plan
static beforeInsert = {
if( !plan ) Plan.withTransaction {
plan = Plan.findByName 'default'
}
}
}

Strange behaviour in Grails' Integration Tests

I am doing Grails tutorials on IBM(here) but I am a quite disappointed by an integration test.
To sum up : I call a method who render a JSON object according to the ID (iata).
My domain is :
class Airport {
String name
String iata
}
My controller is :
class AirportController {
// In order to enable scaffolding
def scaffold = Airport
def iata = {
def iata = params.id?.toUpperCase() ?: "NO IATA"
def airport = Airport.findByIata(iata)
if (!airport) {
airport = new Airport(iata: iata, name: "Not found")
}
render airport as JSON
}
}
When I do :
http://localhost:8080/trip-planner/airport/iata/foo (in order to retreive null value) or
http://localhost:8080/trip-planner/airport/iata/DEN (for DENVER), the method works fine !
The issue is my Integration tests :
class AirportControllerTests extends GroovyTestCase {
void testWithGoodIata(){
def controller = new AirportController()
controller.metaClass.getParams = { ->
return ["id":"den"]
}
controller.iata()
def response = controller.response.contentAsString
assertTrue response.contains("Denver")
}
void testWithWrongIata() {
def controller = new AirportController()
controller.metaClass.getParams = { ->
return ["id":"foo"]
}
controller.iata()
def response = controller.response.contentAsString
assertTrue response.contains("\"name\":\"Not found\"")
}
}
The problem is:
Whenever I run the tests (by running : grails test-app -integration trip.planner.AirportControllerTests), I will always obtain a good behavior in the first test and a groovy.lang.MissingMethodException in the second test. (even if I switch the two : the second test always fail)
If I run them separately , it works.
The exception occurred at this line (in the controller) : def airport = Airport.findByIata(iata)
Is that someting to do with "transactional" ? Any help would be great :)
P.S : I am using Grails 2.2.1
The exception stacktrace :
groovy.lang.MissingMethodException: No signature of method: trip.planner.Airport.methodMissing() is applicable for argument types: () values: []
at trip.planner.AirportController$_closure4.doCall(AirportController.groovy:39)
at trip.planner.AirportControllerTests.testWithWrongIata(AirportControllerTests.groovy:25)
I suspect the metaclass changes you're making in one test are somehow leaking through to the other. But you don't need to (and shouldn't) manipulate the metaclass in an integration test, just say
def controller = new AirportController()
controller.params.id = "den"
You only need to do mocking for unit tests.
Bear in mind that the tutorial you're looking at was written way back in 2008 (in the Grails 1.0.x days), and Grails has moved on a very long way since then, with some components (including testing) having been through one or more complete rewrites.

Grails 2 abstract domain inheritance issue

The following is not working for me when using abstract (or non-abstract for that matter) inheritance in Grails.
Very quickly, my inheritance is as follows:
abstract BaseClass { ... }
SomeClass extends BaseClass { ... }
SomeOtherClass extends BaseClass { ... }
And then in another domain object:
ThirdClass {
...
BaseClass baseProperty
...
}
But now, when I try to set that property to either a SomeClass or SomeOtherClass instance, Grails compains:
ERROR util.JDBCExceptionReporter - Cannot add or update a child row: a foreign key constraint fails
...
Is this not possible?
I have also tried having the base class not be abstract, and also tried casting the SomeClass or SomeOtherClass instances to BaseClass. They generate the same error.
UPDATE
I just checked. It works for the first sub-class that I add. But as soon as I try to add the other sub-class it fails.
In other words:
def prop1 = new ThirdClass(baseProperty: instanceOfSomeClass).save()
works fine. But when I then try and do:
def prop2 = new ThridClass(baseProperty: instanceOfSomeOtherClass).save()
it fails.
UPDATE 2
Further investigation shows that something goes wrong during the table creation process. It correctly adds two foreign keys to the ThirdClass table, but the keys incorrectly references:
CONSTRAINT `...` FOREIGN KEY (`some_id`) REFERENCES `base_class` (`id`),
CONSTRAINT `...` FOREIGN KEY (`some_id`) REFERENCES `some_class` (`id`)
Don't know why it's choosing the base class and one of the sub-classes? I have tried cleaning etc.
First of all, create your BaseClass outside domain structure. It must be an external class, put it on script folder, source folder.
package com.example.model
/**
* #author Inocencio
*/
class BaseClass {
Date createdAt = new Date()
}
Now, create a regular domain class and extend it.
package com.example.domain
import com.example.model.BaseClass
class SomeClass extends BaseClass {
String name
static constraints = {
name(nullable: false)
}
}
As you can see, once you persist SomeClass a createdAt field is filled and saved as well. Check the test class out:
#TestFor(SomeClass)
class SomeClassTests {
void testSomething() {
def some = new SomeClass()
some.name = "Hello There"
some.save()
//find it
def someFind = SomeClass.list()[0]
assert someFind
assertTrue someFind.createdAt != null
// println "Date: $someFind.createdAt"
// println "Name: $someFind.name"
}
}
I hope it can be helpful.
I have just created class structure as yours (Grails 2.1.0) and there is no problem. It works when mocked and unit-tested. The same when scaffolded and SomeClass and ThirdClass instances saved from forms.
Try clean your DB, especially if you haven't used 'create-drop' mode. Maybe there is some old constraint left.
Last thing, you haven't specified when the error occurs - on save (create or update)? It's rather not probable to get JDBC exception on property set, is it?
I don't remember for sure but it's possible that simple property isn't cascaded by default then try to save SomeClass instance before saving the ThirdClass instance. Also you can auto-cascade instead of declaring simple property by use hasOne relation like:
class ThirdClass {
...
static hasOne = [baseProperty:BaseClass]
}

Grails GORM count function in a named query

I'm writing some named queries for my domain classes in Grails and I've hit a blocker.
Given the following domain class:
class Contributor {
// evals is a collection of another domain class
def evals
static namedQueries = {
hasNoEvals {
// Something like this...
evals.size() == 0
}
}
}
Can anyone help with the syntax I need to select the Contributors who have no Evals?
Thanks.
Please look in createCriteria doc for "collection property" operations. In your case, it is isEmpty:
static namedQueries = {
hasNoEvals {
isEmpty('evals')
}
}
For generic size restriction, it is sizeEq, sizeLe and so on.

Resources