Grooovy weird error - grails

class Area {
String name
String description
static constraints = {
}
_
class SearchIndexing {
String search
Area area
static constraints = {
}
}
_
<%
def area = cm.Area.get(1)
def si = new cm.SearchIndexing()
def concat
concat = area.name // i wanna join here more things with much bigger class
si.search = concat
si.area = area
si.save()
out << searchIndexing.list()
%>
ERROR:
No signature of method: cm.SearchIndexing.save() is applicable for argument types: () values: [] Possible solutions: wait(), any(), wait(long), any(groovy.lang.Closure), isCase(java.lang.Object), use([Ljava.lang.Object;)

Sure you don't have an initial + sign, ie:
def temp = + obj2.prop1 + " " + ...
Why not try a more groovy way like:
def temp = "$obj2.prop1 $obj2.prop2 ..."
Or:
def temp = [ obj2.prop1, obj2.prop2 ].join( ' ' )

From the way you're creating the instance of SearchIndexing
def si = new cm.SearchIndexing()
it looks like it's an inner class. I don't think a domain class can be an inner class, which would explain why it has no save() method.

Related

Why does overriding putAt result in MissingPropertyException?

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

How can I pass a class to Groovy's Eval binding?

I'm doing some gross stuff, like using Groovy's metaClass and Eval to dynamically assign properties to an object from an XML import:
class ObjectBuilder {
def assignProp(String propName, String propValue) {
Eval.x(this, "x.metaClass.${propName} = '${propValue}'")
}
}
def h = new ObjectBuilder()
h.assignProp('name', 'Henson')
println(h.name)
What I'd like to do though, is be able instantiate another copy of the class inside itself:
Eval.x(this, "x.metaClass.${ObjName} = new ObjectBuilder()")
But I can't, because I think the class isn't passed to the binding. Is there another solution?
A couple of solutions:
Expando
You may try working with a bunch of Expandos:
h = new Expando()
h.last = new Expando()
h.last.name = 'tech'
assert h.last.name == 'tech'
Metaclass the object directly
xml = '''
<person>
<name>john</name>
<surname>doe</surname>
<age>41</age>
<location>St Louis, MO</location>
</person>
'''
class Person {
def name, surname, location, age
}
root = new XmlParser().parseText xml
person = new Person(root.children().collectEntries { [it.name(), it.text()] })
person.metaClass.getFullname = { "$delegate.name $delegate.surname" }
assert person.fullname == "john doe"
person.metaClass.likes = "chicken with lemon"
assert person.likes == "chicken with lemon"
Maps
map = [:]
map.last = [:]
map.last.name = 'Tech'
assert map.last.name == 'Tech'
Passing a newly instantiated object then assigning it with Eval seems to work:
class ObjectBuilder {
def assignProp(String propName, String propValue) {
Eval.x(this, "x.metaClass.${propName} = '${propValue}'")
}
def nestObj(String objName) {
Eval.xy(this, new ObjectBuilder(), "x.metaClass.${objName} = y")
}
}
ObjectBuilder h = new ObjectBuilder()
h.assignProp('name', 'Henson')
h.nestObj('last')
h.last.assignProp('name', 'Tech')
println h.name + ' ' + h.last.name

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.

How to save multiple rows of data by looping through an array or a map?

Class Buyer {
String name
static constraints = {
}
}
Class Order {
String ref
static belongsTo = [buyer:Buyer]
static constraints = {
buyer(nullable:false)
}
}
In OrderController.groovy
...
def someAction = {
//working
def data1 = ["buyer.id": 2, "ref": "xyz"]
def ord = new Order(data1);
ord.save();
def data2 = ["buyer.id": 2, "ref": "234xyz"]
def ord2 = new Order(data2);
ord2.save();
//But in a loop - its not working
def items = ['abc', 'def', 'ghi', 'jkl']
def data2 = [:]
for(e in items) {
data2 = ["buyer.id": 2, "ref" : e.value] //keeping buyer id same
def ord = new Order(data2);
ord.save();
data2 = [:] //just emptying it?
}
}
As you would notice in "working" above, if I am able to save multiple rows by copy pasting and definging new maps but If I try to loop through an array, it doesnt work. Any ideas how do I save data by looping through an array or a map?
Any questions, please let know
Thanks
First, I'm not sure about ["buyer.id": 2, "ref" : e.value], I think it should be [buyer: Buyer.get(2), ref : e.value].
Second, I would recommend using cascading save to do the task. You can try something like this(You need to define a static hasMany = [orders: Order] relation in Buyer for Buyer-Order relationship.
Buyer b = new Buyer(name: "foo")
for(e in items) {
def ord = new Order(ref: e.value);
b.addToOrders(ord)
}
b.save(flush:true)
You should just be able to do:
def someAction = {
def items = ['abc', 'def', 'ghi', 'jkl']
items.each { item ->
def ord = new Order( [ 'buyer.id':2, ref:item ] )
ord.save()
}
}
What errors (if any) are you getting?
Also, why are you doing e.value? This will get you an array of Character rather than a String (which is what your first working example is using)

Using Curry to Define Grails Tags

I have a grails tag library TpTagLib and in it I want to define 4 new tags that differ only in one constant value, so I tried to use curry.
But there is an exception: groovy.lang.MissingPropertyException: No such property: attr for class: TpTagLib
Does anyone have any idea why this exception occurs?
Here is the code:
def ifPermsTag = { permissions, attr, body ->
def user = attr?.user ?: session.userInstance
if( !user ) return false
if( !securityService.hasPermissions(user,permissions) ) return false
out << body()
return true
}
def canAdminRequestmaps = ifPermsTag.curry(Permission.CAN_ADMIN_REQUESTMAPS)
def canAdminCorporations = ifPermsTag.curry(Permission.CAN_ADMIN_CORPS)
def canAdminUsers = ifPermsTag.curry(Permission.CAN_ADMIN_USERS)
def canAdminDevices = ifPermsTag.curry(Permission.CAN_ADMIN_DEVICES)
Cool technique. You just need to make ifPermsTag private so it's not considered a candidate to be a usable tag method:
private ifPermsTag = { permissions, attr, body ->
...
}
Tags can have no parameters, or an 'attr' parameter, or an 'attr' and 'body' parameters but other signatures are invalid.

Resources