I have a class that I moved under the grails-app/services directory in order to inject the springSecurityService. This class is the implementation (Is that the proper terminology?) of the spring userDetailsService class. Here is my declaration in resources.groovy:
userDetailsService(com.company.product.PracticeUserDetailsService) {
grailsApplication = ref('grailsApplication')
}
This class is extending GormUserDetailsService.
My attempted dependencyInjection results in a null object.
class PracticeUserDetailsService extends GormUserDetailsService{
def springSecurityService
UserDetails loadUserByUsername(String username, boolean loadRoles) throws UsernameNotFoundException {
// impl omitted
}
}
If I create some test controller or some service in grails and inject the springSecurityService, it works fine. So, there is perhaps something about this particular class that is not placing it in the Grails ecosystem. I checked out this to try to manually inject it as follows:
beans = {
springSecurityTEST(grails.plugins.springsecurity.SpringSecurityService) {}
}
Move PracticeUserDetailsService from grails-app/services to src/groovy and change your Spring bean definition in resources.groovy to:
userDetailsService(com.company.product.PracticeUserDetailsService) {
grailsApplication = ref('grailsApplication')
springSecurityService = ref('springSecurityService')
}
For me it happened when I used GrailsApp.run(Application, args) to run the app...
Related
Grails services are abstractions used for implementing business logic (as well as connecting to backing services/DBs, etc.) outside of a controller. So in a typical controller you might have:
class DashboardController {
StatisticsService statsService
def index() {
// Fetches all the stats that need to be displayed to the
// admin on the dashboard.
AdminDashboardMetrics adm = statsService.getAdminStats()
render(view: "/dashboard", model: [ adm: adm ])
}
}
Here, Grails automatically injects the DashboardController with a bean instance of StatisticsService (provided of course that the service was properly created with grails create-service ...).
But what happens when I need to access StatisticsService outside of a controller, and particularly, under src/groovy?
// src/groovy/com/example/me/myapp/FizzBuzzer.groovy
class FizzBuzzer {
StatisticsService statsService
FizzBuzzer(StatisticsService statsService) {
super()
this.statsService = statsService
}
def doSomething(MyData input) {
MoreData result = statsService.calculate(input)
// use 'result' somehow, etc....
}
}
How do I properly inject FizzBuzzer with the same StatisticsService instance ad what is passed into DashboardController?
You can inject grails service in spring bean by defining injection login in resources.groovy under conf > spring
As I made an ExampleService and Example class in src/groovy
ExampleService
class ExampleService {
def serviceMethod() {
println "do something"
}
}
Example Class under src/groovy
class Example {
ExampleService exampleService
def doSomething() {
def result = exampleService.serviceMethod()
}
}
resources.groovy under conf>spring
beans = {
ex(Example){ bean ->
exampleService = ref('exampleService')
}
}
so I can define Example ex as spring bean in grails-app and it will have ExampleService injected by itself.
Hope this helps. Thanks
You can also get a service using grails.util.Holders
Example:
For injecting MyService service class, use Holders.applicationContext.getBean("myService")
Where "myService" is the name of your service class in lower camel case.
One way of achieving this is by using ServletContext-
ApplicationContext ctx = (ApplicationContext)ServletContextHolder.
getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
statisticsService = (StatisticsService ) ctx.getBean("statisticsService ")
see this blog - http://www.grailsbrains.com/availing-grails-goodies-in-srcjava-or-srcgroovy/
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 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 trying to unit test a controller for User domain generated by Spring Security Core Plugin. The controller was generated with grails generate-all.
The domain has a transient property called springSecurityService. In my unit test I am trying to mock that service and assign this transient variable to my mocked version. However, I get this error :
No such property: springSecurityService for class: com.myapp.security.SecUser Possible solutions:
springSecurityService groovy.lang.MissingPropertyException: No such property: springSecurityService for class:
com.myapp.security.SecUser at com.myapp.security.SecUserControllerTests.setUp(SecUserControllerTests.groovy:26)
Here is my domain look like:
class SecUser {
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
....
def beforeInsert() {
encodePassword()
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
Here is how my test look like:
package com.myapp.security
import org.junit.*
import grails.test.mixin.*
import com.myapp.system.*
import grails.plugins.springsecurity.*
#TestFor(SecUserController)
#Mock([SecUser,SpringSecurityService])
class SecUserControllerTests {
#Before void setUp() {
def service = mockFor(SpringSecurityService)
service.demand.encodePassword(1..2) { a -> return 'd3jk3j4ls234'}
def control = service.createMock()
SecUser.springSecurityService = control
}
Not sure what I am doing wrong or even I can even do something like this with transient property?
Could be a mockup situation, See if this works:
#Before void setUp() {
def service = mockFor(SpringSecurityService)
// using the groovy MetaClass runtime
service.metaclass.encodePassword = {def a -> 'd3jk3j4ls234'}
SecUser.springSecurityService = service
}
or a more static solution:
#Before void setUp() {
secUser.springSecurityService = [
encodePassword : {def a -> 'd3jk3j4ls234'}
] as SpringSecurityService
}
You're trying to assign your mocked springSecurityService to the SecUser class (as if it were a static), which won't work when it's an instance variable. I'm not an expert on the new Grails 2 testing annotations but I believe that if you replace
SecUser.springSecurityService = control
with
SecUser.metaClass.getSpringSecurityService = {-> control}
then it should do what you want.
I'm having trouble accessing springSecurityService from resources.groovy file, I'm trying to load user locale setting and create LocaleResolver
import User
beans = {
localeResolver(org.springframework.web.servlet.i18n.SessionLocaleResolver) {
def user = User.get(springSecurityService.principal.id)
if (user?.settings?.locale) {
defaultLocale = new Locale(user?.settings?.locale)
java.util.Locale.setDefault(defaultLocale)
}
}
}
Thanks,
Mika
Your code above doesn't make a lot of sense. In resources.groovy you're supposed to define the implementation class of Spring beans and set their dependencies. It looks like you're trying to actually write the implementation class in resources.groovy.
Instead you should write your own LocaleResolver class
package org.example
class MyLocaleResolver extends AbstractLocaleResolver {
def springSecurityService
// implementation of methods omitted, because I haven't clue how you want to resolve Locales
}
Then in resources.groovy, define a bean of this type that replaces the default localeResolver bean
beans = {
localeResolver(org.example.MyLocaleResolver) {
springSecurityService = ref('springSecurityService')
}
}