如何解决Faktor IPS中ClassloaderRuntimeRepository不可序列化问题:java.io.NotSerializableException
首先,这个java.io.NotSerializableException: org.faktorips.runtime.ClassloaderRuntimeRepository异常的核心原因是:Faktor IPS生成的KfzVertrag(及父类Vertrag)中持有了ClassloaderRuntimeRepository的引用,而这个类没有实现Serializable接口。当Hibernate在持久化、缓存实体或者处理关联关系时,会尝试序列化实体对象,遇到无法序列化的引用就会抛出这个错误。
下面是具体的排查和解决步骤:
1. 确保所有JPA实体实现Serializable接口
首先检查你的Angebot、KfzVertrag、Vertrag以及关联的KfzHaftpflichtdeckung、KfzAssistancedeckung类是否都实现了Serializable接口:
@Entity public class Angebot implements Serializable { // 原有代码... } @Entity @DiscriminatorValue("KV") // 其他Faktor IPS注解... public class KfzVertrag extends Vertrag implements Serializable { // 原有代码... } // 父类Vertrag也需要实现Serializable public abstract class Vertrag implements Serializable { // 原有代码... }
如果是Faktor IPS自动生成的类,你可以在Faktor IPS的模型配置(比如.policycmpttype文件)中开启“生成Serializable”的选项,让工具自动为生成的实体添加这个接口。
2. 标记非持久化的Faktor IPS内部引用为@Transient
Faktor IPS生成的策略类通常会持有一些内部运行时对象(比如ClassloaderRuntimeRepository),这些对象不需要被JPA持久化。找到KfzVertrag或Vertrag中持有这类引用的字段,添加@Transient注解,告诉Hibernate忽略这些字段:
public class KfzVertrag extends Vertrag implements Serializable { // 标记非持久化的运行时引用为@Transient @Transient private ClassloaderRuntimeRepository runtimeRepository; // 原有关联字段... }
如果这些字段是Faktor IPS自动生成的,你可以通过自定义生成模板或者在IPS模型中配置这些字段为“非持久化”,避免生成时包含在JPA映射中。
3. 禁用Hibernate二级缓存(临时排查)
如果你的项目启用了Hibernate二级缓存,缓存操作会触发实体序列化。可以先临时禁用二级缓存来验证是否是缓存导致的问题:
在application.properties中添加:
spring.jpa.properties.hibernate.cache.use_second_level_cache=false spring.jpa.properties.hibernate.cache.use_query_cache=false
如果禁用后异常消失,说明缓存序列化是触发点,后续可以调整缓存配置(比如使用支持非序列化对象的缓存实现),或者确保实体完全可序列化。
4. 验证类加载器一致性
虽然你禁用了spring.devtools.restart,但仍需确认实体类的类加载器是否和Hibernate的类加载器一致。DevTools的类加载器隔离可能导致某些类无法被正确序列化,你可以尝试:
- 完全移除
spring-boot-devtools依赖,重新运行项目 - 检查
application.properties中是否有其他类加载器相关配置,确保实体类由应用类加载器加载
5. 检查Linkki UI的间接影响
虽然UI版本理论上不影响持久化,但Linkki 2.0.0可能引入了不同的依赖或类加载器行为。你可以尝试暂时移除Linkki依赖,仅保留Spring Boot和JPA相关代码,验证是否能正常持久化。如果可以,再逐步添加Linkki并排查冲突点。
按照上述步骤逐一排查,应该能定位并解决序列化异常问题。
内容的提问来源于stack exchange,提问作者j neu

