I don't appear to be able to override a getter within my grails controller. The sample code I've created to illustrate this is provided below:
class MyController extends RestfulController<MyDomainObj> {
def field
def getField(){
field += 1
}
def index(MyCommand command) {
field = 1
// in a controller this prints 1, but in my class it prints 2
println('field' + field)
}
}
If I create a Groovy class and override the getter then it works.
class X {
public static void main(String[] args){
def x = new X()
x.field = 1
println x.field
}
def field
def getField(){
field += 1
}
}
Am I doing something wrong in the Controller or is this feature not supported in controllers? If it isn't supported, then does anyone know why? What magic is going on that would cause this feature not to work?
For attributes within a class, Groovy uses the generated private variable directly:
See http://groovy.codehaus.org/Groovy+Beans:
If you access a property from within the class the property is defined
in at compile time with implicit or explicit this (for example
this.foo, or simply foo), Groovy will access the field directly
instead of going though the getter and setter.
Example:
class C {
def prop
def getProp() {
println "getter"
prop
}
def dostuff() {
prop = "Y"
println prop
println getProp()
}
}
new C().dostuff()
results in
Y
getter
Y
Related
I have a global shared library on Jenkins implicitly loaded on all pipelines, then my Jenkinsfile is like that:
new com.company.Pipeline()()
And then the shared library has on directory src/com/company some files, below the Pipeline.groovy class:
package com.company
import static Utils.*
def call() {
// some stuff here...
}
The problem is, this way I have to static declare all methods, thus I lose the context and cannot access jenkins' methods easly without the Pipeline class' instance. As you can see here they passing this to the method mvn.
Thinking of avoid this I was wondering about dynamically add all methods as closures by calling Utils.install this instead of using import static Utils.*, then my Utils.groovy is something like that:
package com.company
private Utils() {}
static def install(def instance) {
def utils = new Utils()
// Some extra check needed here I know, but it is not the problem now
for (def method in (utils.metaClass.methods*.name as Set) - (instance.metaClass.methods*.name as Set)) {
def closure = utils.&"$method"
closure.delegate = instance
instance.metaClass."$method" = closure
}
}
def someMethod() {
// here I want to use sh(), tool(), and other stuff freely.
}
But it raises an GStringImpl cannot be cast to String error, I believe .& do not work with variables, how can I convert a method into closure having the method name on a variable? I have the MetaMethod mostly being a CachedMethod instance, if it were possible to turn it a ClosureMetaMethod instance maybe the problem can be solved, but whenever I search for method to closure conversion for groovy I just found the .& solution!
If I use instance.metaClass.someMethod = utils.&someMethod it do work, but I want it to be dinamic as I add new methods without needing to worry about sharing it.
There is a way to do it dynamically. Notation utils.&someMethod returns a MethodClosure object that can be simply instantiated with its constructor:
MethodClosure(Object owner, String method)
Consider following example:
class Utils {
def foo() {
println "Hello, Foo!"
}
def bar() {
println "Hello, Bar!"
}
}
class Consumer {
}
def instance = new Consumer()
def utils = new Utils()
(utils.metaClass.methods*.name - instance.metaClass.methods*.name).each { method ->
def closure = new MethodClosure(utils, method)
closure.delegate = instance
instance.metaClass."$method" = closure
}
instance.foo() // Prints "Hello, Foo!"
instance.bar() // Prints "Hello, Bar!"
In this example I use def closure = new MethodClosure(utils, method) to get object method reference and then add this method to instance object. I hope it helps.
I have a Grails application. I want to use a value from Grails controller class (say MyController) inside a class in src/groovy/MyClass.groovy
How can I pass the value from Grails controller class to this class? I couldn't find anything relevant.
I tried this:
class MyController {
def name = "myapp"
}
Class MyClass{
def username = MyController.name
}
Please correct me . Thanks
It is hard to say for sure without knowing what you are doing but your probably want to pass the value as an argument to a method in MyClass and you probably don't want the value to be a field in the controller class.
class MyController {
def someControllerAction() {
def name = // I don't know where you are
// getting this value, but you got it from somewhere
def mc = new MyClass()
mc.someMethod(name)
// ...
}
}
class MyClass {
def someMethod(String name) {
// do whatever you want to do with the name
}
}
Or you could pass the value as a constructor argument:
class MyController {
def someControllerAction() {
def name = // I don't know where you are
// getting this value, but you got it from somewhere
def mc = new MyClass(name: name)
// ...
}
}
class MyClass {
def name
}
I hope that helps.
I'm developing a Groovy library providing variable binding/syncronization with simple syntax and rich event handler.
Firstly I'm aiming to archive running the following:
def a = 1
def b = 1
def c = 1
a bind { b + c }
assert a==2 & b==1 & c==1
b = 3
assert a==4 & b==3 & c==1
c = -1
assert a==2 & b==3 & c==-1
I'd like avoid Java FX approach of providing additional classes but rather enhance objects with this functionality.
I'm stuck at finding some tracking of objects. Groovy doesn't feature overload of assignment expression.
Currently I see solution in heavy AST transformation (maybe dsld might help).
Maybe there is some object tracking, events or whatever, I've missed?
I'm presuming you are writing your code using scripts. Did what you wanted with the following ideas:
Instead of binding values to keys using the Script.binding, it is better if you create a Variable class which represents both the value and the variable name;
Every method called on the Variable object gets delegated to its value;
A Listener class which encapsulates a reference to the updating operation AND the Variable object which needs to be updated;
An updateListeners() method, to, well, update the listeners;
A bind(closure) method that just bypasses the closure to the variable object. It could pretty much be dropped and written as a { b + c };
class Listener { Closure operation; Variable variable }
class Variable implements GroovyInterceptable {
String name; def value
def invokeMethod(String method, args) {
def var = args[0]
var.class == Variable ?
value."$method"(var.value) : value."$method"(var)
}
}
Variable.metaClass.call = { Closure operation ->
binding['listeners'] <<
new Listener(operation: operation, variable: delegate)
updateListeners()
}
def bind(Closure operation) { operation }
def updateListeners() {
binding.listeners.each {
it.variable.value = it.operation()
}
}
void setProperty(String prop, value) {
if (!binding.hasVariable('listeners')) binding['listeners'] = []
binding[prop] = new Variable(name: prop, value: value)
updateListeners()
}
And your tests worked like a charm.
Given this grossly simplified rendition of the setup:
package net.myexample.plugin
class MyExampleService {
Map doMunge(Map m) {
// do stuff to 'm'
return m
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.plugin
class MyTagLib {
static namespace = 'p'
def myExampleService
def tag = { attrs, body ->
def m = doMungeAndFilter(attrs.remove('m'))
out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
}
Map doMungeAndFilter(def m) {
def mm = myExampleService.doMunge(m)
// do stuff to 'm'
return mm
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.app
import net.myexample.plugin.MyExampleService
class MyExampleService extends net.myexample.plugin.MyExampleService {
def doMunge(def m) {
def mm = super.doMunge(m)
// do more stuff to 'mm'
return mm
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.app
import net.myexample.plugin.MyTagLib
class MyTagLib extends net.myexample.plugin.MyTagLib {
static namespace = 'a'
def myExampleService
def tag = { attrs, body ->
def m = doMungeAndFilter(attrs.remove('m'))
out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
}
Map doMungeAndFilter(def m) {
def mm = super.doMungeAndFilter(m)
// do more stuff to 'mm'
return mm
}
}
/**
* But we get an exception that cites that it cannot call 'doMunge' on a null
* object -- which could only be 'myExampleService'
*/
Why would the service appear to be null when the method on the app's taglib calls its superclass (the taglib on the plugin), which in turn calls the method on the service?
The best theory I could come up with is that the service is not actually being instantiated in the app's taglib class because there are no explicit references to it aside from the def. I presume that this is the case because if I move all the logic from service class's method into the taglib's method, it works as expected.
(For the sake of painting a complete picture: MyExampleService.doMunge is called in other places, whereas the subsequent filtering (in MyTagLib.doMungeAndFilter) is only needed for the taglib.)
Alternatively: if I move doMungeAndFilter into another service class, creating the base version in the plugin and extending it in the app, that works fine. Which I suppose is an acceptable conclusion, though it feels like bloat to create another service class just to support the taglib like that.
Thoughts? Tips? Glaring errors or omissions?
Remove the def myExampleService from the subclass taglib. A property like that in Groovy compiles to a private field plus a public getter and setter, so in the superclass taglib you have implicitly
private Object myExampleService;
public void setMyExampleService(Object svc) {
this.myExampleService = svc;
}
// getter similar
When you declare myExampleService again in the subclass the subclass gets its own private field (with the same name) and the setter gets overridden to store the supplied value in this subclass field instead of the superclass one. Spring calls the setter to inject the service, so the end result is that the superclass private myExampleService never gets set, hence the null pointer exception when trying to call myExampleService.doMunge in the superclass.
The subclass has access to the superclass property via the inherited getter and setter so it doesn't need to re-declare it.
This is just a quick guess, but is you taglib class file located under /grails-app/taglib, or somewhere in your /src directory? I've noticed I can't get services to inject (automatically, at least) into classes located outside the /grails-app folder.
Given this relationship:
class A {
String name
static hasMany = [b:B]
}
class B {
String name
static belongsTo = [a:A]
}
I have an record b that I want to save. I've already discovered via working Grails reflection (omitted in the code example below) that it needs to be an instance of class B. Beyond that, record b only knows:
it has a relation "a"
relation "a"'s key
Since it's a dynamic case, we do not know and must discover:
relation "a" is to an instance of class A (so we can call A.find(a's key))
the "other side" of the relation - class A's perspective - is relation "b" (so we can call .addToB(b))
So how do I save b to the database? Here's how I'm doing it:
class AssocTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
// I don't know this part, but it's in the DB
def a = new A(name:"al")
a.save()
}
void testAssociation() {
// I want to create a new B such that name="bob"
// I also had to discover "class B" using (working) Grails reflection
// but omitted it for this example.
def b = new B(name:"bob")
// ... and the relation is as "given" below
def given = [a:[name:"al"]]
// So I need to call A.find([name:"al"]).addToB(b). But "A" and
// "addToB" are unknown so need to be found via reflection
def gdc = new DefaultGrailsDomainClass(B)
given.each { give ->
def prop = gdc.getPropertyByName(give.key)
if (prop.isAssociation() && !prop.isOwningSide()) {
println "I want to use otherSide, but it's ${prop.otherSide}"
def os = reallyGetOtherSide(B, give)
def object = os.parent.find(
os.parent.newInstance(give.value))
object."${os.method}"(b)
}
}
def bFound = B.findByName("bob")
assertEquals "al", bFound.a.name
}
def reallyGetOtherSide(clazz, relation) {
def parent=clazz.belongsTo[relation.key]
def addTo=parent.hasMany.find { (clazz == it.value) }.key
[parent:parent, method:"addTo${addTo.capitalize()}"]
}
}
...with otherSide returning null, unfortunately. This can't be the best way to do this, can it?
If I understood you correctly, You can refer to these docs here. You can try the following:
`new A(name:"Gatwick")
.addToB(new B(name:"BA3430"))
.addToB(new B(name:"EZ0938"))
.save()`