Change the name of an injected service in grails - grails

Can't seem to find info on this, if you have some, please point me to the right thread/post/link!
I have a service, lets say it's called 'SomeServiceWithAReallyLongNameICannotChange'. Of course the normal way to use services is to allow grails to inject them using either typless or typed notation:
class SomeClass{
//...
def someServiceWithAReallyLongNameICannotChange
//...
}
-- or --
class SomeClass{
//...
SomeServiceWithAReallyLongNameICannotChange someServiceWithAReallyLongNameICannotChange
//...
}
What I would like to do is rename the service to something shorter, but only where I'm using it, as I cannot change the name of the actual service. I tried using 'as' notation like you do with imports, and I tried changing the name in the typed declaration, but none of these things seem to work. Is this possible?
I tried something like this:
class SomeClass{
//...
def someServiceWithAReallyLongNameICannotChange as SS
//and I tried
def SomeServiceWithAReallyLongNameICannotChange SS
//no joy
//...
}
Thanks for your help!

The solution is to use autowire by type. By default grails uses autowire by name and hence you have to declare the service with the same name as the bean.
Here's example
class FooController {
boolean byName = false //set autowire by type
SomeReallyLongService service
}
You have to define a boolean variable byName and set it to false
You can not use def but must use the actual type of the service when declaring the service
It will enable autowire by type for whole controller, so all other dependencies will also be autowired by type
It is explained here
Update:
It is even possible to use Autowired annotation along with Qualifier.
Example:
class MyController {
#Autowired
#Qualifier("myServiceWithDifferntName")
def someService
}

You should be able to create a new bean via resources.groovy
beans = {
ss(SomeServiceWithAReallyLongNameICannotChange)
}
You can then inject it normally:
class SomeClass {
//...
def ss
//...
}

Another option, if you don't want to use autowire by type through the whole controller, nor do you want to add a custom bean for some reason, is to add a simple method to your controllers where you need the service, like so:
def someServiceWithAReallyLongNameICannotChange
def getSS() { someServiceWithAReallyLongNameICannotChange }
Then you could reference the service using ss.someMethod() anywhere within that controller.
However, this still requires you to add a chunk of code for every controller you use this service, or you will have inconsistent naming of the service.
(Personally, I think that doelleri's method is the best, since it allows you to be consistent in naming without modifying individual classes.)

I tried it and it's not working for me on Grails 3, did this by doing
import org.springframework.beans.factory.annotation.Autowired
...
#Autowired
PaymentStrategyService paymentStrategySvc

Related

How can I inject a custom service not associated with any domain class in grails?

I wish to make DAO layer in my grails project which would be not be associated with any of the domain classes and would be interacting with the secondary database of my project. I get the following error when I try to inject the service in any controller:
"Cannot invoke method abc() on null object"
However, the error is resolved and works perfectly when I initialise the service using the new keyword in the controller but I know that shouldn't be necessary as grails is supposed to handle it. Can anyone tell me what am I missing?
I don't think the issue has anything to do with whether or not the service is associated with a domain class. The DI container doesn't know anything about that.
If you have a controller like this:
// grails-app/controllers/demo/SomeController.groovy
package demo
class SomeController {
SomeService someService
def someControllerAction() {
someService.abc()
// ...
}
}
And a service like this...
// grails-app/services/demo/SomeService.groovy
package demo
class SomeService {
void abc() {
// ...
}
}
That will work fine.
It is almost impossible to say for sure without seeing what your code what you are doing wrong but one possibility is something like this, which will not work:
// grails-app/controllers/demo/SomeController.groovy
package demo
class SomeController {
def someControllerAction() {
// This is a local variable, not
// a property and as such will not
// be subjected to dependency injection.
SomeService someService
// ...
someService.abc()
// ...
}
}
Also, make sure the property name (someService in the sample above) matches the service class name, but with a lower case first letter (more generally, make sure the property name matches the property name representation of the service class name, which is usually as simple as lower casing the first letter of the class name).

How to autowire a service in grails (2.5.5) with multiple capital letters at front

I have a domain class named ABCDCode and created a service for the this ABCDCodeService. Now I want to use this service in controllers so I wrote it like below:
class TestController{
ABCDCode abcdCode
def index(int id){
abcdCode.getData(id) //Here I am getting NullPOinterException
}
}
I am suspecting something wrong with the autowiring by name.
class TestController{
ABCDCode aBCDCode
}
should work
You have multiple issues.
1) You assign a member variable but it is never initialized, therefore you get a NullPointerException. You need to get the instance from your database by id first.
2) Be aware that the controller needs to be thread-safe, by assigning the member variable in the controller scope it will be used for many calls at the same time with unpredictible outcome.
3) Names like ABCDCode are against grails naming conventions. Use AbcdCode for the domain and AbcdCodeService for the service and all is well.
This would be the correct approach with the domain class AbcdCode and the corresponding service AbcdCodeService:
// if not in the same module
import AbcdCode
class TestController {
// correct injection of the service
def abcdCodeService
// ids are Long, but you could omit the type
def index(Long id) {
// get instance from database by id, moved to method scope
def abcdCode = AbcdCode.get(id)
// note the "?." to prevent NullpointerException in case
// an abcdCode with id was not found.
def data = abcdCode?.getData()
}
}
Grails looks first two characters for beans naming. If the second character of the controller/service is capital then Grails did not convert the first character to lower case.
e.g., TestService bean name is testService and TEstService bean name is TEstService.
So, your code becomes
ABCDCode ABCDCode
def index(int id){
ABCDCode.getData(id)
}
But if you want to user abcdCode as bean name, then you can do this with the help of resources.groovy. Add the following to your resources.groovy file--
beans = {
springConfig.addAlias 'abcdCode', 'ABCDCode'
}

GORM Trigger pattern in Grails 2.5.4

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.

Play Framework: Dependency Injection inside Action

Short version: how to inject an object inside Action in Play Framework?
Long version: In my project I have custom annotation action #AuthenticationRequired which loads User object from the database and puts it into context.args. It uses DAO class that implements UserDAO. Now I want to use DAO class injected into Action by Google Guice. I can use Guice and inject instances in controllers and tests, but I have difficulties injecting DAO class inside Action.
Injector is a field on GlobalSettings instance.
I tried to override GlobalSettings#onRequest() and put UserDAO instance to context.args and then retrieve it from inside AuthenticationRequired action, but it turns out that Action returned by GlobalSettings#onRequest() being called last in the chain of action used with #With and/or custom annotations, so, it is to late.
I also tried to inject DAO instance by annotating action constructor, but but it uses no-args constructor to create an instance of action.
Any ideas how can I achieve this?
For play 2.5 you can simply add #Inject on top of the constructor of Action class and inject whatever needed. Here is a snippet from my working project (I'm using Guice as DI):
public class ChannelPermissionAction extends Action<ChannelPermission> {
private final AuthorizationService authorizationService;
private final AsyncHelper asyncHelper;
#Inject
public ChannelPermissionAction(AuthorizationService authorizationService, AsyncHelper asyncHelper) {
this.authorizationService = authorizationService;
this.asyncHelper = asyncHelper;
}
...
}
You can achieve this just the same as with controllers - describe your action as (a bean in my case - i'm using spring IoC) a dependency and get it called by
public <A> A getControllerInstance(Class<A> clazz)
of Application Global object. That's all you need - you'r dependencies would be injected.
BTW. Actions need to be created with each instance so in my case I should use "prototype" scope.
Mind it while using Guice - it should have similar functionality.

How to access the g.-namespace in a Domain Class

I would like to make use of the g.message() functionality in the toString method of my domain class, but the g.-namespace is not accessible by default.
I doubt that a import g.* will do the trick.
I already know that I can use the messageSource functionality, but it would be nicer to use the same syntax as in the views.
You can use:
class MyDomain {
def someMethod() {
def g = ApplicationHolder.application.mainContext.getBean( 'org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib' )
return g.message(....)
}
}
or else you can get messageSource directly: ApplicationHolder.application.mainContext.getBean('messageSource')
Using g.render in a grails service has some hints how to use "g:" in a service. I have not tested this, but it should work mostly the same in domain classes, with one important exception: a domain class cannot use InitializingBean since it's not a bean residing in the application context.

Resources