You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Infinispan 7升级至10.1.3:UUID作为缓存键/字段的序列化处理

解决Infinispan 10.1.3中Protostream处理UUID的问题

刚好我之前处理过类似的Infinispan升级问题,给你一步步拆解解决方法——不管是把UUID作为缓存键,还是作为实体类的字段,核心都是让Protostream能识别并正确序列化/反序列化UUID:

1. 给UUID自定义Protostream转换器

因为Protobuf本身不支持UUID类型,我们可以把它转成String来存储。这里有两种方式,推荐用注解适配器,更贴合你想用注解处理器的需求:

方式一:注解适配器(推荐适配注解处理器)

写一个UUIDAdapter类,用@ProtoAdapter标记,告诉Protostream如何把UUID和String互相转换:

import org.infinispan.protostream.annotations.ProtoAdapter;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import java.util.UUID;

@ProtoAdapter(UUID.class)
public class UUIDAdapter {
    // 反序列化:从String生成UUID
    @ProtoFactory
    public UUID create(String uuidStr) {
        return UUID.fromString(uuidStr);
    }

    // 序列化:把UUID转成String
    @ProtoField(number = 1, type = org.infinispan.protostream.annotations.ProtoType.STRING)
    public String getValue(UUID uuid) {
        return uuid.toString();
    }
}

方式二:自定义Marshaller类

如果不想用注解,也可以直接实现Marshaller接口:

import org.infinispan.protostream.Marshaller;
import org.infinispan.protostream.ProtobufTagMarshaller;
import java.io.IOException;
import java.util.UUID;

public class UUIDMarshaller implements Marshaller<UUID> {
    @Override
    public UUID readFrom(ProtobufTagMarshaller.Input input) throws IOException {
        return UUID.fromString(input.readString());
    }

    @Override
    public void writeTo(ProtobufTagMarshaller.Output output, UUID uuid) throws IOException {
        output.writeString(uuid.toString());
    }

    @Override
    public Class<? extends UUID> getJavaClass() {
        return UUID.class;
    }

    @Override
    public String getTypeName() {
        return "your.package.UUID"; // 自定义proto类型名即可
    }
}

2. 注册转换器到Protostream上下文

不管用哪种方式,都需要把转换器注册到Infinispan的序列化上下文中,这样框架才能识别UUID:

import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.protostream.SerializationContext;
import org.infinispan.protostream.marshaller.ProtoStreamMarshaller;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;

public class CacheInitializer {
    public static void main(String[] args) {
        EmbeddedCacheManager manager = new DefaultCacheManager();
        
        // 获取Protostream序列化上下文
        SerializationContext ctx = ProtoStreamMarshaller.getSerializationContext(manager);
        
        // 注册UUID适配器(注解方式)
        ctx.registerAnnotatedClass(UUIDAdapter.class);
        // 如果用自定义Marshaller,就注册这个实例
        // ctx.registerMarshaller(new UUIDMarshaller());
        
        // 注册你的实体类(比如Bar)
        ctx.registerAnnotatedClass(Bar.class);
        
        // 配置缓存使用Protostream作为序列化方式
        ConfigurationBuilder configBuilder = new ConfigurationBuilder();
        configBuilder.encoding()
                .key().mediaType("application/x-protostream")
                .value().mediaType("application/x-protostream");
        
        // 定义需要的缓存
        manager.defineConfiguration("t1", configBuilder.build());
        manager.defineConfiguration("t2", configBuilder.build());
    }
}

3. 处理实体类中的UUID字段(比如Bar类)

现在你的Bar类可以直接用UUID字段了,注意必须提供公共无参构造方法——这是注解处理器的要求,也是你之前报错的原因之一:

import org.infinispan.protostream.annotations.ProtoDoc;
import org.infinispan.protostream.annotations.ProtoField;
import java.util.UUID;

@ProtoDoc("包含UUID字段的实体类Bar")
public class Bar {
    private UUID uuidField;
    private String otherField;

    // 必须要有无参构造,注解处理器要求
    public Bar() {}

    public Bar(UUID uuidField, String otherField) {
        this.uuidField = uuidField;
        this.otherField = otherField;
    }

    @ProtoField(number = 1) // 字段序号唯一即可
    public UUID getUuidField() {
        return uuidField;
    }

    public void setUuidField(UUID uuidField) {
        this.uuidField = uuidField;
    }

    @ProtoField(number = 2)
    public String getOtherField() {
        return otherField;
    }

    public void setOtherField(String otherField) {
        this.otherField = otherField;
    }
}

4. 把UUID用作缓存键

完成上面的配置后,你就可以像原来一样直接用UUID作为缓存键了:

Map<UUID, Foo> testUUIDAsKey = manager.getCache("t1");
testUUIDAsKey.put(UUID.randomUUID(), new Foo("测试值"));

// 读取操作也完全正常
Foo targetFoo = testUUIDAsKey.get(targetUuid);

额外注意事项

  • 确保缓存的编码配置使用application/x-protostream,这样键和值都会用Protostream序列化。
  • 如果用Maven/Gradle构建,要正确配置Protostream注解处理器,比如Maven中添加:
<plugin>
    <groupId>org.infinispan.protostream</groupId>
    <artifactId>protostream-processor</artifactId>
    <version>4.3.1.Final</version> <!-- 和Infinispan 10.1.3对应版本一致 -->
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
        </execution>
    </executions>
</plugin>

内容的提问来源于stack exchange,提问作者iXô

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:24:07