GemFire '@type' 不生效:REST API与Native Client互操作异常
首先直接给结论:你不一定必须实现PdxSerializable来解决这个问题,但需要调整PDX配置或者处理逻辑,当然实现PdxSerializable是最稳妥的长期方案。
接下来分析你遇到的问题根源:
当你用Native Client保存Person对象时,PDX自动序列化会基于客户端的类信息生成对应的PDX元数据;但通过REST API发送带@type的JSON时,GemFire的REST服务是通过Jackson JSON库来处理序列化的,它生成的PDX数据结构和Native Client自动生成的可能存在元数据不匹配(比如字段顺序、类型映射细节),导致Native Client获取到的是PdxInstanceImpl实例,而不是可以直接强转的Person对象。
下面给你几个可行的解决方案,按推荐程度排序:
方案1:统一服务器端与客户端的PDX自动序列化配置(无需实现接口)
这个方案适合简单类场景,只需要确保服务器和Native Client都用相同的PDX自动序列化规则处理Person类:
- 服务器端配置:在
cache.xml或者gemfire.properties中配置PDX自动序列化,指定要处理的Person类:
<pdx> <pdx-serializer> <class-name>com.gemstone.gemfire.pdx.AutoSerializer</class-name> <parameter name="classes"> <string>com.package.Person</string> </parameter> </pdx-serializer> <!-- 设置为false,让服务器尽量返回可直接转换的对象 --> <pdx-read-serialized>false</pdx-read-serialized> </pdx>
- 客户端配置:确保Native Client的PDX配置和服务器端一致,同样启用AutoSerializer并包含
com.package.Person类。
这样服务器端处理REST请求时生成的PDX数据,会和Native Client生成的元数据完全匹配,客户端调用getObject()时就能正常转换为Person对象。
方案2:手动转换PdxInstance为目标对象(无需修改类或配置)
如果暂时无法调整服务器配置,可以在客户端获取数据时,先判断是否为PdxInstance,再手动映射字段:
Object rawValue = yourRegion.get("someId"); Person targetPerson; if (rawValue instanceof PdxInstance) { PdxInstance pdxInstance = (PdxInstance) rawValue; targetPerson = new Person(); targetPerson.setId((String) pdxInstance.getField("id")); targetPerson.setName((String) pdxInstance.getField("name")); } else { // 原本Native Client保存的对象,可以直接强转 targetPerson = (Person) rawValue; }
这个方式比较灵活,但需要手动维护字段映射,适合字段较少的简单类。
方案3:实现PdxSerializable接口(最稳妥的长期方案)
如果你的Person类结构复杂,或者需要长期跨客户端/REST API交互,推荐让Person类实现PdxSerializable接口,手动控制序列化逻辑,彻底避免元数据不匹配问题:
package com.package; import com.gemstone.gemfire.pdx.PdxReader; import com.gemstone.gemfire.pdx.PdxSerializable; import com.gemstone.gemfire.pdx.PdxWriter; public class Person implements PdxSerializable { private String id; private String name; // 必须要有无参构造函数,PDX序列化需要 public Person() {} // Getter和Setter方法 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void toData(PdxWriter writer) { // 明确指定要序列化的字段 writer.writeString("id", id); writer.writeString("name", name); } @Override public void fromData(PdxReader reader) { // 按相同顺序读取字段 id = reader.readString("id"); name = reader.readString("name"); } }
实现接口后,不管是Native Client还是REST API处理Person对象,都会使用统一的序列化逻辑,生成的PDX数据完全一致,客户端调用getObject()时就能无缝转换。
内容的提问来源于stack exchange,提问作者Rostislav V

