I would like to utilize a service written in Java in my Grails app using dependency injection. Creating it in Java without injection would look like this:
ServiceFactory.newInstance().getElementService()
I would like to use this in the same way services are injected for controllers, services, and jobs.
class ImportJob {
def elementService
...
}
I know this should go into resources.groovy and this is what I have so far:
serviceFactory(ServiceFactory) { bean ->
bean.factoryMethod = 'newInstance'
}
elementService(ElementService) {
}
I have found few resources in the documentation to help with this. How do I complete the elementService so it is creating the object as described above? Should I use a BeanBuilder?
You could create a FactoryBean for this since it's not as direct as calling a method in a class:
package com.mycompany
import org.springframework.beans.factory.FactoryBean
import org.springframework.beans.factory.InitializingBean
class ElementServiceFactoryBean implements FactoryBean<ElementService>, InitializingBean {
private ElementService elementService
ElementService getObject() { elementService }
Class<ElementService> getObjectType() { ElementService }
boolean isSingleton() { true }
void afterPropertiesSet() {
elementService = ServiceFactory.newInstance().elementService
}
}
and you'd register it in resources.groovy as
elementService(ElementServiceFactoryBean)
Use bean.factoryMethod and bean.factoryBean in the elementService bean.
serviceFactory(ServiceFactory) { bean ->
bean.factoryMethod = 'newInstance'
bean.scope = 'singleton'
}
elementService(ElementService) { bean ->
bean.factoryMethod = 'getElementService'
bean.factoryBean = 'serviceFactory'
}
This is a simple solution especially if ServiceFactory is external and cannot be changed.
Related
So I have a class where I need to inject a service in grails.
class APIPaymentCreateCommand implements CreateCommand {
def cardTokensService
}
I have tried the following pattern below but none of them seem to be injecting the service.
resources.groovy:
// 1
aPIPaymentCreateCommand(APIPaymentCreateCommand) { bean ->
bean.autowire = 'byName'
}
// 2
apipaymentCreateCommand(APIPaymentCreateCommand) { bean ->
bean.autowire = 'byName'
}
// 3
APIPaymentCreateCommand(APIPaymentCreateCommand) { bean ->
bean.autowire = 'byName'
}
I have found the link below so I'm assuming the issue is around the class naming not being compliant with grails. Renaming the class is a last resort as it has a lot of dependency so trying to avoid that approach.
Any help or approach I should try would be greatly appreacited!
How to autowire a service in grails (2.5.5) with multiple capital letters at front
See the project at https://github.com/jeffbrown/kennanwhoserviceinjection.
https://github.com/jeffbrown/kennanwhoserviceinjection/blob/188f64d7fff55a24c466c17c26763e3f489d0774/grails-app/services/kennanwhoserviceinjection/CardTokensService.groovy
package kennanwhoserviceinjection
class CardTokensService {
int getTheAnswer() {
42
}
}
https://github.com/jeffbrown/kennanwhoserviceinjection/blob/188f64d7fff55a24c466c17c26763e3f489d0774/src/groovy/kennanwhoserviceinjection/APIPaymentCreateCommand.groovy
package kennanwhoserviceinjection
class APIPaymentCreateCommand {
def cardTokensService
int getTheAnswer() {
cardTokensService.theAnswer
}
}
https://github.com/jeffbrown/kennanwhoserviceinjection/blob/188f64d7fff55a24c466c17c26763e3f489d0774/grails-app/controllers/kennanwhoserviceinjection/DemoController.groovy
package kennanwhoserviceinjection
class DemoController {
APIPaymentCreateCommand aPIPaymentCreateCommand
def index() {
int answer = aPIPaymentCreateCommand.theAnswer
render "The answer is $answer"
}
}
https://github.com/jeffbrown/kennanwhoserviceinjection/blob/398a46efe373b5f2bafbdbbb9c25f017f9be244e/grails-app/conf/spring/resources.groovy
import kennanwhoserviceinjection.APIPaymentCreateCommand
beans = {
aPIPaymentCreateCommand(APIPaymentCreateCommand) { bean ->
bean.autowire = 'byName'
}
}
That all works. I used the first of your example bean definitions from resources.groovy but the others would work too (assuming the bean name was kept in sync in DemoController.groovy).
Grails 2.4.x here. If I created a Grails service using grails create-service com.example.Widget, then how can I inject a reference of that service (a "bean") into a class under src/groovy?
This is actually not explained anywhere in the official Grails docs, and extensive searching turned back nadda.
1) You can use Spring Beans to inject a service into a non-artefact groovy file, using resources.groovy:
MyClass.groovy
class MyClass {
def widgetService
...
}
resources.groovy
beans = {
myclass(com.example.MyClass) {
widgetService = ref('widgetService')
}
}
2) There is also an additional #Autowired annotation that can do the same thing:
MyClass.groovy
import org.springframework.beans.factory.annotation.Autowired
class MyClass {
#Autowired
def widget
...
}
resources.groovy
beans = {
myclass(com.example.MyClass) {}
}
Notice - this time the myclass bean doesn't need the reference to the widget.
3) There is an alternative to injecting the WidgetService - using the Holders class to get the grailsApplication which will have a reference to the existing bean.
import grails.util.Holders
class MyClass {
def widgetService = Holders.grailsApplication.mainContext.getBean('widgetService')
...
}
**Update**
4) There is another option that is a hybrid of 1) and 2) -
Having the bean(s) injected by autowire=true within resources.groovy:
MyClass.groovy
class MyClass {
def widgetService
...
}
resources.groovy
beans = {
myclass(com.example.MyClass) { bean ->
bean.autowire = true
}
}
This is the approach I've been using locally as I feel it's the cleanest, but it does take more advantage of Grail's 'magic' (for better or worse).
I'd like to use data generator at init in my application. It works fine when create objects using .save() method, but it doesn't work when I want to use dedicated services, because of null pointers instead of injected services. That's my code:
I have defined DataGenerator bean inside conf/spring
beans = {
dataGenerator(DataGenerator)
}
My Bootstrap.groovy looks like:
class BootStrap {
def dataGenerator
def init = { servletContext ->
dataGenerator.generateData()
}
}
In `DataGenerator' I have:
class DataGenerator{
BookService bookService
def generateData() {
log.info("Generating books")
createBooks()
}
def createBooks(){
(1..40).each() {
CreateBookCommand command = new CreateBookCommand()
/* some command populate code*/
bookService.create(command);
}
}
}
The problem is, that I cannot invoke create() method, because bookService is always null
BookService is simple grails service with some dependencies, of course placed in grails-app/services
class BookService {
UserService userService
SpringSecurityService springSecurityService
def create(CreateBookCommand command){
Book book = new Book()
command.bindTo(book)
book.save(flush:true, failOnError:true)
}
/*some other methods*/
}
Could you tell me how to fix it?
Try this in resources.groovy
beans = {
dataGenerator(DataGenerator) { bean ->
bean.autowire = 'byName'
}
}
I assume DataGenrator being a class outside the grails artifact (that is: placed in src/groovy), you can refer the already available service class in the context as:
beans = {
dataGenerator(DataGenerator){
bookService = ref('bookService')
}
}
or try autowiring byName as mentioned by #sudhir.
I have some (non-Grails-artifact) classes that access the service layer beans via passing around the grailsApplication object. However I'm having trouble unit testing the classes implemented in this way. Why doesn't the bean get registered in the main context?
#TestMixin(GrailsUnitTestMixin)
class ExampleTests {
void setUp() {}
void tearDown() {}
void testSomething() {
defineBeans {
myService(MyService)
}
assert grailsApplication.mainContext.getBean("myService") != null
}
}
The above code fails with:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myService' is defined
What I'm trying to do is access services from plain old Java classes via the grailsApplication. This works, but not in unit test environment. Should I do it differently?
class POJO {
MyService myService;
public POJO(GrailsApplication grailsApplication) {
myService = (MyService) grailsApplication.getMainContext().getBean("myService");
}
}
The answer is that in the GrailsUnitTestMixin the applicationContext that holds your beans is set as the parentContext in the grailsApplication
beans.registerBeans(applicationContext)
static void initGrailsApplication() {
...
//the setApplicationContext in DefaultGrailsApplication set's the parentContext
grailsApplication.applicationContext = applicationContext
}
So you can get your beans with:
defineBeans {
myService(MyService)
}
assert applicationContext.getBean("myService")
assert grailsApplication.parentContext.getBean("myService")
EDIT
Today I faced the same problem, and my solution is:
#Before
void setup() {
Holders.grailsApplication.mainContext.registerMockBean("myService", new MyService())
}
In my case (grails 2.4.4) the accepted solution didn't work but pointed me in the right direction, this line worked instead as the bean factory in the mainContext within my unit test was an OptimizedAutowireCapableBeanFactory
Holders.grailsApplication.mainContext.beanFactory.registerSingleton('myBean', new MyBeanClass())
I have spent some time with the same issue, in my case running grails 2.2.4 and having (in src/groovy):
import grails.util.Holders
class SomeClass {
transient myService = Holders.grailsApplication.mainContext.getBean 'myService'
.....
}
Which is a bit different to question author, but at least it will be useful for someone coming from search engine results
Nevertheless accepted answer did not work for me, so I came up with a bit different approach of mocking and registering service used in SomeClass.
import grails.util.Holders
.. other imports
#TestMixin(GrailsUnitTestMixin)
class SomeClassTests {
#Before
void setUp() {
Holders.grailsApplication = grailsApplication
defineBeans {
myService(MyServiceMock)
}
}
....
}
class MyServiceMock extends MyService {
// overriden methods here
}
I am currently updating my Grails project in order not to use the deprecated ConfigurationHolder class.
This goes fine in most cases, but I am facing trouble in my custom codec classes, where I have been using the following approach until now:
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
class MyCodec {
static boolean myStaticConfigProperty=CH.config.myStaticConfigProperty
static encode = { something ->
if(myStaticConfigProperty)
...
}
}
Direct injection using
def grailsApplication
does not work in this case since this will be injected as a non-static object.
Instead I have tried to use the approach suggested in this post getting-grails-2-0-0m1-config-info-in-domain-object-and-static-scope, but I cannot make it work even after injecting the grailsApplication object into my codec metaclasses in the bootstrap:
class BootStrap {
def grailsApplication
def init = { servletContext ->
for (cc in grailsApplication.codecClasses) {
cc.clazz.metaClass.getGrailsApplication = { -> grailsApplication }
cc.clazz.metaClass.static.getGrailsApplication = { -> grailsApplication }
}
}
}
Could anyone suggest an approach that will allow me to access the config object in a static way inside codec classes?
I'd suggest something like this completely untested code:
class MyCodec {
static def grailsConfig
static boolean myStaticConfigProperty = grailsConfig.myStaticConfigProperty
static encode = { something ->
if(myStaticConfigProperty)
...
}
}
class BootStrap {
def grailsApplication
def init = { servletContext ->
for (cc in grailsApplication.codecClasses) {
cc.grailsConfig = grailsApplication.config
}
}
}
If all of your codec classes just need the same one configuration property, you could skip injecting the grailsApplication and/or the config object entirely, and just set the one static property from BootStrap.
it works for me in grails 2.2.3
import grails.util.Holders as holders;
class MyFileCodec {
static encode = {file ->
def configPath= holders.grailsApplication.config.share.contextPath
return "${configPath}/${file.name}"
}
}
grails.util.Holders has been introduced since grails 2.0, it's the way to access config object.