Spring Boot集成GemFire时如何反序列化无无参构造的com.auth0.jwk.Jwk
错误根因
你给Key类添加的@PersistenceConstructor仅作用于Key自身的实例化,本次报错的根源是嵌套属性com.auth0.jwk.Jwk类本身没有无参构造函数,GemFire默认的序列化机制反序列化Jwk实例时,找不到可用的构造函数,因此抛出异常。
可行解决方案
方案一:自定义GemFire序列化器(推荐,业务代码侵入最小)
为Jwk类单独注册自定义的序列化/反序列化器,利用Jwk本身提供的toMap、fromMap公开API完成转换即可,步骤如下:
- 实现
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); } } }
- 在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类配置自定义实例化逻辑,步骤如下:
- 首先在配置类开启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
相关产品推荐
相关产品推荐

