Grails 3 allows authors to use startup hooks similar to the ones provided to Grails 2 plugins. I'm looking at defining beans in the doWithSpring closure, and I'd like to pass values into a new bean based on some configuration values. I can't figure out, however, how to get the grailsApplication instance or the application configuration. How do you do this with Grails 3?
Your plugin should extend grails.plugins.Plugin which defines the getConfig() method. See https://github.com/grails/grails-core/blob/9f78cdf17e140de37cfb5de6671131df3606f2fe/grails-core/src/main/groovy/grails/plugins/Plugin.groovy#L65.
You should be able to just refer to the config property.
Likewise you can refer to the inherited grailsApplication property which is defined at https://github.com/grails/grails-core/blob/9f78cdf17e140de37cfb5de6671131df3606f2fe/grails-core/src/main/groovy/grails/plugins/Plugin.groovy#L47.
I hope that helps.
Under Grails 3, I took Jeff Scott Brown's advice and used GrailsApplicationAware instead:
This is how you go about setting up a configuration bean:
So in your new plugin descriptor you need to change grails 2 style def doWithSpring to a ClosureDoWithSpring as below:
Notice in Grails 2 we injected grailsApplication, in grails 3 all we do is declare the bean:
/*
def doWithSpring = {
sshConfig(SshConfig) {
grailsApplication = ref('grailsApplication')
}
}
*/
Closure doWithSpring() { {->
sshConfig(SshConfig)
}
}
Now to get your plugin configuration:
src/main/groovy/grails/plugin/remotessh/SshConfigSshConfig.groovy
package grails.plugin.remotessh
import grails.core.GrailsApplication
import grails.core.support.GrailsApplicationAware
class SshConfig implements GrailsApplicationAware {
GrailsApplication grailsApplication
public ConfigObject getConfig() {
return grailsApplication.config.remotessh ?: ''
}
}
grails.plugin.remotessh.RemoteSsh.groovy:
String Result(SshConfig ac) throws InterruptedException {
Object sshuser = ac.config.USER ?: ''
Object sshpass = ac.config.PASS ?: ''
...
This is now your configuration object being passed into your src groovy classes. The end user application would pass in the sshConfig bean like this:
class TestController {
def sshConfig
def index() {
RemoteSSH rsh = new RemoteSSH()
....
def g = rsh.Result(sshConfig)
}
Edited to add, just found this :) which is relevant or duplicate question:
http://grails.1312388.n4.nabble.com/Getting-application-config-in-doWithSpring-closure-with-a-Grails-3-application-td4659165.html
Related
I have two services with the same name in my Grails 2.4.4 project, called RemittanceService. One is in the package on ph.bank (which I created weeks ago) and another is on ph.gov.advice.slip(which I created today). Since now there are two instances of the service with the same name, I replaced all dependency-injection of ph.bank.RemittanceService from:
class ... {
def remittanceService
...
}
into this:
class ... {
def bankRemittanceService
// added the word `bank` from its package
...
}
and the injections for ph.gov.advice.slip.RemittanceService into:
class ... {
def slipRemittanceService
// added the word `slip` from its package
...
}
Now the problem is that it doesn't point the respective Service, and instead, returns an error:
java.lang.NullPointerException:
Cannot invoke method [...] on null object
I decided to revert it my previous code. When I return the declaration into:
def remittanceService
it always points to the Service found on ph.bank, never to my newly-created Service. My current fix is:
import ph.gov.advice.slip.RemittanceService
class ... {
def slipRemittanceService = new RemittanceService()
// Here I initialize it instead on how dependencies should be declared
...
}
Although, I felt that is wrong. Is there more Grails-ly way to do this?
You can declare beans in your resources.groovy file.
beans = {
bankRemittanceService(ph.bank.RemittanceService) {
}
slipRemittanceService(ph.gov.advice.slip.RemittanceService) {
}
}
now you can inject bankRemittanceService and slipRemittanceService
I have a Maven plugin that I am attempting to test using a subclass of the AbstractMojoTestCase. The plugin Mojo defines an outputFolder parameter with a defaultValue. This parameter is not generally expected to be provided by the user in the POM.
#Parameter(defaultValue = "${project.build.directory}/someOutputFolder")
private File outputFolder;
And if I use the plugin in a real scenario then the outputFolder gets defaulted as expected.
But if I test the Mojo using the AbstractMojoTestCase then while parameters defined in the test POM are populated, parameters with a defaultValue that are not defined in the POM are not populated.
public class MyPluginTestCase extends AbstractMojoTestCase {
public void testAssembly() throws Exception {
final File pom = getTestFile( "src/test/resources/test-pom.xml");
assertNotNull(pom);
assertTrue(pom.exists());
final MyMojo myMojo = (BaselineAssemblyMojo) lookupMojo("assemble", pom);
assertNotNull(myMojo);
myMojo.execute(); // Dies due to NullPointerException on outputFolder.
}
}
Further: if I define the outputFolder parameter in the POM like so:
<outputFolder>${project.build.directory}/someOutputFolder</outputFolder>
then ${project.build.directory} is NOT resolved within the AbstractMojoTestCase.
So what do I need to do to get the defaultvalue populated when testing?
Or is this a fault in the AbstractMojoTestCase?
This is Maven-3.2.3, maven-plugin-plugin-3.2, JDK 8
You need to use lookupConfiguredMojo.
Here's what I ended up using:
public class MyPluginTest
{
#Rule
public MojoRule mojoRule = new MojoRule();
#Test
public void noSource() throws Exception
{
// Just give the location, where the pom.xml is located
MyPlugin plugin = (MyPlugin) mojoRule.lookupConfiguredMojo(getResourcesFile("basic-test"), "myGoal");
plugin.execute();
assertThat(plugin.getSomeInformation()).isEmpty();
}
public File getResourcesFile(String filename)
{
return new File("src/test/resources", filename);
}
}
Of course you need to replace myGoal with your plugin's goal. You also need to figure out how to assert that your plugin executed successfully.
For a more complete example, check out the tests I wrote for fmt-maven-plugin
I have a file under src/groovy and I have some properties that are in my Config.groovy and in external property file too. Normally if one want access properties its possible to use grailsApplication .configuration.property.name expression. I want to be able to access all those properties from this file that is under src/groovy directory. What I've tried so far
import grails.util.Holders
class ForkedTomcatCustomizer {
def application
void customize(Tomcat tomcat) {
println Holders.grailsApplication.config.property.name
}
}
gave me NPE saying that grailsAppliction is null
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class ForkedTomcatCustomizer {
def application
void customize(Tomcat tomcat) {
def ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT)
def grailsAppliction = ctx.grailsApplication.getObject()
println grailsAppliction.config.property.name
}
}
the same - NPE because grailsAppliction is null
Is it possible to handle this situation somehow? Thank you!
Use the below and see if it works
println Holders.config.property.name
You don't need grailsApplication when using Holders.
The examples below are probably a little more complex than what you need, but they show how to get a configuration property at build time. I use them to merge two configuration files, but you might not need to do that.
This method returns a config property when called here at the CompileEnd event.
You could define a similar method in your app's _Events.groovy file that calls your own configuration holder class.
import org.codehaus.groovy.grails.commons.ConfigurationHolder;
class KeyAndSecret{
public static String consumerKey = ConfigurationHolder.config.consumerKey;
public static String consumerSecret = ConfigurationHolder.config.consumerSecret;
}
Try like this
Relating to Accessing grails application config from a quartz job:
Apparently, DI doesn't happen prior to the creation of a job. I'm guessing this is the same with other grails artefacts (couldn't spot relevant documentation).
In my particular case, I was aiming to load a property from config and expose that property from the job class. In general though, it seems a valid use-case to me, that artefacts will load configuration, and then return those properties via API.
I'm wondering then, how could this be achieved when a class cannot rely on access to grailsApplication.config at construction.
Thanks
Try with:
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
class MyJob {
def execute() {
def myConfigVar = CH.flatConfig.get('my.var.setup.in.config.groovy')
...
}
}
OR
import grails.util.Holders
class MyJob {
def execute() {
def myConfigVar = Holders.config.my.var.setup.in.config.groovy
...
}
}
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"