Why does overriding putAt result in MissingPropertyException? - grails

I've been trying to take advantage of operator overloading in Groovy by defining a custom putAt method in my POGO like this:
class Book {
Map additionalInfo = [:]
def putAt(key, value) {
additionalInfo[key] = value
}
}
So that I can do something like, book['notes'] = 'I like this one.' (let's say this makes sense). However, I've been getting:
groovy.lang.MissingPropertyException: No such property: notes for class: Book
at BookSpec.Set property using putAt(BookSpec.groovy:40)
My class is part of a Grails application so I'm not sure if Grails has something to do with the problem. Can anyone enlighten me on this?

The signature should be
def putAt(String key, value)

Instead of doing putAt and then override the operator, there is an easy/better way by adding the propertyMissing methods.
Here is the link for more explanation.
class Foo {
def storage = [:]
def propertyMissing(String name, value) { storage[name] = value }
def propertyMissing(String name) { storage[name] }
}
def f = new Foo()
f.foo = "bar"
assertEquals "bar", f.foo

Related

grails find arraylist string based on corresponding string

I have a method:
def nameToCode(nameStr){
def ret = resortService.getResort("all")
//this gets like 180 objects with various properties like name, code, etc.
def resorts = [name: ret.prName, code: ret.prProductIndex]
def code = resorts.findByName(nameStr) //this doesn't work
println(code)
return code
}
I'm trying to call this method and send it a name. It's then supposed to go find the name in the map, if it finds it it's supposed to return the name's code. This is supposed to be simple but I've been searching everywhere and can't figure out how to do this. I'll appreciate any help. Thanks
you are using a gorm method on a standard map:
Instead of :
def resorts = [name: ret.prName, code: ret.prProductIndex]
def code = resorts.findByName(nameStr) //this doesn't work
Try:
def resorts = [name: ret.prName, code: ret.prProductIndex]
def code = resorts.findAll{name==nameStr}

Get domain class field names

I would like to get the field names of a class and maybe store it in a list. Can anyone help? Thanks.
You can try this to get field names of domain class.
YourClass.declaredFields.each {
if (!it.synthetic) {
println it.name
}
}
You can use gormPersistentEntity for any domain object, this works with Grails 2.4.4 at least:
def names = Person.gormPersistentEntity.persistentPropertyNames
//returns ['firstName', 'lastName'...]
you can also get natural name using GrailsNameUtils like so:
def naturalNames = Person.gormPersistentEntity.persistentPropertyNames.collect {
grails.util.GrailsNameUtils.getNaturalName(it)
}
//returns ['First Name', 'Last Name'...]
def capitilizedNames = Person.gormPersistentEntity.persistentProperties.collect{
it.capitilizedName
}
//returns ['FirstName', 'LastName'...]
Just found it out, this one works:
def names = grailsApplication.getDomainClass('com.foo.Person').persistentProperties.collect { it.name }
You can iterate over the fields of a class like this.
YourClass.fields.each { println it.name }
If you need to put them into a list you could use collect() or populate it within the each.
http://groovy.codehaus.org/JN3535-Reflection

Dynamic namedQueries

Is their a dynamic namedquery on grails? Im not sure if its the right term but, I mean a namedquery that can be true to all.
Something like:
namedQueries = {
dynamicQuery{ term, name, value ->
term(name, value)
}
}
Then it can be called maybe like but not exactly:
def testClass = TestClass.dynamicQuery('eq', 'lastname', 'Bill').list()
and so you call it too like:
def testClass = TestClass.dynamicQuery('gt', 'id', 12).list()
This one might not work but is their something similar in grails?
UPDATE
The idea is that so I can chained it as many as I want like:
def testClass = TestClass.dynamicQuery('gt', 'id', 12).dynamicQuery('eq', 'stat', 11).list()
This is so that I dont have to create many namedqueries. I was hoping I can create one and use it multiple times.
Grails' createCriteria method generates Grails HibernateCriteriaBuilder instance, within which you can call invokeMethod method to dynamically create query criteria, which usually is defined by the standard DSL.
Here is a example in some controller:
private String dynamicCriteriaTest(String term, name, value) {
def c = TestClass.createCriteria()
def param = []
param << name
param << value
def result = c.list{
c.invokeMethod(term, param as Object[])
}
return result.toString()
}
def test() {
render dynamicCriteriaTest('eq','lastname','Bill')
}
That will get something you want.
update
If you want to call this method multiple times, pass the criteria parameters in an a List then execute the query:
private List dynamicCriteriaTest(List param) {
def c = TestClass.createCriteria()
def paramList = param.collate(3) //split the parameters into groups
def result = c.list{
paramList.each { paramInstance ->
def command = paramInstance[0]
paramInstance.remove(0)
c.invokeMethod(command, paramInstance as Object[])
}
}
return result
}
def test() {
ArrayList param = new ArrayList()
//the 1st criteria
param << 'gt'
param << 'id'
param << (long)12 //you have to check the Grails [HibernateCriteriaBuilder] API to make sure the parameter passed to `invokeMethod` is in the right type (e.g. **long** in this case)
//the 2nd one
param << 'eq'
param << 'stat'
param << (long)11
//even more
param << 'like'
param << 'description'
param << 'some text%'
render dynamicCriteriaTest(param)
}
In Grails you have NamedQueries and also Where Queries. The example you give can possibly be implemented by using a namedqueries and placing this in a abstract domain class. Your domain classes should extend this abstract domain.

Why I get a cannot cast object 'null' error, when testing my controller?

I have a controller like this :
def unCompletedTasks() {
def user = User.get(springSecurityService.principal.id)
def choice = params.managersProject
params.max = Math.min(params.max ? params.int('max') : 10,100)
def search = Tasks.createCriteria().list(max: params.max as Integer, offset: params.offset as Integer, order: params.order as String, sort : params.sort) {
and {
project {
like('name',"${choice}")
}
eq('completed',false)
lt('endDate',new Date().clearTime())
}
}
[tasksInstanceList : search, tasksInstanceTotal: search.getTotalCount() ]
}
I want to test this. I wrote a test specification in Spock like this:
def 'user should be displayed unCompletedTasks' () {
setup: "set the required objects"
def tasksController = new TasksController()
tasksController.springSecurityService = [principal: [id:tasksInstance.id]]
tasksController.params.managersProject = "testing"
//other codings goes here
when:
def model = tasksController.unCompletedTasks()
then:
model.tasksInstanceTotal == 1
where:
//required fields
}
When I run, I get a error like this :
user should be displayed unCompletedTasks(mnm.schedule.TasksSpec)
| org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'org.codehaus.groovy.runtime.NullObject' to class 'java.lang.Integer'
at mnm.schedule.TasksController.unCompletedTasks(TasksController.groovy:39)
at mnm.schedule.TasksSpec.user should be displayed unCompletedTasks(TasksSpec.groovy:59)
I don't know where I went wrong.
Thanks in advance.
Sounds like the same problem as discussed in Problems casting a null object with Spock. The solution is to upgrade to Grails 2.0.2.

How to sort Domain-Objects with attribute with type JodaTime / DateTime in grails 1.3.7?

I'm working on a small event calendar and i want to sort the events by start time!
I'm using JodaTime Plugin in grails for the startTime attribute. ( http://www.grails.org/JodaTime+Plugin )
So, how can i sort with this datatype? This does not work:
def sortedEvents = events.asList().sort({ a, b -> a.startTime <=> b.startTime } as Comparator)
I hope you can help me!
Thanks,
whitenexx
/EDIT/
This is the code where i'm getting the events:
def getEventsNext(Location location) {
def events = location.events.findAll { it.endTime >= new DateTime() }
def sortedEvents = events.sort{it.startTime}
System.out.println(sortedEvents); //test
return sortedEvents
}
In /event/list action everything works fine with g:sortableColumn (sorting by startTime):
Try this:
def sortedEvents = events.asList().sort{it.startTime}
To reverse the sorting order, use:
def sortedEvents = events.asList().sort{-it.startTime}
FYI, Groovy adds this sort() method to Collection so you can remove asList() from the code above if events is already a Collection.
Try overriding the compareTo method in your domain classes.
For example,
int compareTo(obj) {
startTime.compareTo(obj.startTime)
}
Edit
Sort your events like so:
def sortedEvents = events.sort{e1,e2-> e1.startTime.compareTo(2.startTime)}
Or as suggested by #Don, the groovier equivalent
def sortedEvents = events.sort{e1,e2-> e1.startTime <=> e2.startTime}
Try
def events = location.events.findAll { it.endTime.isAfterNow() }
def sortedEvents = events.sort{it.startTime.toDate()}
JavaDoc for isAfterNow()

Resources