grails service inside a package - grails

I'm pretty new to grails and spring
Me created a service like this
services\com.mypackage\MyService
where
class MyService {
static transactional = true
def serviceMethod(params) {
println "params:"+params
}
}
Then when in my controller
controller\com.mypackage\mycontroller
Then in its action I tried to access like this
def myaction= {
com.mypackag.MyService myService //also used def myService
myService.serviceMethod(params)
render(view: "otherpage")
}
But it show the following error :(
java.lang.NullPointerException: Cannot invoke method serviceMethod() on null object
it cannot make the object of myservice.
myService shows null
What mistake i have done?
It will be very helpful if anyone provide me some good simple links and tutorials for using service with grails
Thank you

One mistake you have done.
You are declaring that myService inside your myaction closures. Where it should be done in the controller outside any of your methods or closures.
You can access your service methods using your service object (here myService) inside any of your methods or closures
So change like this
In your controller\com.mypackage\mycontroller declare your service first
def myService
Then you can access it in any closures
def myaction= {
myService.serviceMethod(params)
render(view: "otherpage")
}

Your directory hierarchy does not correspond to you packages. You should change the directory hierarchy for your service to:
services\com\mypackage\MyService.groovy
and make sure you add the following at the top of MyService.groovy
package com.mypackage
class MyService {
// .....
}
Similarly, change the directory hierarchy for your controller to
controller\com\mypackage\MyController.groovy
Then to get a reference to your service inside your controller
// add the correct package statement
package com.mypackage
// rename the controller and the mycontroller.groovy file to MyController
class MyController {
// this will be injected by Spring (it must be named with a lower-case 'm')
def myService
def myaction= {
// use the service inside your action
myService.serviceMethod(params)
render(view: "otherpage")
}
}

1) I'd read the Grails User guide on Services
2) I'd make your services using the command line tools grails provides as it will save you putting things in invalid directories (com.mypackage as a folder name is going to give you nothing but trouble), and it will make sure you have the correct package declarations at the top of your groovy files

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'
}

How can you structure Grails Services so superclass methods are non-transactional and subclass methods are transactional?

I have the following super class grails service:
abstract class SuperClassService {
public def execute(def payload) {
def tracker = new TrackerDomain().save()
doWork()
tracker.status = 'done'
tracker.save()
}
protected abstract doWork(def payload);
}
and seveeral child class grails services that follow this pattern:
class SubClassService extends SuperClassService {
protected doWork(def payload){
new SomeDomain().save()
}
}
In my controllers I kick off a call to the 'execute' method of the various child classes.
What I want is for the SubClass services to follow the traditional Service pattern where any problems get rolled back, but I want the domains created int he parent class code to both NOT be rolled back and be committed immediately (so that they can be viewed on a tracking page while the subclass service code is still executing. I would PREFER not to set everything as non-transactional and only set the functions in the subclass as transactional but if that's the only option here I would like to know that too.
Have you tried annotating your subclasses service method with a #Transactional(propagation = Propagation.REQUIRES_NEW)? I think that it should do the trick, regardless of whether the outside service code is transactional or not.

Change the name of an injected service in 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

Grails: how to get a controller by controllerName in a filter?

I have a filter and the controllerName var getting controller target.
For example:
when user try to access /myApp/book/index, my filter is triggered and controllerName is equals book. How can I get a BookController instance?
Tks
EDIT:
I can get an Artefact using:
grailsApplication.getArtefactByLogicalPropertyName("Controller", "book")
But what I do with this artefact?
The controller will be registered as a spring bean. Just grab it by name:
applicationContext.getBean('mypackage.BookController') // or
def artefact = grailsApplication.getArtefactByLogicalPropertyName("Controller", "book")
applicationContext.getBean(artefact.clazz.name)
As Burt said, you probably don't want one controller instance inside your filter. This is a wrong way to solve your problem.
Grails Controllers as injected automagically by Spring Framework, and there is some black magic and procedures made when creating it. So, I can assure you this is not the way to solve this problem.
As you yourself described, you want to call your action, and I can imagine you're trying to reuse some code that resides in your action, maybe to generate some data in your database, or even to work with your HTTP session, am I right?
So, you can do two things to solve this kind of issue.
1) Just redirect your request flow to to your controller/action like this:
if (something) {
redirect controller: 'xpto', action: 'desired'
return false
}
2) Or you can get the logic inside your action (that is doing that dirty job you want to run), separate that logic inside one service, and reuse the service in both classes (action / service) this way:
MyService.groovy
class MyService {
def methodToReuse() {
(...)
}
}
MyController.groovy
class MyController {
def myService //auto-injected by the green elf
def myAction = {
myService.methodToReuse()
}
}
MyFilters.groovy
class MyFilters {
def myService //auto-injected by the red elf
(...)
myService.methodToReuse()
(...)
}
[]s,
You should be able to call newInstance on the artefact you've retrieved. newInstance works just like the constructor so you can provide any parameters you would to a normal constructor call.
So you can probably just do:
def bookController = grailsApplication.getArtefactByLogicalPropertyName("Controller", "book").newInstance()
Working code:
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.springframework.context.ApplicationContext
ApplicationContext applicationContext = (ApplicationContext) ServletContextHolder.getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
def grailsApplication
String nameController = "search"
def artefact = grailsApplication.getArtefactByLogicalPropertyName("Controller", nameController)
def controller = applicationContext.getBean(artefact.clazz.name)

Resources