Apologies, since there are lots of links out there and I have tried a few examples including stuff that already works within my project(s) that are non plugin:
What I have tried:
Within my Plugin descriptor:
def doWithSpring = {
someService(SomeService)
}
Then within my end src/groovy
//def someService = Holders.grailsApplication.mainContext.getBean 'someService'
def someService
None of above works...
If I instantiate the service everything appears to work fine, I would prefer to inject it and its just taking a lot of time doing something rather basic :(
SomeService someService=new SomeService()
Any help would be appreciated
Not that I have ever seen it before (within a plugin) should I include conf/spring/resources.groovy and initialise bean in there ?
In this case, like most cases, there's a way to access what you want without using holders. The Groovy class implements ServletContextListener, so there's a contextInitialized method with a ServletContextEvent event containing the ServletContext. So it wasn't necessary to use the ServletContextHolder to get the ServletContext - it was right there. You can see from the FAQ that the Spring ApplicationContext is stored in the ServletContext as an attribute. Once you have that, you can access whatever Spring beans you want; in this case the jenkinsService and the grailsApplication beans (you can get the config directly from the grailsApplication without using Holders for that.
I made these changes and did a bunch of cleanup, and sent a pull request.
You can inject your service in a src/groovy class like so:
import com.example.SomeService
import grails.util.Holders
class SrcGroovy {
SomeService someService = Holders.applicationContext.getBean("someService")
// ...
}
Related
I want to implement the concept of Trigger objects in Grails for my domain classes. Grails allows me to define methods like beforeInsert() in my domain classes to handle insert, update and delete events, similar to how SQL databases have the concept of database triggers. But to separate concerns I'd like to move all of the trigger logic outside of the domain class.
Ideally I can simply define a static list of trigger classes in my domain class and then iterate through those in the beforeInsert() method. Sample code shown below.
static beforeInsertTriggers = [AccountNameTrigger, AccountDumpTrigger]
def beforeInsert() {
for (Class<Trigger> triggerClass : beforeInsertTriggers) {
triggerClass.newInstance().using(this).execute()
}
}
I've created a sample Grails 2.5.4 project on GitHub illustrating what I'm trying to do. But the problem is that the triggers literally are standalone islands of logic without the ability to autowire services. How can I better set up this Trigger pattern or something similar? So I may autowire services and other beans into the Trigger instances?
I am also trying to keep the design simple and readable.
Avoid cluttering the domain class with fields and properties that are not related to the data model. To me this means no autowired beans in the domain class.
Define the list of triggers using the trigger class names (or bean names, if need be). This may be overly idealistic, but hey...
For what it's worth, part of my inspiration also comes from how Salesforce implements triggers as distinct units of self-contained code.
Register your Triggers as Singleton Beans and there you can inject other services/beans. You can create your custom beans via resources.groovy.
Lets take the example of AccountDumpTrigger. Lets make a simple change to it:
package grails.domain.trigger.demo.triggers
import grails.domain.trigger.demo.Account
import org.codehaus.groovy.grails.commons.GrailsApplication
/**
* Created by marty on 6/25/16.
*/
class AccountDumpTrigger extends AbstractTrigger<Account> {
GrailsApplication grailsApplication
#Override
void execute() {
println grailsApplication.isInitialised()
println resource.dump()
}
}
And code in resources.groovy or in your plugin's doWithSpring closure:
accountDumpTrigger(grails.domain.trigger.demo.triggers.AccountDumpTrigger) { bean ->
bean.factoryMethod = 'getInstance'
/*
either refer each bean individually or you can use:
bean.autowire = "byType"
OR
bean.autowire = "byName"
*/
grailsApplication = ref("grailsApplication")
}
And inside your domain:
static beforeInsertTriggers = [AccountDumpTrigger]
def beforeInsert() {
for (Class<Trigger> triggerClass : beforeInsertTriggers) {
triggerClass.instance.using(this).execute()
}
}
And instead of writing your code inside beforeInsert you can also do the same by registering an implementation of AbstractPersistenceEventListener. This way you don't have to repeat your code. Also yo can move it to a parent class.
How do I access "grailsApplication" of the main application from a plugin?
An example situation:
I have a class in a plugin, which needs to get a resource link from the main application, which is usually retrieved via "grailsApplication". How do I do that?
SOLUTION
In the plugin class you may simply specify:
import grails.util.Holders
Holders.getGrailsApplication()
In services, you should be able to add
def grailsApplication
and it will be injected into your service.
If your class is a spring bean, then you should be able to inject it inside the
def doWithSpring = { ->
myBean( org.whatever.BeanClass ) {
grailsApplication = ref( 'grailsApplication' )
}
}
block of the plugin main groovy file.
If it's neither of these, have you tried using the Holders class?
def grailsApplication = grails.util.Holders.getGrailsApplication()
I am trying to access grailsApplication in groovy class under src/groovy but I get a null pointer exception. I also tried to inject a service into the same class and same result. How can I access grailsApplication or a service from groovy class? (I am using Grails 1.3.7)
The ApplicationHolder class is deprecated in newer Grails versions (2.0 and above).
There is another way, which is described in one of Burt's blogposts: http://burtbeckwith.com/blog/?p=1017
After Grails 2.0, you should use:
def grailsApplication = Holders.grailsApplication
Dependency injection does not work for groovy classes under src/groovy. You can get the access to grailsApplication using ApplicationHolder like this:
import org.codehaus.groovy.grails.commons.ApplicationHolder
def grailsApplication = ApplicationHolder.application
You can access all services like this:
def allServicesArtefacts = grailsApplication.services
If you have classes that you want to participate with dependency injection from src/groovy or src/java or even 3rd party jars all you have to do is configure them in grails-app/conf/spring/resources.groovy.
If you had the class mypackage.MyClass in your src/groovy directory that looked like this:
package mypackage
class MyClass{
def grailsApplication
def myMethod(){
//uses grailsApplication
}
}
Then by adding the following to grails-app/conf/spring/resoruces.groovy it would get auto-injected:
myClass(mypackage.MyClass){bean->
bean.autowire = "byName"
}
This will work in any version of grails thusfar, and like I said you can even use 3rd party jars - for example I ALWAYS have the following in my resources.groovy:
jdbcTemplate(org.springframework.jdbc.core.JdbcTemplate){
dataSource = ref('dataSource')
}
For more comprehensive Spring/Grails documentation see:
http://grails.github.io/grails-doc/latest/guide/spring.html
I've a Grails project where I replaced Log4j with Logback. Now I also want to use the org.slf4j.Logger instead of org.apache.commons.logging.Log class for logging. How can I change the default log object which is placed by Dependency Injection to every Controller/Service/Domain class?
I searched within the BuildConfig.groovy and Config.groovy files but I couldn't find any configuration for this? I also looked at grails-app/src/templates/artifacts/Controller.groovy but I still couldn't find any place where this could be configured...
Shure, I could get my own instance of an org.slf4j.Logger, but then I'd have to declare it within every class like
private static Logger lbLogger = LoggerFactory.getLogger(MyClass.class)
and that's not what I want - I'd love to just replace injected Logger object.
Does anybody have any suggestions on this topic?
I can't recall how the log object been injected, but anyway you can inject your own logger into controller, service or domain object.
In BootStrap:
def doWithDynamicMethods = { applicationContext ->
// def logger = SLF4J new instance
application.controllerClasses.each { controllerClass ->
controllerClass.metaClass.getLogger = {-> logger }
}
}
This is the idea, sorry I don't have the Grails env now so I can not make a workable code.
I'm relatively new to the Grails community, but I love already what the engine has to offer. Currently, I'm implementing a custom tag library in order to easily facilitate a standard design on our pages. However, I need a way of calling helper functions for utility purposes (e.g. filtering data) and to stash request level meta data about my tags (e.g. counters, parent/child relationships).
I have attempted two solutions:
First: I've created a service, set its scope to "request"
package myapp
class CustomTagService {
static scope = 'request'
def data = []
def add(localData) {
data.add(localData)
}
}
However, when I try to inject it in my tag library
package myapp
class MyTagLib {
def customTagService
def myTag = { attrs, body ->
customTagService.add(attrs)
}
}
The engine yells at me for referencing a request scope (after a long painful stacktrace): "Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton"
Second: I understand the pageScope is available to me inside of a tag closure, and I've exploited it before. However, for the structure I am wanting, encapsulation would be much preferred.
Please let me know if I am going down the wrong path on this. Any suggestions would be much appreciated!
You can't use scoped beans in singleton beans since the singleton beans (including taglibs) are created at startup when there's no request active. Instead use a scoped proxy (a bit complicated) or just get the bean from the ApplicationContext for each use at runtime when there is an active request:
package myapp
class MyTagLib {
def grailsApplication
def myTag = { attrs, body ->
customTagService.add(attrs)
}
private getCustomTagService() {
grailsApplication.mainContext.customTagService
}
}