使用Kryo 5.6.0序列化注册类时遇UnmodifiableMap不可见问题求助
问题描述
使用Kryo 5.6.0 + Java 1.8,启用类注册序列化时触发如下异常:
com.esotericsoftware.kryo.KryoException: java.lang.IllegalArgumentException: Class is not registered: java.util.Collections$UnmodifiableMap
系统提示需执行kryo.register(java.util.Collections.UnmodifiableMap.class)注册该类,但UnmodifiableMap是Java包私有内部类,直接引用会报ClassNotFoundException。相关代码如下:
TestClass 代码
public class TestClass implements Serializable { private static final long serialVersionUID = 6400867639765519428L; private List<Books> items; public TestClass(List<Books> items) { super(); if (items != null) { for (Book item : items) { // 注:此处存在类型不匹配,参数为List<Books>,循环变量应为Books item.setOwner(this); } this.items = Collections.unmodifiableList(items); } } public List<Books> getItems() { return items; } }
Kryo 配置代码
public class HelloKryo { public static void main (String[] args) throws Exception { Kryo kryo = new Kryo(); kryo.register(TestClass.class); kryo.register(Books.class); kryo.register(List.class); Output output = new Output(); kryo.writeClassAndObject(output, object); // 注:object变量未定义,需替换为实际TestClass实例 byte[] result = output.toBytes(); } }
解决方案
方法1:通过实例获取内部类并注册对应序列化器
由于UnmodifiableMap/UnmodifiableList是包私有内部类,无法直接通过类名引用,可通过创建临时实例获取其Class对象,再注册Kryo的内置序列化器:
Kryo kryo = new Kryo(); kryo.setRegistrationRequired(true); // 注册业务类和底层集合类 kryo.register(TestClass.class); kryo.register(Books.class); kryo.register(ArrayList.class); kryo.register(HashMap.class); // 获取不可修改集合的Class对象并注册序列化器 Class<?> unmodifiableListClass = Collections.unmodifiableList(new ArrayList<>()).getClass(); kryo.register(unmodifiableListClass, new CollectionSerializer()); Class<?> unmodifiableMapClass = Collections.unmodifiableMap(new HashMap<>()).getClass(); kryo.register(unmodifiableMapClass, new MapSerializer()); // 后续序列化逻辑 TestClass object = new TestClass(new ArrayList<>()); Output output = new Output(); kryo.writeClassAndObject(output, object); byte[] result = output.toBytes();
方法2:关闭强制注册(快速解决)
如果业务允许放宽序列化安全性,可关闭Kryo的强制注册要求,让其自动处理未注册的内部类:
Kryo kryo = new Kryo(); // 关闭强制注册,允许Kryo自动处理未注册类 kryo.setRegistrationRequired(false); kryo.register(TestClass.class); kryo.register(Books.class); // 后续序列化逻辑 TestClass object = new TestClass(new ArrayList<>()); Output output = new Output(); kryo.writeClassAndObject(output, object); byte[] result = output.toBytes();
方法3:自定义序列化器转换集合类型
在序列化时将不可修改集合转为普通集合,反序列化后再恢复为不可修改集合,避免直接处理内部类:
Kryo kryo = new Kryo(); kryo.setRegistrationRequired(true); // 注册业务类和普通集合类,自定义TestClass序列化逻辑 kryo.register(TestClass.class, new Serializer<TestClass>() { @Override public void write(Kryo kryo, Output output, TestClass object) { // 序列化时将不可修改列表转为ArrayList kryo.writeObject(output, new ArrayList<>(object.getItems())); } @Override public TestClass read(Kryo kryo, Input input, Class<TestClass> type) { // 反序列化后通过构造方法自动转为不可修改列表 List<Books> items = kryo.readObject(input, ArrayList.class); return new TestClass(items); } }); kryo.register(Books.class); kryo.register(ArrayList.class); // 后续序列化逻辑 TestClass object = new TestClass(new ArrayList<>()); Output output = new Output(); kryo.writeClassAndObject(output, object); byte[] result = output.toBytes();
内容的提问来源于stack exchange,提问作者user25743358
相关产品推荐
相关产品推荐

