Load application class from plugin - grails

In a Grails 1.1 plugin, I'm trying to load a class from the main application using the following code:
class MyClass {
static Map getCustomConfig(String configName){
return new ConfigSlurper().
parse(ApplicationHolder.application.classLoader.loadClass(configName))
}
}
Where configName is the name of the class in $MAIN_APP/grails-app/conf containing the configuration info. However, when the code above runs within a unit test applicationHolder.application returns null, causing the method above to throw a NullPointerException. A Grails JIRA issue was created for this problem, but it has been marked as fixed despite the fact that problem appears to still exist.
I know that within the plugin descriptor class I can access the main application (an instance of GrailsApplication) via the implicit application variable. But the code shown above is in not in the plugin descriptor.
Is there a way that I can load a class from the main application within a plugin (but outside the plugin descriptor)?
Thanks,
Don

It turns out there are 2 possible answers.
The Right Answer
GrailsApplication is not available in unit tests, so for the code above to work it should be an integration test
The Hack that Works
Change
parse(ApplicationHolder.application.classLoader.loadClass(configName))
to
parse(MyClass.classLoader.loadClass(configName))

Related

Grails run-command ask for application class argument

I'm using grails 3.2.9 version. And trying to create custom command. I need a command because I need to have access to spring beans. So the code is simply like this:
class MyTestCommand implements GrailsApplicationCommand {
boolean handle() {
def bean = applicationContext.getBean('myBean')
bean.doSomething()
return true
}
When I run it as
grails run-command my-test
I'm getting an error: "Missing application class name and script name arguments"
I'am able to add application class as last param and everything seems works, but the question is, why I should add it? Does grails doesn't know about its Main Application class? I did some research about and there is no answers, in each examples i se only command name without Application class. But as I understand from this source we should pass main class always. Am I missed something?

grailsApplication not available in Domain class when running all Integration tests

I'm running into a problem when running integration tests in Grails. One of the domain classes in the project has a method that accesses the grailsApplication.config property. We have an integration test for one of our services that call this method in the domain class. When the test is run on its own using the command
grails test-app integration: com.project.MyTestSpec
The test runs fine and the domain class can access grailsApplication. However when the whole test suite is run using:
grails test-app integration
then the test fails with the error
java.lang.NullPointerException: Cannot get property 'config' on null object
When trying to access grailsApplication.config. It seems that when the tests are all run together grailsApplication is not being injected into the domain class. Has anyone come across this issue before?
From what I have read it seems to be a test pollution issue but as there is no setup happening in each integration test the problem is hard to track down.
I came across this issue with grails 3. If you are testing a Domain, you have to setup (testing with spock) at the begining of the test:
def setup() {
Holders.grailsApplication = new DefaultGrailsApplication()
Holders.grailsApplication.config.property.code = '1234'
}
I'm not sure what the issue is, but this must be a test pollution issue where yours any one of the test case is doing something with grailsApplication using meta class. Because this seems to work fine for me.
As a workaround you can avoid using injected grailsApplication and use the Holders class instead like the following:
package com
import grails.util.Holders
class User {
// def grailsApplication
String email
String name
String getTitle() {
return Holders.getConfig()["app.title.prefix"] + name
// Or
//return Holders.grailsApplication.config["app.title.prefix"] + name
}
}
This way, you are not dependent upon the dependency injection.
I had the same issue and found that my integrationstest implemented ServiceUnitTest<> which caused the problem.

Grails Cache and EHCache Plugin caches Controller methods but not Service methods

I'm having trouble getting the Grails EHCache Plugin to cache service methods. Here is my setup:
Grails 2.4.2, JDK 1.7
BuildConfig.groovy compile ":cache-ehcache:1.0.4"
Config.groovy defines the following cache named "cache"
grails.cache.config = {
cache {
name 'cache'
timeToLiveSeconds 60
}
}
The following controller method properly caches. I have tested by setting a breakpoint in the method, and it only is hit the first time, until the cache expires.
#Cacheable('cache')
def index() {
render "index-$params.id"
}
I can check the keys in the cache with:
grailsCacheManager.getCache('cache').getNativeCache().getKeys()
and see the value:
localhost:GET:/grails-cache-test/cache/index?id=34
So far so good.
The following service method exists:
#Cacheable('cache')
public method1(id) {
"method1+$id"
}
I set a break point in here, and this method is always called, regardless of the #Cacheable annotation. I've tried setting the value and key annotation attributes manually, and no change. I test calling this method from a non-cached controller method, as well as directly from the console plugin. When I get the keys in the service method I see that there are no keys set.
I've looked through examples in the official documentation, code samples online, github, a book I have, everything looks good, so I'm not sure where the problem lies.
Any ideas on why this service method does not cache the value? Thanks!
UPDATE 1
I've been digging into the grails cache-1.1.8 plugin (as well as the associated cache-ehcache-1.0.4 plugin), and believe I've found something helpful. In PageFragmentCachingFilter.doFilter() there are calls to check the controller's annotations - but nothing to check the service. It appears that as a result, the service annotations are never honored. There is a lot of documentation that mentions service methods, so I don't know if there is something elsewhere that handles this, or if it's a less common use case compared to controller methods.
UPDATE 2
It appears that Controllers and Services are handled separately. In CacheAspectSupport.execute() there is a for() loop that will call cachePutRequest.apply(result.get());, which will actually add the entry to the cache. Unfortunately after the entry is added to the request, it is not immediately available to be retrieved. The underlying put() code is part of Spring Source, so at this point I'm not sure if it's a grails plugin issue or a Spring Source issue.
I have created a JIRA issue for this plugin GPCACHEEHCACHE-16

Grails override a plugin service static method

I'm using a plugin which has this Service:
package grails.plugins.imports
class ImportsService {
static rabbitQueue = "${grails.util.Holders.grailsApplication.metadata['app.name']}ImportRows"
....
}
While this works fine when using run-app; i.e grails run-app, this is wreaking havoc when attempting to run as a war; grails run-war.
2014-09-09 15:54:25,069 [localhost-startStop-1] ERROR StackTrace - Full Stack Trace:
java.lang.NullPointerException: Cannot get property 'metadata' on null object
at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:56)
at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:169)
at org.codehaus.groovy.runtime.callsite.NullCallSite.getProperty(NullCallSite.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)
at grails.plugins.imports.ImportsService.<clinit>(ImportsService.groovy:9)
Short of forking the plugin, any suggestions here?
Grails 2.3.10
Thanks in advance,
Todd
So, I know your goal was to avoid forking the plugin, but I think the issue is that the plugin was written in earlier days when you would get the grailsApplication object through a holder class. That's not really recommended these days (see Burt Beckwith's post on the subject), but there are options.
The easiest way for your plugin to get the grailsApplication object would be through dependency injection:
class ImportsService {
def grailsApplication
static rabbitQueue = "${grailsApplication.metadata['app.name']}ImportRows"
//....
}
Though in this case, since all you need is the app.name, it might be better to:
class ImportsService {
static rabbitQueue = "${grails.util.Metadata.current.'app.name'}ImportRows"
//....
}
You might try manipulating the plugin code in a local copy to see if that fixes the issue. GGTS makes that fairly easy by providing the plugins in the project explorer view. If that change works, and you can submit a patch to the plugin developer, you might be able to have the fix become part of the official release.

How do I use the Java ServiceLoader class in Grails?

I've used the JDK's SPI mechanism in numerous other applications without any problem; however, I can't seem to get it to work within Grails.
I've tried the usual code (shown below) both from within a static initializer, and from within a class constructor, but neither worked.
ServiceLoader loader = ServiceLoader.load(QueryEngine.class);
Iterator<QueryEngine> it = loader.iterator();
The iterator doesn't actually iterate through the implementing classes.
I've also tried:
ServiceLoader.load(QueryEngine.class, Thread.currentThread().getContextClassLoader());
which should use the classloader for the current class, but that doesn't work either.
Is there some other mechanism I should be using to load implementing classes?

Resources