如何在ProtoStream 4.4.3(Java8)中编组?泛型与ZonedDateTime问题
问题解决步骤
一、解决ZonedDateTime无参构造错误
Java 8的ZonedDateTime没有公共无参构造函数,Protostream无法直接实例化它,可通过以下两种方式处理:
方案1:引入JDK8时间类型支持模块
如果使用Maven,添加对应依赖:
<dependency> <groupId>org.infinispan.protostream</groupId> <artifactId>protostream-jdk8</artifactId> <version>你的Protostream版本</version> </dependency>
然后在ProtoInitializer相关类中注册JDK8时间编解码器:
public class ProtoSchemaInitializer implements GeneratedSchema { @Override public void registerSchema(SerializationContext serCtx) { // 注册JDK8时间类型编解码器 Jdk8TimeMarshaller.register(serCtx); // 注册生成的proto文件 serCtx.registerProtoFiles(FileDescriptorSource.fromResources("proto/abc.proto")); } @Override public void registerMarshallers(SerializationContext serCtx) { Jdk8TimeMarshaller.register(serCtx); } }
方案2:自定义ZonedDateTime的Marshaller
若不想引入额外模块,自行实现编解码器:
public class ZonedDateTimeMarshaller implements Marshaller<ZonedDateTime> { @Override public Class<? extends ZonedDateTime> getJavaClass() { return ZonedDateTime.class; } @Override public String getTypeName() { return "pkg_abc.ZonedDateTime"; } @Override public void writeTo(ProtoStreamWriter writer, ZonedDateTime zonedDateTime) throws IOException { writer.writeString("value", zonedDateTime.toString()); } @Override public ZonedDateTime readFrom(ProtoStreamReader reader) throws IOException { return ZonedDateTime.parse(reader.readString("value")); } }
同时在proto schema中定义对应消息类型:
message ZonedDateTime { string value = 1; }
最后在初始化类中注册该Marshaller。
二、解决通配符泛型List<? extends Account>错误
Protostream不支持通配符类型,需修改集合类型并处理多态逻辑:
- 修改
P类的集合字段类型
将List<? extends Account>改为List<Account>:
class P { @ProtoField(number = 1, collectionImplementation = ArrayList.class) List<Account> accounts; @ProtoField(number = 2) ZonedDateTime fromDate; @ProtoFactory public P(List<Account> accounts, ZonedDateTime fromDate) { this.accounts = accounts; this.fromDate = fromDate; } }
- 在父类
Account上声明多态子类
给Account类添加@ProtoInclude注解,指定所有子类:
@ProtoInclude(value = 1, type = SavingAccount.class) @ProtoInclude(value = 2, type = ChequingAccount.class) public abstract class Account { // 父类字段需添加@ProtoField注解(如有) }
- 完善子类的注解与构造
子类需添加@ProtoMessage注解,同时提供无参构造(Protostream要求):
@ProtoMessage(name = "SavingAccount") public class SavingAccount extends Account { @ProtoField(number = 1) private String name_sa; public SavingAccount() {} public SavingAccount(String name_sa) { this.name_sa = name_sa; } // getter、setter方法 public String getName_sa() { return name_sa; } public void setName_sa(String name_sa) { this.name_sa = name_sa; } }
@ProtoMessage(name = "ChequingAccount") public class ChequingAccount extends Account { @ProtoField(number = 1) private String holder_ca; public ChequingAccount() {} public ChequingAccount(String holder_ca) { this.holder_ca = holder_ca; } // getter、setter方法 public String getHolder_ca() { return holder_ca; } public void setHolder_ca(String holder_ca) { this.holder_ca = holder_ca; } }
三、修正ProtoInitializer的语法错误
原代码中Public需改为小写public:
@AutoProtoBuilder( basePackages = "com.domain", schemaFileName = "abc.proto", schemaFilePath = "proto/", schemaPackageName = "pkg_abc" ) public interface ProtoInitializer extends GeneratedSchema { }
最终生成的Proto Schema
完成上述修改后,生成的abc.proto示例如下:
package pkg_abc; message Account { oneof subtype { SavingAccount saving_account = 1; ChequingAccount chequing_account = 2; } } message SavingAccount { string name_sa = 1; } message ChequingAccount { string holder_ca = 1; } message ZonedDateTime { string value = 1; } message P { repeated Account accounts = 1; ZonedDateTime from_date = 2; }
内容的提问来源于stack exchange,提问作者user1912935
相关产品推荐
相关产品推荐

