Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Startup sometimes fails when used together with resources plugin #148

Closed
stefanrother opened this issue Feb 22, 2017 · 10 comments
Closed

Startup sometimes fails when used together with resources plugin #148

stefanrother opened this issue Feb 22, 2017 · 10 comments

Comments

@stefanrother
Copy link

Problem

We are migrating our Grails 2.2.2 application from the resources plugin to the asset-pipeline plugin. Some views are already migrated but most of them still use the resources plugin.

Sometimes the application does not start and produces the following stack trace on initialization of the asset-pipeline:
| 2017-01-27 09:16:25,342 [localhost-startStop-1] ERROR org.grails.plugin.resource.ResourceProcessor - Unable to load resources groovy.lang.MissingMethodException: No signature of method: asset.pipeline.grails.CachingLinkGenerator.appendMapKey() is applicable for argument types: (java.lang.StringBuilder, java.util.LinkedHashMap) values: [resource, [plugin:jquery, dir:js/jquery, ...]] at asset.pipeline.grails.CachingLinkGenerator.makeKey(CachingLinkGenerator.groovy:55) at asset.pipeline.grails.CachingLinkGenerator.resource(CachingLinkGenerator.groovy:24) at org.grails.plugin.resource.ResourceProcessor.buildLinkToOriginalResource(ResourceProcessor.groovy:485) at org.grails.plugin.resource.ResourceModule$_closure1.doCall(ResourceModule.groovy:62) at org.grails.plugin.resource.ResourceModule.<init>(ResourceModule.groovy:58) at org.grails.plugin.resource.ResourceProcessor.defineModuleFromBuilder(ResourceProcessor.groovy:681) at org.grails.plugin.resource.ResourceProcessor$_loadModules_closure19.doCall(ResourceProcessor.groovy:802) at org.grails.plugin.resource.ResourceProcessor.loadModules(ResourceProcessor.groovy:802) at org.grails.plugin.resource.ResourceProcessor.reloadAll(ResourceProcessor.groovy:1075) at ResourcesGrailsPlugin$_closure3.doCall(ResourcesGrailsPlugin.groovy:172) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)

The source of the problem seems to be buried in a bug in Groovy (GROOVY-3073 - Private inheritance bug: Closure accessing private method) and the fact that the class asset.pipeline.grails.CachingLinkGenerator extends org.codehaus.groovy.grails.web.mapping.CachingLinkGenerator and accesses the private method appendMapKey() from the super class via its makeKey() method.

We were surprised that this is possible (We did not expect the access to private methods of the super class to work) and that this sometimes fails.

The problem appears on our development machines (iMacs with OS X 10.11.6 and JDK 1.7.0_75) and our staging and production systems (Debian 8 with Tomcat 7.0.73 and JDK 1.7.0_111)

Workaround

Our workaround is to inject a modified copy of asset.pipeline.grails.CachingLinkGenerator that has copies of the private methods of the super class that were accessed by makeKey(). Via resources.groovy we inject the class the same way it is done in AssetPipelineGrailsPlugin.

@davydotcom
Copy link
Contributor

davydotcom commented Feb 22, 2017 via email

@jglapa
Copy link

jglapa commented Apr 13, 2017

Seeing the same upgrading to Grails 3.2.8 from 3.2.6.

2017-04-13 15:33:14,550 [http-nio-8080-exec-4] DEBUG o.g.w.s.v.GroovyPageView - Error processing GroovyPageView: [views/login/auth.gsp:30] Error executing tag <g:form>: No signature of method: asset.pipeline.grails.CachingLinkGenerator.appendMapKey() is applicable for argument types: (java.lang.StringBuilder, org.grails.taglib.GroovyPageAttributes) values: [link, [method:post, action:auth, id:loginForm]] org.grails.taglib.GrailsTagException: [views/login/auth.gsp:30] Error executing tag <g:form>: No signature of method: asset.pipeline.grails.CachingLinkGenerator.appendMapKey() is applicable for argument types: (java.lang.StringBuilder, org.grails.taglib.GroovyPageAttributes) values: [link, [method:post, action:auth, id:loginForm]]

@jukin-jerry
Copy link

jukin-jerry commented Apr 21, 2017

I have the same problem as @jglapa

Stepping through in a debugger, i can see that this line:
https://github.com/bertramdev/asset-pipeline/blob/master/asset-pipeline-grails/src/main/groovy/asset/pipeline/grails/CachingLinkGenerator.groovy#L56

calls this method:
https://github.com/grails/grails-core/blob/v3.2.8/grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/CachingLinkGenerator.java#L104

when the exception is thrown.

@samuelzyx
Copy link

Same problem in createLink function (Grails updagre 3.2.9 from 3.2.7)

protected String generateLink(String action, String token) {
        createLink(base: "$request.scheme://$request.serverName:$request.serverPort$request.contextPath",
                controller: 'user', action: action, params: [t:token])
    }

Error in log

Caused by: groovy.lang.MissingMethodException: No signature of method: asset.pipeline.grails.CachingLinkGenerator.appendMapKey() is applicable for argument types: (java.lang.StringBuilder, org.grails.taglib.GroovyPageAttributes) values: [link, [base:http://localhost:8080, controller:user, action:resetPassword, ...]]
        at asset.pipeline.grails.CachingLinkGenerator.makeKey(CachingLinkGenerator.groovy:56)
        at org.grails.web.mapping.CachingLinkGenerator.link(CachingLinkGenerator.java:79)
        at org.grails.plugins.web.taglib.ApplicationTagLib.doCreateLink(ApplicationTagLib.groovy:382)
        at org.grails.plugins.web.taglib.ApplicationTagLib$_closure9.doCall(ApplicationTagLib.groovy:359)
        at org.grails.taglib.TagOutput.captureTagOutput(TagOutput.java:64)
        at grails.artefact.gsp.TagLibraryInvoker$Trait$Helper.methodMissing(TagLibraryInvoker.groovy:88)
        at btask.UserController.generateLink(UserController.groovy:859)
        at btask.UserController.forgotPassword(UserController.groovy:662)
        ... 47 common frames omitted

@jukin-jerry
Copy link

jukin-jerry commented Apr 27, 2017

I started to implement @stefanrother 's workaround in his report, but I found that by reimplementing the private method it depends on another ton of private stuff in the class and doesn't seem feasible. I think the simple fix is for the base class (org.codehaus.groovy.grails.web.mapping.CachingLinkGenerator) to not mark that method as private. Anyone have any pull with the devs of that module? I've never forked grails framework else I'd just do it and submit a PR. My workaround was to stop using g:link which isn't feasible in anything but the short term.

@jglapa
Copy link

jglapa commented Apr 27, 2017

I wonder why this started happening with just a minor Grails version update. From the release notes it looks like the version was build with a newer Groovy 2.4.10. They warn that the StaticCompile is more strict though.
You can theoretically bypass the private access by using reflection but I'm not sure if this is such a good idea.

@jukin-jerry
Copy link

Downgrading to Groovy 2.4.7 in my Grails 3.2.9 webapp project clears up this problem for me. I did this by:

  1. Adding "groovyVersion=2.4.7" to gradle.properties
  2. I'm sure there is a better way, but here is how i updated my build.gradle to explicitly override all groovy packages versions:
dependencies {
    provided "org.codehaus.groovy:groovy:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-all:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-ant:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-groovydoc:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-json:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-sql:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-templates:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-test:${groovyVersion}"
    provided "org.codehaus.groovy:groovy-xml:${groovyVersion}"

    console "org.codehaus.groovy:groovy:${groovyVersion}"
    console "org.codehaus.groovy:groovy-console:${groovyVersion}"
    console "org.codehaus.groovy:groovy-groovysh:${groovyVersion}"
    console "org.codehaus.groovy:groovy-swing:${groovyVersion}"
    console "org.codehaus.groovy:groovy-templates:${groovyVersion}"
    console "org.codehaus.groovy:groovy-xml:${groovyVersion}"
   ....
} 
  1. Checked work with
./grailsw dependency-report --plain-output

@jglapa
Copy link

jglapa commented Jun 7, 2017

FYI I've raised an issue in the grails core project grails/grails-core#10660

@jglapa
Copy link

jglapa commented Jun 19, 2017

UPDATE the method visibility has been changed to protected with this grails/grails-core@7e48044

This should be available with the next Grails release.

@davydotcom
Copy link
Contributor

nice thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants