I have a Service, called Mailer, and a controller, which should use this service:
class DocumentController {
def mailer
def publish = {
mailer.sendReport()
}
}
But when I call publish I get:
java.lang.NullPointerException: Cannot invoke method sendReport() on null object
Why doesn't the dependency injection work here?
Grails is all about conventions. I think mailer needs to be called mailerService. It needs to be in the services directory. Controller needs to be in the controllers directory.
From the documentation
"A service contains business logic that can be re-used across a Grails application. In Grails a service is a class that ends in the convention "Service" and lives in the grails-app/services directory. A service can be created with the create-service command:"
Related
Cassandra Low-level API
A lower level API is provided by the plugin
that is based on the Spring Data Cassandra project.
Spring Data Cassandra provides a CassandraTemplate with methods to
execute statements using the regular Cassandra Java Driver
To get hold of the cassandraTemplate instance inside a controller or
service simply define a cassandraTemplate property. An example can be
seen below:
def cassandraTemplate
def myAction = {
def people = []
people << new Person(firstName: "Fred", lastName: "Flintstone")
people << new Person(firstName: "Barney", lastName: "Rubble")
cassandraTemplate.insert(people)
}
From the docs:
Dependency Injection Basics
A key aspect of Grails services is the ability to use Spring Framework's dependency injection features. Grails supports "dependency injection by convention". In other words, you can use the property name representation of the class name of a service to automatically inject them into controllers, tag libraries, and so on.
As an example, given a service called BookService, if you define a property called bookService in a controller as follows:
class BookController {
def bookService
...
}
In this case, the Spring container will automatically inject an instance of that service based on its configured scope. All dependency injection is done by name. You can also specify the type as follows:
class AuthorService {
BookService bookService
}
Let's say I have some codes to make 2 rest calls to the other API. And I need a service layer to make 2 rest calls in the same action.
In Java, I probably would do something like this
#Service
public class RestService{
#Autowired
RestClient restClient
def shutdown(){
if(restClient.isSystemGood()){
restClient.shutdownSystem()
}
}
}
#Repository
public class RestClient {
boolean isSystemGood() {
...
}
void shutdownSystem() {
...
}
}
How should I fit in grails way to do the similar thing?
Should I put the logic inside RestClient into a domain class? or Should I put both RestService and RestClient into a domain class? Does domain class have to be backed by a DB?
Because I only see service and domain folders in the grails default file structure.
RestService (in your simple case a non-transactional one) inside grails-app/services directory is the right place for the logic. Inject the service inside the controller action to use it.
Injecting services into the domain class is not recommended. It hard to test, degrades the read performance and results in a spaghetti design. This is why Grails now by default, has disabled the services injection in the domain class
It seems to me that somewhere a rabbit is being pulled out of a hat when it comes to DI in Web API Controllers.
I grok that:
0) The Controller in a Web API project can be called with various classes to be instantiated, all of which implement the interface on which the Controller depends. e.g., with this Controller code:
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository is null");
}
_deptsRepository = deptsRepository;
}
..."deptsRepository" can be a class that implements IDepartmentRepository and retrieves test data, OR it can be a class that implements IDepartmentRepository and retrieves production data, OR (etc.)
1) Web API decides which Controller is called based on the URI the client calls, and that Web API decides which method in that Controller is called based on what type (GET, POST) etc. it is and what args, if any, are passed with it.
2) Castle Windsor intercepts this automatic control of Controllers with its own replacement routing engine.
What I don't grok is just where the developer injects the concrete class that implements the interface expected by the Controller. IOW, if I want to run the class that pulls from test data, where do I add code to specify that? I would think it would be somewhere in Global.asax.cs, something like (pseudocode):
// Use test data for now
DeptsControllerClass = TestDataClass;
//DeptsControllerClass = ProductionDataClass;
IOW, where does one specify, "This time, I want you to inject THIS concrete class which implements the required interface"?
As you wrote at point 1, Routing and IoC are two different things.
Once the routing engine figures out which controller has to be invoked, a "controller factory" will be invoked.
WebApi framework allows to plug your own factory as following:
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorCompositionRoot(this.container));
Read more on Mark Seemann post about webapi&windsor plumbing.
Which concrete will be used to satisfy a given interface dependency, that's up to the ioc you choose to use within your factory as above. Using Windsor you may/should link interfce&concrete in the Installers.
Let me try to recap the whole process
1) Set up the routing in order to link url vs controller
2) create the container and register all components using installers
3) replace default controller factory w/ a factory working w/ your favorite ioc container(Windsor, I presume :-) )
4) Enjoy the magic.
All those steps happend in the Application_start within the Global.asax
This thread describes how to call a Service in a view: How do I get an instance of a Grails service programmatically?
This describes how to call it in a Servlet: How do I get an instance of a Grails service programmatically?
This one says how to call it in a Controller: How to dynamically select a service in Grails
I need to get a handle to my service in an integration test. Is this possible?
If its an integration test, you have access to the entire runtime so just inject it like you do normally.
def someService
Have a look at Testing Controllers with Service.
Gist:
You have to initialize the service (spring bean) to controller in the test.
class FilmStarsTests extends GroovyTestCase {
def popularityService
void testInjectedServiceInController () {
def fsc = new FilmStarsController()
fsc.popularityService = popularityService
fsc.update()
}
}
Services are autowired in integration tests as in controllers.
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