grails / grails-database-migration

Grails® framework Database Migration Plugin
Apache License 2.0
98 stars 116 forks source link

ServletContext is not really what is should be during dbm scripts #143

Open fredgalvao opened 6 years ago

fredgalvao commented 6 years ago

Heads Up: there's a chance this is actually a grails issue, as it is reproducible with grails console too. I wanted to make sure here first, as it's the main scenario I have.

Consider:

Task List

Steps to Reproduce

  1. Create a grails application
  2. Apply/install GDM
  3. Create an empty file inside webapp
  4. Create a bean configuration that needs to access the file on [3] through it's real path
  5. Run DMS

Expected Behaviour && Actual Behaviour

Issue The servletContext obtainable through multiple sources/means, during the bean configuration phase, for both MA and PLUGIN, in the context of a DMS, is a org.springframework.mock.web.MockServletContext, even though GDM+MA fires up the "grails application" context in the development profile (spring security is loaded, bootstrap runs, beans register, etc). It should be org.apache.catalina.core.ApplicationContextFacade, or any other implementation of a ServletContext that is properly setup, so that getRealPath (for example) would work.

My issue I have an application with GDM, and another internal plugin that sets up a bean (easy stuff). On the configuration of this bean, I need to access the real path of something inside src/main/webapp (standard stuff). For run-app or test-app and it's derivatives, it shines: I can access servletContext any way I want [holders, mainContext, bean], and it's a valid instance, and getRealPath returns stuff from where it is, dev or prod. Then, when I need to run dbm-gorm-diff changelog-bacon.groovy, it fails with a few NPE, caused by the fact that servletContext isn't accessible through all means, and is a mock otherwise. I've tried many other ways to get the real path to a file there but with no success (this isn't really an issue with the plugin, just colateral damage).

Environment Information

Example Application

Changes made to the pure grails create-app worth mentioning:

Stacktraces and code snippets

ON DMS

WARN MockServletContext : Couldn't determine real path of resource class path resource [src/main/webapp] java.io.FileNotFoundException: class path resource [src/main/webapp] cannot be resolved to URL because it does not exist <LONG STACKTRACE I DON'T THINK IS USEFUL FOR NOW> MABeansConfiguration : @Autowired servletContext.getRealPath('.')::null

WARN MockServletContext : Couldn't determine real path of resource class path resource [src/main/webapp/] java.io.FileNotFoundException: class path resource [src/main/webapp/] cannot be resolved to URL because it does not exist <LONG STACKTRACE I DON'T THINK IS USEFUL FOR NOW> MABeansConfiguration : @Autowired servletContext.getRealPath('/')::null


- on a bean configuration from PLUGIN
Same output as on the MA, but with the protection domain returning the location of the jar on maven's cache, which is unrelated to the issue.

**ON INTEGRATION TESTS** (the output on `run-app` differs from this only on the path to compiled classes, which is expected)
- on a bean configuration from MA

MABeansConfiguration : @Autowired servletContext::org.apache.catalina.core.ApplicationContextFacade@652e64bb MABeansConfiguration : Holders.servletContext::org.apache.catalina.core.ApplicationContextFacade@652e64bb MABeansConfiguration : ServletContextHolder.servletContext::org.apache.catalina.core.ApplicationContextFacade@652e64bb MABeansConfiguration : @Autowired grailsApplication.mainContext::org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@11a95360: startup date [Wed Apr 25 20:52:10 BRT 2018]; root of context hierarchy MABeansConfiguration : @Autowired grailsApplication.mainContext?.servletContext::org.apache.catalina.core.ApplicationContextFacade@652e64bb MABeansConfiguration : this.getClass().getResource("/").getPath()::/build/classes/integrationTest/ MABeansConfiguration : getProtectionDomain().getCodeSource()::/build/classes/main/ MABeansConfiguration : this.getClass().getClassLoader().getResource('.')::file:/build/classes/integrationTest/ MABeansConfiguration : this.getClass().getClassLoader().getResource('/')::null MABeansConfiguration : @Autowired servletContext.getRealPath('.')::/src/main/webapp MABeansConfiguration : @Autowired servletContext.getRealPath('/')::/src/main/webapp/


- on a bean configuration from PLUGIN
Same output as on the MA, but with the protection domain returning the location of the jar on maven's cache, which is unrelated to the issue.
fredgalvao commented 6 years ago

Relates to https://github.com/grails-plugins/grails-database-migration/issues/125

fredgalvao commented 6 years ago

Maybe relates to https://github.com/grails-plugins/grails-database-migration/issues/141

jameskleeh commented 6 years ago

Upload an example project that reproduces the issue. I don't think the two issues you linked to are related to anything with the servlet class

fredgalvao commented 6 years ago

The stacktrace on #125 is exactly the same, that made me think they were related. I supposed the grails version support could relate because this seems like the execution context for the scripts on this plugin doesn't match 100% of what's needed from grails (similar to what unit tests do).

fredgalvao commented 6 years ago

@jameskleeh Updated the main post with the Example Application section. Minimal changes to the pure grails shell, and results are exactly the same.