grails-audit-logging-plugin icon indicating copy to clipboard operation
grails-audit-logging-plugin copied to clipboard

hot reload using undertow application server throws NPE

Open xqliu opened this issue 3 years ago • 2 comments

Thanks for reporting an issue for the grails audit-logging plugin. Please review the task list below before submitting the issue.

WARNING: Your issue report may be closed if the issue report is incomplete and does not include an example. Make sure the below tasks are completed!

NOTE: If you are unsure about something and the issue is more of a question, a better place to ask questions is on Stack Overflow (http://stackoverflow.com/tags/grails) or Slack (http://slack-signup.grails.org). DO NOT use the issue tracker to ask questions.

Task List

  • [x] Steps to reproduce provided
  • [x] Stacktrace (if present) provided
  • [x] Example that reproduces the problem uploaded to Github
  • [x] Full description of the issue provided (see below)

Steps to Reproduce

  1. Generate a new template project on http://start.grails.org/ with web profile
  2. Change the build.gradle file and replace tomcat with undertow as below
// Configuration part 
configurations {
    developmentOnly
    runtimeClasspath {
        extendsFrom developmentOnly
    }
   // @@ --> Follow two lines exclude tomcat packages
    compile.exclude module: 'spring-boot-starter-tomcat'
    compile.exclude group: 'org.apache.tomcat'    
}

// Include undertow explicitly and comment out tomcat part
dependencies {
    developmentOnly("org.springframework.boot:spring-boot-devtools")
    compile "org.springframework.boot:spring-boot-starter-logging"
    compile "org.springframework.boot:spring-boot-autoconfigure"
    compile "org.grails:grails-core"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile 'org.grails.plugins:audit-logging:4.0.3'    
    //@@ --> Follow two lines Include undertow explicitly and comment out tomcat part
    //compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.springframework.boot:spring-boot-starter-undertow"    
  1. Configure audit plugin and start the application by grardle bootRun (can directly clone the repo I mentioned below)
  2. Change Application.groovy and add a new line
  3. Reload starts but failed and here are the exception
java.lang.NullPointerException: null
	at io.undertow.servlet.spec.ServletContextImpl.getInitParameterNames(ServletContextImpl.java:430)
	at org.springframework.web.context.support.ServletContextPropertySource.getPropertyNames(ServletContextPropertySource.java:41)
	at org.grails.config.EnvironmentAwarePropertySource.initialize(EnvironmentAwarePropertySource.java:79)
	at org.grails.config.EnvironmentAwarePropertySource.getPropertyNames(EnvironmentAwarePropertySource.java:45)
	at org.grails.config.PropertySourcesConfig.mergeEnumerablePropertySource(PropertySourcesConfig.java:109)
	at org.grails.config.PropertySourcesConfig.initializeFromPropertySources(PropertySourcesConfig.java:98)
	at org.grails.config.PropertySourcesConfig.<init>(PropertySourcesConfig.java:48)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:80)
	at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:249)
	at grails.plugins.orm.auditable.ReflectionUtils.setAuditConfig(ReflectionUtils.groovy:74)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
	at groovy.lang.MetaClassImpl.setProperty(MetaClassImpl.java:2754)
	at groovy.lang.MetaClassImpl.setProperty(MetaClassImpl.java:3809)
	at org.codehaus.groovy.runtime.InvokerHelper.setProperty(InvokerHelper.java:215)
	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.setProperty(ScriptBytecodeAdapter.java:496)
	at grails.plugins.orm.auditable.AuditLoggingConfigUtils.mergeConfig(AuditLoggingConfigUtils.groovy:103)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(StaticMetaMethodSite.java:149)
	at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:100)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:216)
	at grails.plugins.orm.auditable.AuditLoggingConfigUtils.reloadAuditConfig(AuditLoggingConfigUtils.groovy:71)
	at grails.plugins.orm.auditable.AuditLoggingConfigUtils$reloadAuditConfig$0.call(Unknown Source)
	at grails.plugins.orm.auditable.AuditLoggingGrailsPlugin$_doWithSpring_closure2.doCall(AuditLoggingGrailsPlugin.groovy:110)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
	at groovy.lang.Closure.call(Closure.java:405)
	at groovy.lang.Closure.call(Closure.java:399)
	at grails.spring.BeanBuilder.invokeBeanDefiningClosure(BeanBuilder.java:759)
	at grails.spring.BeanBuilder.beans(BeanBuilder.java:588)
	at grails.spring.BeanBuilder.invokeMethod(BeanBuilder.java:531)
	at org.grails.plugins.DefaultGrailsPlugin.doWithRuntimeConfiguration(DefaultGrailsPlugin.java:543)
	at org.grails.plugins.AbstractGrailsPluginManager.doRuntimeConfiguration(AbstractGrailsPluginManager.java:166)
	at grails.boot.config.GrailsApplicationPostProcessor.postProcessBeanDefinitionRegistry(GrailsApplicationPostProcessor.groovy:171)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:125)
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:99)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:485)
	at grails.boot.GrailsApp.run(GrailsApp.groovy:472)
	at myapp.Application.main(Application.groovy:12)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)

Expected Behaviour

Hot reload should success

Actual Behaviour

Hot reload fails and application stops response to frontend request

Environment Information

  • Operating System: MacoS 11
  • GORM Version: 7.0.8.RELEASE
  • Grails Version (if using Grails): 4.0.12
  • JDK Version: 11

Example Application

https://github.com/xqliu/grails-audit-plugin-issue-reproduce

xqliu avatar Oct 05 '21 02:10 xqliu

I have debugged the application and it is caused by deploymentInfo in file io.undertow.servlet.spec.ServletContextImpl is null, when springboot-dev-tools restart the application, the deploymentInfo was first set to null in destroy() method of io.undertow.servlet.spec.ServletContextImpl, but never been set a new value, so NPE error was thrown in below code

 @Override
    public Enumeration<String> getInitParameterNames() {
        return new IteratorEnumeration<>(deploymentInfo.getInitParameters().keySet().iterator());
                                                                 //deploymentInfo is null
    }

The error was caused by the follow line in auditable/ReflectionUtils.groovy

    static void setAuditConfig(ConfigObject c) {
        ConfigObject config = new ConfigObject()
        config.grails.plugin.auditLog = c

        PropertySource propertySource = new MapPropertySource('AuditConfig', [:] << config)
        def propertySources = application.mainContext.environment.propertySources
        propertySources.addFirst propertySource

        // Follow line caused the exception mentioned above
        getApplication().config = new PropertySourcesConfig(propertySources)
    }

Hope the analysis helps.

Thanks.

xqliu avatar Oct 05 '21 02:10 xqliu

Hi, is there any update on this or anything I could do to help? Thanks ;)

xqliu avatar Oct 20 '21 21:10 xqliu