Grails含复合主键的Domain类无法调用REST API求助
解决Grails复合主键Domain类JSON序列化空指针问题
我之前也碰到过一模一样的问题,这个空指针的根源很明确:Grails默认的JSON DomainClassMarshaller并不支持复合主键的域类序列化。它会尝试去读取域类的id属性(单一主键的场景),但你的CGender用的是budYear和genderCode组成的复合主键,没有这个单一的id字段,所以Marshaller拿到null之后就抛出了NPE。
下面给你两个靠谱的解决方案,你可以根据自己的场景选择:
方案一:自定义JSON Marshaller(推荐)
手动编写一个Marshaller来控制CGender的JSON序列化逻辑,完全规避默认Marshaller的问题。
- 创建一个Marshaller类,放在
src/main/groovy下:
import grails.converters.JSON import org.springframework.stereotype.Component @Component class CGenderJsonMarshaller { void register() { JSON.registerObjectMarshaller(CGender) { CGender gender -> // 手动定义需要序列化的字段,包括复合主键的两个字段 def result = [ budYear: gender.budYear, genderCode: gender.genderCode, genderNdesc: gender.genderNdesc, genderEdesc: gender.genderEdesc, disableFlag: gender.disableFlag, createdBy: gender.createdBy, createdDate: gender.createdDate ] // 如果需要序列化关联的CProjects,记得手动处理(避免循环引用或同样的复合键问题) // if (gender.cProjects) { // result.cProjects = gender.cProjects.collect { project -> // [/* 这里定义CProject需要序列化的字段 */] // } // } return result } } }
- 在应用启动时注册这个Marshaller:
创建一个启动监听类,同样放在src/main/groovy下:
import org.springframework.boot.context.event.ApplicationReadyEvent import org.springframework.context.ApplicationListener class CGenderMarshallerStartup implements ApplicationListener<ApplicationReadyEvent> { private final CGenderJsonMarshaller cGenderJsonMarshaller // 构造注入Marshaller CGenderMarshallerStartup(CGenderJsonMarshaller cGenderJsonMarshaller) { this.cGenderJsonMarshaller = cGenderJsonMarshaller } @Override void onApplicationEvent(ApplicationReadyEvent event) { // 应用启动完成后注册Marshaller cGenderJsonMarshaller.register() } }
方案二:添加虚拟的id getter
这个方案更简单,但需要注意可能带来的副作用(比如数据绑定场景):
在你的CGender类里添加一个getId()方法,返回复合主键的Map形式,让默认Marshaller能拿到“id”值:
@Resource(uri="/gender",formats = ['json','xml']) class CGender implements Serializable { // ... 原有的字段和方法 ... // 添加这个方法 Map getId() { [budYear: budYear, genderCode: genderCode] } // ... 原有的mapping、constraints等 ... }
额外注意事项
- 如果你的关联类(比如
CProject、CYear)也使用了复合主键,同样会遇到序列化问题,需要用上述方案一并处理。 - 测试时要覆盖列表渲染、单个资源渲染等场景,确保没有其他序列化异常。
内容的提问来源于stack exchange,提问作者Arish Nepal
相关产品推荐
相关产品推荐

