According to Grails it should be possible to use a service within a domain class. But when I run the following simple example, the grails run-app fails with a NullPointerException: "Cannot invoke method test() on null object"
To reproduce use the following code pieces:
Bootstrap.groovy:
class BootStrap {
def init = { servletContext ->
new Test().test()
}
def destroy = {
}
}
with the service:
#Transactional
class TestService {
def test() {
}
}
and the domain class:
class Test {
def testService
def test() {
testService.test()
}
}
This happens with Grails 3.2.9 and 3.3.0. Is this a Grails error or a GORM failure, not auto injecting the service into domain classes ?
SOLUTION:
For all wondering what the solution is (see answer from erichelgeson) using "static mapping = { autowire true }". But testing both solutions, I found that "static mapping ..." works in Grails 3.3.0 and in 3.2.9, hence setting it globally in application.yml did only work for Grails 3.2.9 but not in Grails 3.3.0 thou.
Recent versions of Grails (3.2.9+) have disabled autowire by default on domain classes for performance reasons. You can re-enable it:
per domain:
static mapping = {
autowire true
}
or globally in application.yml/groovy
grails.gorm.autowire = true
See more # http://gorm.grails.org/6.1.x/hibernate/manual/index.html
Section 1.2.9
You could reenable autowiring per the previous suggestion, but there are performance implications to your whole application for that. It may be worth it, if this is a common situation.
If this is a rare situation for you, you can also access a service as so, in a domain class:
Holders.applicationContext.serviceName.methodName()
Related
I'm following this tutorial for Spring Security Authentication:
http://spring.io/blog/2010/08/11/simplified-spring-security-with-grails/
Video: https://www.youtube.com/watch?v=auwML_bsUEE
I can't follow the step in 4:50.
package org.example
import grails.plugins.springsecurity.Secured
class PostController {
...
#Secured(['ROLE_USER'])
def followAjax = { ... }
#Secured(['ROLE_USER', 'IS_AUTHENTICATED_FULLY'])
def addPostAjax = { ... }
def global = { ... }
#Secured(['ROLE_USER'])
def timeline = { ... }
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
def personal = { ... }
}
import grails.plugins.springsecurity.Secured is not found.
I'm using Grails 2.4.4 and compile ':spring-security-core:2.0-RC4' in BuildConfig.groovy. Thanks.
That tutorial is more than 4 years old, a lot has changed since then. Try reading the plugin docs - I'm sure that there are several other changes like this that will cause issues.
The import should be grails.plugin.springsecurity.Secured. You can also use the Spring Security org.springframework.security.access.annotation.Secured annotation, but the plugin's annotation supports all of the same features and a few additional ones, e.g. letting you define the rules with a Closure.
You can't use either annotation on an action defined as a Closure though. They are still supported in Grails 2.0+ but methods are now preferred, and although Grails lets you define actions with closures or actions, the plugin only supports methods.
I have 1 bean defined in resources.groovy
cachedbean(serviceImpl) {
}
In service I am using it this way
MyService{
static transactional = false
def cachedbean
myMeth(){
cachedbean.get("cacheKey")
}
}
This works fine but when I try to test it with integration test, I get nullpointer exception on 'get'
cachedbean.get("cacheKey").
How does it work?
Instead of "new"-ing up the service instance, if you let Grails auto wire the service bean into your integration test class it should be auto wired.
class MyServiceTests extends GroovyTestCase {
def myService
void testSomething () {
// myService should already be wired up
}
}
It's unclear if you did or not based on your sample code, but you need to fully-qualify out the package and class name for "serviceImpl" in your resources.groovy unless you explicitly import the package.
You may need to add inside the scope of your declaration in resources.groovy the line bean.autowire = "byName"
I want to override a service implementation by just installing a plugin - when the plugin is installed I want the plugin-version of the service to be used and when the plugin is uninstalled I want the default version of the service to be used.
To prevent wasting time, I'll explain my problem using code. I have a "common plugin" that is shared by my main application and my "custom plugin" with the following:
public interface SimpleService {
void doProcessing();
}
I then have a "main application" that contains the following
Default implementation of service interface:
public DefaultSimpleService implements SimpleService {
void doProcessing() {
// ...
}
resource.groovy:
simpleService(DefaultSimpleService) { bean ->
bean.autowire = 'byName'
}
Controller that uses the service:
class SimpleController {
def simpleService
def index() {
simpleService.doProcessing()
}
}
So far so good. What I now want to do is to replace the implementation of SimpleService interface with a new one by just installing a plugin. I do not want to change any configuration within my application.
I have a plugin with a new implementation of the service:
public CustomSimpleService implements SimpleService {
void doProcessing() {
// ...
}
}
My first attempt was to register the custom service bean in the plugins "doWithSpring" section, but it is always overridden by the main application. Fair enough since it seems like plugins are always loaded before main application beans is registered (?)
My second attempt was to register the custom bean in "doWithApplicationContext" inside my CustomServiceGrailsPlugin.groovy:
def doWithApplicationContext = { applicationContext ->
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory()
beanFactory.registerBeanDefinition("simpleService", BeanDefinitionBuilder.rootBeanDefinition(CustomSimpleService.class.getName()).getBeanDefinition())
}
This actually works partially - When the plugin is loaded the plugins implementation of SimpleService is used, and if the plugin is uninstalled the main applications implementation of SimpleService is used. But there was a side issue: autowiring of beans is not working inside the plugin implementation that was "manually" registered...
Then I started to look at BeanPostProcessors but from what I read it looked like it wouldn't solve my problem.
So how do I solve my problem?
Regards
Tobbe
I think that your best bet is to check if the plugin is installed and don't declare the service in the application if so.
You can check the plugins installed with: org.codehaus.groovy.grails.plugins.PluginManagerHolder.pluginManager.allPlugins
And you can use this in the resources.groovy
boolean containsPlugin(String pluginName) {
def names = org.codehaus.groovy.grails.plugins.PluginManagerHolder.pluginManager.allPlugins.collect { it -> return it.name }
return(pluginName in names)
}
beans = {
if(!containsPlugin("thePlugin")) {
println "Installation not contains plugin, defining bean!"
myService(...)
}
}
I have a service that implements InitializingBean and DisposableBean
class MyService implements InitializingBean, DisposableBean {
static transactional = false
def grailsApplication
#Override
void afterPropertiesSet() {
System.setProperty("JMS_TIMEOUT", grailsApplication.config.JMS_TIMEOUT);
// code performing a JDNI lookup
}
}
enter code here
The system properties are used to initialize some other components in the service. I have added the configs in Config.groovy.
grails.config.locations = [ "file:${basedir}/grails-app/conf/myconfig.properties" ]
This works fine when running the application. However I'm writing an integration test in test/integration that injects the service.
class MyServiceIntegrationTests extends GrailsUnitTestCase {
def myService
void testMyService() {
}
}
When running the test I get a StackTrace with the folllowing root cause:
Caused by: javax.naming.NameNotFoundException: Name [ConnectionFactory] not bound; 0 bindings: []
at javax.naming.InitialContext.lookup(InitialContext.java:354)
at com.ubs.ecredit.common.jmsclient.DefaultConnector.<init>(DefaultConnector.java:36)
Seems that the Config could not be loaded or are different in the Integration Tests. Any idea how I can change the config or code, so that these properties are also set for my integration test, before the service is instantiated?
UPDATE:
It turned out the cause was not the configurations but a JDNI lookup and a bug in Grails.
See: http://jira.grails.org/browse/GRAILS-5726
${basedir} gets different paths in different environments. As an alternative, you can use PropertiesLoaderUtils.loadProperties to load your customized configurations:
import org.springframework.core.io.support.PropertiesLoaderUtils
import org.springframework.core.io.ClassPathResource
....
void afterPropertiesSet() {
def configProperties = PropertiesLoaderUtils.loadProperties(
new ClassPathResource("myconfig.properties"))
System.setProperty("JMS_TIMEOUT", configProperties.getProperty("JMS_TIMEOUT"))
....
}
It turned out the cause was a JNDI lookup used by a library method, I have not shown in afterPropertiesSet() in my Service, which can be seen in the StackTrace.
After doing some research I found that this was a bug in Grails: http://jira.grails.org/browse/GRAILS-5726
Adding the mentioned workaround, resolved the issue for now.
I am having problems when using dependency injection with Services in Grails.
class ExampleService{
def example2Service
def example3Service
def method1(){
def result = example2Service.method2()
}
}
class ExampleService{
def example3Service
def method2(){
def result = example3Service.method3()
return result
}
}
class Example3Service{
def method3(){
return true
}
}
Basically in Example2Service, I am getting a Null Pointer Exception when trying to call method3 in Example3Service.
I would appreciate any help than anybody can give me with this issue
thanks
Dependency Injection needs to be initialized. (The same applies to other kinds of runtime meta programming, like augmenting Domain classes with their save() and validate() methods.)
A Grails application will be initialized when
being run from the grails run-app command
being run after having been deployed to a web server
being run from the grails test-app command (integration tests, only; unit tests do not trigger initialization).
Involved classes are not initialized when
executing a single Groovy file (i.e., by using groovy, groovysh, or groovyConsole)
or when executing a unit test.
The following as an integration test should work:
class Test2ServiceTests extends GroovyTestCase {
def test2Service
void testMethod2() {
assert test2Service.method2() == true
}
}