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

Spring Boot集成GemFire时如何反序列化无无参构造的com.auth0.jwk.Jwk

错误根因

你给Key类添加的@PersistenceConstructor仅作用于Key自身的实例化,本次报错的根源是嵌套属性com.auth0.jwk.Jwk类本身没有无参构造函数,GemFire默认的序列化机制反序列化Jwk实例时,找不到可用的构造函数,因此抛出异常。


可行解决方案

方案一:自定义GemFire序列化器(推荐,业务代码侵入最小)

为Jwk类单独注册自定义的序列化/反序列化器,利用Jwk本身提供的toMap、fromMap公开API完成转换即可,步骤如下:

  1. 实现org.apache.geode.serialization.Serializer接口,编写自定义序列化逻辑:
import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.geode.serialization.Serializer;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Map;

public class JwkSerializer implements Serializer<Jwk> {
    private final ObjectMapper objectMapper = new ObjectMapper();

    // 自定义唯一ID,取值范围在65536以上即可,避免和内置序列化器冲突
    @Override
    public int getId() {
        return 100001;
    }

    @Override
    public Class<Jwk> getSupportedClass() {
        return Jwk.class;
    }

    @Override
    public void serialize(Jwk jwk, DataOutput out) throws IOException {
        // 将Jwk转为JSON字符串写出
        Map<String, Object> jwkMap = jwk.toMap();
        out.writeUTF(objectMapper.writeValueAsString(jwkMap));
    }

    @Override
    public Jwk deserialize(DataInput in) throws IOException {
        // 读取JSON字符串转成Jwk实例
        String jwkJson = in.readUTF();
        Map<String, Object> jwkMap = objectMapper.readValue(jwkJson, new TypeReference<Map<String, Object>>() {});
        try {
            return Jwk.fromMap(jwkMap);
        } catch (JwkException e) {
            throw new IOException("Jwk反序列化失败", e);
        }
    }
}
  1. 在Spring Boot配置中注册序列化器,在application.properties添加如下配置即可:
spring.data.gemfire.cache.serialization.serializers=替换为你自己的包路径.JwkSerializer

方案二:调整缓存存储结构(无需修改GemFire配置,适合快速验证)

把Jwk属性转为JSON字符串存储,读取后手动转回Jwk实例,修改Key类定义即可:

import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.annotation.Id;
import org.springframework.data.gemfire.mapping.annotation.Region;
import java.util.Map;

@Region("jwks")
public class Key {
    @Id
    private String id;
    // 存储JSON字符串,参与序列化
    private String jwkStr;
    // 业务层用的临时字段,不参与序列化
    private transient Jwk jwk;
    private final ObjectMapper objectMapper = new ObjectMapper();

    @PersistenceConstructor
    public Key(String id, String jwkStr){
        this.id = id;
        this.jwkStr = jwkStr;
    }

    // 业务层构造对象用的构造函数
    public Key(String id, Jwk jwk) throws JwkException {
        this.id = id;
        this.jwk = jwk;
        this.jwkStr = objectMapper.writeValueAsString(jwk.toMap());
    }

    public Jwk getJwk() {
        if (jwk == null && jwkStr != null) {
            try {
                Map<String, Object> jwkMap = objectMapper.readValue(jwkStr, new TypeReference<Map<String, Object>>() {});
                this.jwk = Jwk.fromMap(jwkMap);
            } catch (Exception e) {
                throw new RuntimeException("Jwk转换失败", e);
            }
        }
        return jwk;
    }

    // 其他Getter和Setter方法
}

方案三:启用PDX序列化并注册自定义实例化器

使用GemFire原生PDX序列化机制,为Jwk类配置自定义实例化逻辑,步骤如下:

  1. 首先在配置类开启PDX序列化并注册实例化器:
import com.auth0.jwk.Jwk;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.ReflectionBasedPdxSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.config.annotation.EnablePdx;

@Configuration
@EnablePdx(readSerialized = true)
public class GemfireConfig {
    @Bean
    public PdxSerializer pdxSerializer() {
        ReflectionBasedPdxSerializer serializer = new ReflectionBasedPdxSerializer();
        // 注册Jwk的自定义实例化逻辑
        serializer.setInstanceCreator(Jwk.class, (PdxInstance pdxInstance) -> {
            try {
                Map<String, Object> jwkMap = (Map<String, Object>) pdxInstance.getField("modifiableMap");
                return Jwk.fromMap(jwkMap);
            } catch (Exception e) {
                throw new RuntimeException("Jwk实例化失败", e);
            }
        });
        return serializer;
    }
}

内容的提问来源于stack exchange,提问作者Vaishnavi Killekar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 11:18:00