I am using the AWS plugin for grails. I am trying to use the sesMail closure from a Groovy class, not a service or controller e.g. in a method:
String msgId = sesMail {
from props.from
replyTo props.replyTo
to prop.to
html props.body
}
I am getting an error saying sesMail is not a method of the Groovy class. My questions are:
How can I call a plugin closure that is ordinarily available in grails service and controllers from a regular Groovy class
Following that I'm curious how these closures are defined and made available in the service and controller. I can't find a definition of sesMail in the plugin.
thanks
Good Question. And I appreciate that you are curious to find the root cause of your problem. Here are your answers:-
You can directly call the SendSesMail bean to send mail instead of calling the sesMail closure. Your groovy class would look like:
class MyGroovyClass{
def sendSesMail
def sendSomeMails(){
String msgId = sendSesMail.send{
from props.from
replyTo props.replyTo
to prop.to
html props.body
}
}
}
As you can see SendSesMail is not a service class it is just a POGO, so it will not be autowired in this groovy class unless you define that in resources.groovy. So:
Something like:
//resources.groovy
beans = {
sendSesMail(grails.plugin.aws.ses.SendSesMail)
}
Also keep a note by using the above method directly you would be bypassing grails.plugin.aws.ses.enabled configuration. So you have to handle it explicitly.
You can very well find the definition of sesMail method which is metaClasses over target classes to take a Closure as an argument here in MetaClassInjector. This class is basically used to inject/add dynamicMethods from the plugin definition. You can find it as
AwsGrailsPlugin (Line: 37) --> AwsPluginSupport (Line: 86) --> MetaClassInjector (Line: 50)
You can also see in MetaClassInjector (around line 45 and 46), the target classes are controller and service classes. Hence you find the closure sesMail available in those 2 artefacts.
I hope it is clear enough to address your curiousness. :)
Related
I'm starting to learn grails and there is some groovy syntax that I don't get at all, and is undocumented as far as I can tell because I don't know what it's called.
What are 'grails', 'views', and 'gsp' in the code below?
grails {
views {
gsp {
encoding = 'UTF-8'
// ...
}
}
}
Thanks!
p.s. I feel like an idiot for not being able to figure this out...
This is an example of DSL (domain specific language) code. In Groovy, many DSLs are implemented as Groovy code, although sometimes it can look pretty funky. This code block is run as Groovy code, and it's more clear that it's code if you add in the omitted optional parentheses:
grails({
views({
gsp({
encoding = 'UTF-8'
// ...
})
})
})
and more so if we replace the property set call to the equivalent method call
grails({
views({
gsp({
setEncoding('UTF-8')
// ...
})
})
})
If you ran this in a console or as part of other Groovy code or in a Grails app it would fail, because there's no 'grails' method taking a closure as an argument, or a similar 'views' or 'gsp' method, and there's no setEncoding(String) method either. But when run as DSL code, often the code is run inside a closure whose delegate is set to a DSL helper class that handles the resulting methodMissing and propertyMissing calls.
This helper looks at the method name and the number and/or types of the method arguments (or property name and value type) and if they are valid for the DSL, it does the corresponding work, otherwise it throws a MissingMethodException/MissingPropertyException, or a DSL-specific exception, or handles the problem some other way.
In this case, there's a configuration DSL handler that translates these method calls into config property calls.
There are several other DSLs in use in a Grails app that work the same way. The mapping and constraints blocks in domain classes, the grails.project.dependency.resolution block in BuildConfig.groovy, etc. All are evaluated as Groovy code, and the missing method/property calls configure GORM mappings, constraint definitions, plugin dependencies, etc.
Programming Groovy 2 is a particularly good Groovy book for learning DSLs.
I'm trying to update a plugin to Grails 2.4. Thus I have to replace the deprecated ApplicationContext class by the newer Holders class.
But I'm having some problems getting a service bean from the Holders class.
Running the code below:
import grails.util.Holders;
def myService = Holders.grailsApplication.mainContext.myService
println myService
println myService.getClass()
println myService.serviceMethod()
It prints something like:
grails.plugin.my.MyService#1e5cd54d
Exception thrown
java.lang.NullPointerException
at ConsoleScript2.run(ConsoleScript2:6)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1270)
It throws a NullPointerException when I call both: the "getClass" method and the "serviceMethod" method.
I tryed to see what's happening by debugging from eclipse too and I can observe "myService" variable being set to an object. When I click on it I can see it's String representation just like printed above. But I can't see anything inside the object. This service' class has member variables, but I can't see them on debug. It's like uf they were'nt there.
Can someone explain me what is going wrong?
Thanks
Don't use Holders, and avoid pulling in dependencies. Use dependency injection, it's a Good Thing.
Your src/groovy class is probably called from a controller, service, Quartz job, or some other Grails artifact that supports DI, right? If so, inject this service there, and when you call your src/groovy class, pass it as a method argument, or inject it once in a constructor or a setter.
Even if it's not called from a Grails artifact it's likely easy to get access to the service. E.g. a servlet can access the ServletContext and it's simple to access the ApplicationContext from there.
How do I replace methods of an existing java class (GrailsDataBinder in my case).
I read that method calls for java classes doesnt go through invokeMethod, and hence it doesn't work, but I think there would be some solution.
I just tried this
GrailsDataBinder.metaClass.static.createBinder = {Object target, String objectName ->
throw new RuntimeException()
}
And this
GrailsDataBinder.class.metaClass.static.createBinder = {Object target, String
objectName -> throw new RuntimeException()
}
But that did not seem to have replaced the method, as my closure isn't being invoked, but instead the original method executes.
update
I just found that the closure is being executed if I call the createBinder from the test class itself - so it works and method is replaced
void testDataBinder() {
GrailsDataBinder.createBinder(null, null)
}
However When it is invoked from DataBindingUtils, it always executes original method (DataBindingUtils is also a java class)
Following is the code inside DataBindingUtils that invokes the method.
binder = GrailsDataBinder.createBinder(object, object.getClass().getName());
Note : There are some similar questions asked earlier, but none of them have worked for me.
This is disappointing once you see the power of Groovy. However, as you already know, many of the cool metaclass etc. features available in Groovy simply don't work as you would like on Java classes.
If you are trying to override, stub or mock stuff on a Java class for unit testing etc., I advise looking into Spock, because it uses 'magic' that actually works on Java classes also.
If you are try to override methods for some other reason, you should try extending the Java class with a Groovy class or 'wrapping' the Java class with a Groovy class to gain the metaclass features you want when external classes call you classes methods. Unfortunately this still won't allow you to intercept calls that the Java class makes to itself.
I am attempting to add some string utility methods to the String class by utilizing Groovy's metaclass functionality. Right now I have something like this in my init closure in my BootStrap.groovy script:
String.metaClass.upper = {
delegate.toUpperCase()
}
The problem is that this upper method is only available within the scope of the BootStrap...trying to use it anywhere else in the Grails app does not work and I get method missing errors.
Is there any way to make those methods available everywhere?
Does this happen in both testing and running contexts? There is a bug where all metaClass changes get rolled back after each unit test: http://jira.grails.org/browse/GRAILS-8596
The Grails documentation defines a "count" static method, defined in the documentation like this:
Description
Counts the number of instances in the database and returns the result
Parameters
None
Example
def noOfBooks = Book.count()
However, whenever I call it, I get this error! I simple added a call to the name of my Domain Class (Company) like this to a working Controller
def companies = Company.count()
and when it exectutes that line, it blows up with the following error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.RuntimeException: Unable to locate constructor with Class parameter for class org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
Other, working, code in the controller (pre-generated with the static scaffolding commands) access Company.get(...) etc, with no error
What am I doing wrong?
This
class HomeController {
def companies = Company.count()
def index = {
render(view:"index")
}
}
Fails because as lael pointed out the count() method is not available when the application is started. The count() method is a Dynamic method which GORM addeds to the domain classes. Spring (the underlying framework) creates an object for every artifact (Controller/Service/Domain Class etc) at start up. GORM would be after this.
Spring is trying to create a HomeController class, the construction of Home Controller will assign the value of company.count to Companies at startup, However GORM has not started yet so the dynamic methods have not been added.
This code is incorrect anyway, if it did work then the companies variable would only have the value of the number of companies at start up of the application. Once you get "used" to groovy and grails I think you will appreciate the speed of development.
Hope this helps.
The short answer is that the count() method and many others are added to the metaClass at runtime after the Hibernate Plugin is loaded. count() isn't a static method that is available at compile time as Java does it, but rather a static method that is added to the Domain's metaClass at runtime (apparently after parsing the controllers).
Why? Because it doesn't make sense to have count(), get() or read(), etc. methods until after Hibernate/GORM is initialized. It would not be hooked up to the datasource and the methods would be invalid.
I can't help but wonder why you would need to put a property like that on a controller. As soon as you save a new Company or delete one - your companies count would be off.
The long answer would be diving into Grails' source, From the GORMNamespaceHandler -> GORMSessionFactoryDefinitionParser -> GORMEnhancingBeanPostProcessor -> HibernatePluginSupport -> HibernatePluginSupport.addBasicPersistenceMethods()