You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Grails3.3.2+GORM6.1修改UserService重编译时触发空指针异常

Grails 3.3.2 + GORM 6.1: NullPointerException During Development Mode Recompilation

I've run into this exact issue before—when working with Grails 3.3.2 and GORM 6.1, modifying an abstract GORM data service class triggers a NPE during auto-recompilation in development mode, crashing the app. Here's a breakdown of the problem, how to reproduce it, and fixes that work:

The Exception

You'll see a stack trace like this during recompilation:

Exception in thread "Thread-8" BUG! exception in phase 'semantic analysis' in source unit '/Users/emmanuj/projects/cleena/demo/src/main/groovy/com/emmanuj/cleena/UserService.groovy' unexpected NullpointerException
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1070)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:537)
at grails.boot.GrailsApp.compileGroovyFile(GrailsApp.groovy:313)
at grails.boot.GrailsApp.recompile(GrailsApp.groovy:299)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:384)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182)
at grails.boot.GrailsApp$_enableDevelopmentModeWatch_closure1.doCall(GrailsApp.groovy:240)
at grails.boot.GrailsApp$_enableDevelopmentModeWatch_closure1.doCall(GrailsApp.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:408)
at groovy.lang.Closure.run(Closure.java:495)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
at org.grails.datastore.gorm.services.implementers.AbstractDetachedCriteriaServiceImplementor.doImplement(AbstractDetachedCriteriaServiceImplementor.groovy:79)
at org.grails.datastore.gorm.services.implementers.AbstractReadOperationImplementer.implement(AbstractReadOperationImplementer.groovy:62)
at org.grails.datastore.gorm.services.transform.ServiceTransformation.visitAfterTraitApplied(ServiceTransformation.groovy:278)
at org.grails.datastore.gorm.transform.AbstractTraitApplyingGormASTTransformation.visit(AbstractTraitApplyingGormASTTransformation.groovy:52)
at org.grails.datastore.gorm.transform.AbstractTraitApplyingGormASTTransformation.visit(AbstractTraitApplyingGormASTTransformation.groovy:42)
at org.grails.datastore.gorm.transform.AbstractGormASTTransformation.visit(AbstractGormASTTransformation.groovy:59)
at org.codehaus.groovy.transform.ASTTransformationVisitor.visitClass(ASTTransformationVisitor.java:134)
at org.codehaus.groovy.transform.ASTTransformationVisitor$2.call(ASTTransformationVisitor.java:178)
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1065)
... 34 more

Reproduction Steps

  • Create a new Grails 3.3.2 project
  • Add the User domain class:
import grails.compiler.GrailsCompileStatic
@GrailsCompileStatic
class User {
    String name
    static constraints = { }
}
  • Create a custom data service interface IUserService:
package com.emmanuj.cleena
/**
 * DataService interface for user domain
 */
interface IUserService {
    User get(Serializable id)
    List<User> list(Map args)
    Long count()
    void delete(Serializable id)
    User save(User user)
}
  • Create an abstract service class implementing this interface:
import groovy.util.logging.Slf4j
import grails.gorm.services.Service

@Slf4j
@Service(User)
abstract class UserService implements IUserService {
    def grailsApplication
    List<User> search(User currentUser, long radius, int offset, int max){
        return []
    }
    def getZipcodes(String zipCode, long radius) {
        return []
    }
}
  • Start the app via the Grails interactive console, then modify UserService.groovy—the recompilation will trigger the NPE.

Root Cause

This is a known bug in GORM 6.1: when using an abstract GORM data service class that implements a custom interface, the GORM AST transformation fails to properly resolve method metadata during auto-recompilation in development mode, leading to the NullPointerException.

Fixes

The bug was fixed in GORM 6.1.10 and later. Update your build.gradle to use a newer GORM version:

dependencies {
    // Keep other dependencies as-is
    compile "org.grails.plugins:gorm-hibernate5:6.1.10"
    // Adjust if you're using a different GORM implementation (like mongodb)
}

This resolves the issue completely while keeping development auto-recompilation enabled.

2. Disable Auto-Recompilation (Temporary Workaround)

If you can't upgrade right now, turn off auto-recompilation in application.yml:

grails:
    development:
        watch:
            enabled: false

Note: You'll have to manually restart the app after every code change with this approach.

3. Adjust Service Class Structure

Remove the abstract modifier from UserService—GORM's AST transformation will automatically implement the CRUD methods from your IUserService interface without needing an abstract class:

@Slf4j
@Service(User)
class UserService implements IUserService {
    def grailsApplication
    List<User> search(User currentUser, long radius, int offset, int max){
        return []
    }
    def getZipcodes(String zipCode, long radius) {
        return []
    }
}

This avoids the bug because GORM no longer has to handle abstract class metadata during recompilation.

内容的提问来源于stack exchange,提问作者Emmanuel John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:56:58