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.
Related
I am currently running into an issue where I am attempting to use a service within a service however the service is null
class ApplicationService{
def someService
def someMethod(){
someService.method()//null on someService
}
}
Is there additional wiring that I need to perform for this to work? Thanks in advance for your help.
I was able to do this by using the grailsApplication and loading the service.
if(!someService){
someService = grailsApplication.classLoader.loadClass("org.company.SomeService").newInstance()
}
The most possible explanation i here is, the class behind SomeService is not a Grails service artefact thus you cannot just inject it like that.
Double check on the source code whether that class is really a service or just a Groovy class in src/groovy. The framework will treat these two differently.
Also do not attempt to inject service with manually creating the instance like your answer, that is not the correct way to do dependency injection in Grails (or in Spring).
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. :)
Assuming I have a data access object that I've already written, I'd like to be able to use CDI to inject that into say, a service class. Furthermore, I have two implementations of that DAO.
My understanding of CDI is that I'd have to annotate my DAO implementation class so that CDI would know which implementation to inject.
The problem is, the DAO is in a .jar file. By annotating it with CDI annotations, I'm using JavaEE imports in a non-JavaEE class.
For example, let's say I have the following class
public class BusinessService {
#Inject #SomeMybatisQualifier AccountDAO accountDao;
...
}
The #Inject annotation comes from javax.inject.Inject. Now, this service class is dependent on a JavaEE environment.
Can someone please explain to me what I'm missing? How do I inject a non-annotated class into another non-annotated class? This is fairly simple with Spring.
I agree with LightGuard if there's enough classes. But for a couple, why not just produce them with #Produces?
Here's a decent example of implementing your own producer:
Depedency inject request parameter with CDI and JSF2
You should be able to write return new MyObject(); and you can add whatever qualifiers you want
Not sure what's unclear but here's the gist of things: For CDI to scan a jar for beans it must have a beans.xml. Else it will not be scanned and thus not available for injects.A String is not available either. If you try to inject a String say;
#Inject
String myString;
CDI will have no clue what to give you just like your jar. But I know what String I want (a requestparam) and I can let CDI know as well. How? Well I supply a qualifier #RequestParam to my producer (see example again) and now when I want to use it in client code I do it like this:
#Inject
#RequestParam
String myString;
You can do the same thing. Have a producer and just create a new instance of whatever you need and then return it. Now CDI will know just how to dependency inject that particular bean.
Now say you have 40 classes. Then it gets messy to produce them and you want to make sure it gets scanned instead. Then you write your own little extension, observe when CDI is about to scan and instruct it to scan additional jars. Such extension is probably easy to write but I don't know the details because I have not written any extensions like it
By far, the easiest thing would be to create a CDI extension to add the classes in the jar (because there's no beans.xml in that jar so it won't be picked up by CDI) and add additional qualifiers to the metadata.
Can we call service from a plugin? For example I have a plugin, it has its own domain, so now can we call the service of the main application from this domain ?
You can inject it yourself in Bootstrap.groovy, as all is initialized at that time.
Maybe better approach would be to autowire it with something like:
def ctx = grailsApplication.mainContext
ctx.beanFactory.autowireBeanProperties(instance, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false)
Where instance is some object from the plugin.
Another approach is to use Bean PostProcessors http://www.intelligrape.com/blog/tag/bean-post-processing/
Also I really recommend "Programming Grails" book, where you can read about such problems and how to resolve them.
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()