Grails Scoped Service in Integration Test - grails

I have a service that needs the scope "session". So I simply use
class MyService {
static scope = "session"
...
}
But in my integration test it doesn't get wired correctly:
class MyServiceIntegrationSpec extends IntegrationSpec {
def myService
...
}
I always get the error:
Error creating bean with name 'myService': Scope 'session' 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;
What am I doing wrong?

You cannot inject 'lower' scoped bean into singleton. It's like you would like to inject controller into service. Controller is created with each request, but service is one for the application (if singleton by default). Here you can have different sessions, but only one singleton for test - so service from which session would you like to use in test?
It can be done getting the bean from the context instead of injecting it:
def grailsApplication
void testSomething() {
given:
def myService = grailsApplication.mainContext.getBean('myService')
...
Changing the scope of the test from singleton to session would also resolve the problem, but I don't know if this is possible.

Related

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

Autofac scoping issue

I'm trying to setup a custom model validator provider using FluentValidation. Everything works until i try to inject a business layer manager into the validator's constructor to run some business logic.
public class Repository : IRepository
{
public Repository(IDbConnection)
{
}
}
public class Manager : IManager
{
public Manager(IRepository)
{
}
}
public AutofacValidatorFactory : ValidatorFactoryBase
{
}
public MyModelValidator : AbstractValidator<MyModel>
{
public MyModelValidator(IManager) { }
}
I wire everything up like so:
builder.Register(c => new SqlConnection(ConfigurationManager.ConnectionStrings["MyCS"].ConnectionString))
.As<IDbConnection>().InstancePerApiRequest();
builder.RegisterType<Repository>()
.As<IRepository>()
.InstancePerDependency();
builder.RegisterType<Manager>()
.As<IManager>()
.InstancePerDependency();
builder.RegisterType<ValidatorFactory>()
.As<IValidatorFactory>()
.InstancePerLifetimeScope();
builder.RegisterType<FluentValidation.Mvc.WebApi.FluentValidationModelValidatorProvider>()
.As<ModelValidatorProvider>()
.InstancePerLifetimeScope();
AssemblyScanner.FindValidatorsInAssembly(assembly)
.ForEach(
result =>
Builder.RegisterType(result.ValidatorType).As(result.InterfaceType).InstancePerApiRequest());
Finally, i add the FluentValidator Model Provider like so:
// _validatorProvider is injected as per Autofac config above.
GlobalConfiguration.Configuration.Services.Add(typeof(ModelValidatorProvider), _validatorProvider);
The issue is occurring when my validator factory tries to spin up a validator instance. At which point i get the following exception:
"No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself."
I think the issue has something to do with the way Manager & Repository is configured in Autofac but i don't know what i'm missing.
EDIT: This issue is occurring in a Web API project.
Without seeing more of your code I cannot answer your direct question, however I can answer what this exception generally means
Autofac supports nested lifetime scopes (i.e. child containers). The main container is actually just the root lifetime scope. Each lifetime scope can be thought of as a unit of work. You create the lifetime scope, resolve the instances required to perform that task, then dispose the lifetime scope. Anything created by the lifetime scope is then disposed.
Registering as SingleInstance means that single instance is resolved and stored by the root scope. Using InstancePerLifetimeScope will recreate each instance per scope it was resolved from, so you can end up with an instance in the root scope and your child scope. InstancePerMatchingLifetimeScope allows you to register a type so that it is shared between all the child containers of that specific branch of the tree. These types can never exist or be accessed by anything in the root scope. InstancePerApiRequest is the same as InstancePerMatchingLifetimeScope(“AutofacWebRequest”).
In your application each request will be a child autofac scope. Something registered to the child scope (i.e. your IDBConnection) can use anything else in the same scope (registered as InstancePerLifetimeScope) and anything in the parent scope (registered as SingleInstance) however there is a potential problem here. Something registered to the parent scope (for example as SingleInstance in the root container) cannot access anything registered as InstancePerMatchingLifetimeScope in the child scope as the parent scope doesn’t have access to instances in child scopes.
This is what you have most likely done – registered something as a SingleInstance which has a dependency on something registered to a Matching Lifetime scope.

How to call a Service in a Grails integration test

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.

Grails: How do I use a request scoped service in a tag library?

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

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