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.
Related
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
I have static method in a domain class that returns a url. I need to build that url dynamically but g.link isn't working.
static Map options() {
// ...
def url = g.link( controller: "Foo", action: "bar" )
// ...
}
I get the following errors:
Apparent variable 'g' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:
You attempted to reference a variable in the binding or an instance variable from a static context.
You misspelled a classname or statically imported field. Please check the spelling.
You attempted to use a method 'g' but left out brackets in a place not allowed by the grammar.
# line 17, column 19.
def url = g.link( controller: "Foo", action: "bar" )
^
1 error
Obviously my problem is that I am trying to access g from static context, so how do I get around this?
The g object is a taglib, which is not available inside a domain class like it would be in a controller. You can get at it through the grailsApplication as shown here: How To Call A Taglib As A Function In A Domain Class
A better way to do this in Grails 2+ is through the grailsLinkGenerator service, like so:
def grailsLinkGenerator
def someMethod() {
def url = grailsLinkGenerator.link(controller: 'foo', action: 'bar')
}
In both cases, you'll need to do some extra work to get grailsApplication/grailsLinkGenerator from a static context. The best way is probably to grab it off the domainClass property of your domain class:
def grailsApplication = new MyDomain().domainClass.grailsApplication
def grailsLinkGenerator = new MyDomain().domainClass.grailsApplication.mainContext.grailsLinkGenerator
If you're using Grails 2.x you can use the LinkGenerator API. Here's an example, I am re-using a domain class I was testing with earlier so ignore the non-url related functionality.
class Parent {
String pName
static hasMany = [children:Child]
static constraints = {
}
static transients = ['grailsLinkGenerator']
static Map options() {
def linkGen = ContextUtil.getLinkGenerator();
return ['url':linkGen.link(controller: 'test', action: 'index')]
}
}
Utility Class with Static Method
#Singleton
class ContextUtil implements ApplicationContextAware {
private ApplicationContext context
void setApplicationContext(ApplicationContext context) {
this.context = context
}
static LinkGenerator getLinkGenerator() {
getInstance().context.getBean("grailsLinkGenerator")
}
}
Bean Def for New Utility Bean
beans = {
contextUtil(ContextUtil) { bean ->
bean.factoryMethod = 'getInstance'
}
}
If you need the base URL, add absolute:true to the link call.
I would like to map some actions in a child class to their super class, but I cannot figure it out. Example below...
abstract class A {
abstract def foo()
def aAction1 = {
// do something
render(view: '/someView')
}
def aAction2 = {
SomeObject someObject ->
// do something
render(view: '/someView2')
}
}
class B extents A {
def foo() { return "Hello World" }
# map to parent action
# works fine
def jump = super.&aAction1
# doesnt work ... Why? and can I make it work?
def swim = { SomeObject someObject ->
super.aAction2(someObject)
}
}
Any ideas on this one? Thanks.
So it turns out it didnt work because the parameters were slightly different. It does seem to work as expected. If you are having issues with this, make sure that the parameters for any inherited classes are exactly the same as the parent.
I want to allow users to traverse the domain classes and print out dumps of stuff. My frist problem: assuming the following works just fine:
//this works
class EasyStuffController{
def quickStuff = {
def findAThing = MyDomainClass.findByStuff(params.stuff)
[foundThing:findAThing]
}
}
What is the proper way to write what I am trying to say below:
//this doesn't
class EasyStuffController{ servletContext ->
def quickStuff = {
def classNameString = "MyDomainClass" //or params.whichOne something like that
def domainHandle = grailsApplication.domainClasses.findByFullName(classNameString)
//no such property findByFullName
def findAThing = domainHandle.findByStuff(params.stuff)
[foundThing:findAThing]
}
}
//this also doesn't
class EasyStuffController{ servletContext ->
def quickStuff = {
def classNameString = "MyDomainClass" //or params.whichOne something like that
def domainHandle
grailsApplication.domainClasses.each{
if(it.fullName==classNameString)domainHandle=it
}
def findAThing = domainHandle.findByStuff(params.stuff)
//No signature of method: org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass.list() is applicable
[foundThing:findAThing]
}
}
Those lines above don't work at all. I am trying to give users the ability to choose any domain class and get back the thing with "stuff." Assumption: all domain classes have a Stuff field of the same type.
If you know the full package, you can use this:
String className = "com.foo.bar.MyDomainClass"
Class clazz = grailsApplication.getDomainClass(className).clazz
def findAThing = clazz.findByStuff(params.stuff)
That will also work if you don't use packages.
If you use packages but users will only be providing the class name without the package, and names are unique across all packages, then you can use this:
String className = "MyDomainClass"
Class clazz = grailsApplication.domainClasses.find { it.clazz.simpleName == className }.clazz
def findAThing = clazz.findByStuff(params.stuff)
Normally for a Grails domain or command class, you declare your constraints and the framework adds a validate() method that checks whether each of these constraints is valid for the current instance e.g.
class Adult {
String name
Integer age
void preValidate() {
// Implementation omitted
}
static constraints = {
name(blank: false)
age(min: 18)
}
}
def p = new Person(name: 'bob', age: 21)
p.validate()
In my case I want to make sure that preValidate is always executed before the class is validated. I could achieve this by adding a method
def customValidate() {
preValidate()
validate()
}
But then everyone who uses this class needs to remember to call customValidate instead of validate. I can't do this either
def validate() {
preValidate()
super.validate()
}
Because validate is not a method of the parent class (it's added by metaprogramming). Is there another way to achieve my goal?
You should be able to accomplish this by using your own version of validate on the metaclass, when your domain/command class has a preValidate() method. Something similar to the below code in your BootStrap.groovy could work for you:
class BootStrap {
def grailsApplication // Set via dependency injection
def init = { servletContext ->
for (artefactClass in grailsApplication.allArtefacts) {
def origValidate = artefactClass.metaClass.getMetaMethod('validate', [] as Class[])
if (!origValidate) {
continue
}
def preValidateMethod = artefactClass.metaClass.getMetaMethod('preValidate', [] as Class[])
if (!preValidateMethod) {
continue
}
artefactClass.metaClass.validate = {
preValidateMethod.invoke(delegate)
origValidate.invoke(delegate)
}
}
}
def destroy = {
}
}
You may be able to accomplish your goal using the beforeValidate() event. It's described in the 1.3.6 Release Notes.