Gson序列化/反序列化嵌套多态Rule类集合问题求助
我有如下类结构:
public abstract class Rule { .... } public class RuleType1 extends Rule { ... } public class RuleType2 extends Rule { ... } public class RuleType3 extends Rule { ... } public class RuleType4 extends Rule { ... } public class RuleSet extends Rule { ... private final Collection<Rule> rules; }
我需要解析包含多层嵌套Rule子类的JSON,由于RuleSet内部包含Rule集合,所以它也可以嵌套其他RuleSet。我不想实现自定义(反)序列化器,因为这会降低子类灵活性——修改子类时还得同步修改序列化器。
需要序列化/反序列化的JSON示例如下:
{ "ruleType": "ruleSet", "rules": [ { "ruleType": "ruleSet", "rules": [ { "ruleType": "RuleType1" }, { "ruleType": "ruleSet", "rules": [ { "ruleType": "RuleType2" }, { "ruleType": "RuleType3" } ] } ] }, { "ruleType": "ruleSet", "rules": [ { "ruleType": "RuleType1" }, { "ruleType": "ruleSet", "rules": [ { "ruleType": "RuleType3" }, { "ruleType": "RuleType4" } ] } ] } ] }
补充信息
实际项目中类结构有所调整:RuleSet包含Collection<IRule> rules,另外定义了SampleClass:
public class SampleClass { public IRule parameters; public double defaultConfidence; public String ruleType; }
我用RuntimeTypeAdapterFactory配置Gson:
static RuntimeTypeAdapterFactory<IRule> adaptor = RuntimeTypeAdapterFactory.of(IRule.class) .registerSubtype(RuleSet.class) .registerSubtype(Rule.class); static RuntimeTypeAdapterFactory<Rule> ruleAdaptor = RuntimeTypeAdapterFactory.of(Rule.class) .registerSubtype(DocumentTypesRule.class) .registerSubtype(DataAttributesRule.class) .registerSubtype(DictionariesRule.class) .registerSubtype(FileFormatsRule.class) .registerSubtype(FileLengthRule.class) .registerSubtype(FileNamePatternsRule.class) .registerSubtype(FixedRule.class) .registerSubtype(ImageTypesRule.class) .registerSubtype(KeywordsRule.class) .registerSubtype(RegexesRule.class) .registerSubtype(SimilaritiesRule.class) .registerSubtype(TopicsRule.class); private static final Gson GSON = new GsonBuilder() .registerTypeAdapterFactory(adaptor) .registerTypeAdapterFactory(ruleAdaptor) .create();
调用GSON.fromJson(response, SampleClass.class)时抛出错误:
java.lang.RuntimeException: Unable to invoke no-args constructor for interface <classPath>.IRule. Registering an InstanceCreator with Gson for this type may fix this problem.
问题根源
错误核心在于:Gson无法实例化接口IRule,且你的适配器配置层级断裂——你把抽象类Rule注册为IRule的子类型,但Rule本身无法实例化;同时所有具体Rule子类只注册到了Rule的适配器,没有纳入IRule的多态处理链,导致Gson解析IRule类型时找不到具体实现类的构造逻辑。
修正步骤
合并适配器配置,统一注册到IRule
不需要为Rule单独创建适配器,直接将所有具体Rule子类和RuleSet都注册到IRule的RuntimeTypeAdapterFactory中(需确保Rule实现IRule,RuleSet继承Rule),同时指定JSON中标识类型的字段名"ruleType":static RuntimeTypeAdapterFactory<IRule> ruleAdapter = RuntimeTypeAdapterFactory.of(IRule.class, "ruleType") // 注册RuleSet,对应JSON中的ruleType值 .registerSubtype(RuleSet.class, "ruleSet") // 注册所有具体Rule子类,注意和JSON中的ruleType值一一对应 .registerSubtype(DocumentTypesRule.class, "DocumentTypesRule") .registerSubtype(DataAttributesRule.class, "DataAttributesRule") .registerSubtype(DictionariesRule.class, "DictionariesRule") .registerSubtype(FileFormatsRule.class, "FileFormatsRule") .registerSubtype(FileLengthRule.class, "FileLengthRule") .registerSubtype(FileNamePatternsRule.class, "FileNamePatternsRule") .registerSubtype(FixedRule.class, "FixedRule") .registerSubtype(ImageTypesRule.class, "ImageTypesRule") .registerSubtype(KeywordsRule.class, "KeywordsRule") .registerSubtype(RegexesRule.class, "RegexesRule") .registerSubtype(SimilaritiesRule.class, "SimilaritiesRule") .registerSubtype(TopicsRule.class, "TopicsRule"); private static final Gson GSON = new GsonBuilder() .registerTypeAdapterFactory(ruleAdapter) .create();确保所有子类存在无参构造器
Gson默认要求类具有无参构造器(显式定义或隐式生成均可),如果你的Rule子类或RuleSet只有带参构造器,需显式添加无参构造器,或使用Lombok的@NoArgsConstructor注解自动生成。优化SampleClass字段(可选)
SampleClass中同时存在IRule parameters和String ruleType,如果JSON中的ruleType仅用于标识parameters的类型,可删除SampleClass中的ruleType字段——RuntimeTypeAdapterFactory会自动通过JSON中的ruleType字段确定parameters的具体实现类。若业务需要保留该字段,确保其值与JSON中的对应即可。
验证
调整配置后重新调用GSON.fromJson(response, SampleClass.class),即可正常完成嵌套结构的反序列化。
内容的提问来源于stack exchange,提问作者Sahib Yar

