我用的是这个回购的例子https://github.com/kojenov/serial/tree/master/3-4.%20upload,它提供了一种方法,通过定义一个自定义objectinputstream并重写一个受保护的方法resolveclass,在这个方法中,我们必须指定哪些类允许反序列化,从而指定一种在java中防止不安全反序列化的方法。我的问题是,我在planet类中添加了一个localdate字段,当我反序列化序列化对象时,会出现以下异常:
除不支持的类以外的类无效;java.time.ser文件
我在网上搜索,却找不到其他遇到这个问题的人,所以我真的很困惑。我尝试用而不是localdate添加localdatetime,同样的错误再次发生。据我所知,java.time.ser类是该包中类层次结构中某个受保护的类。localdate类是可序列化的,因此不应发生这种情况。我确信问题出在localdate中,因为如果我使该字段按预期工作,那么 transient 代码就会正常工作。我是遗漏了什么还是仅仅是java对象序列化的一个bug?顺便说一句,这些例子最初来自阿列克谢·科耶诺夫(alexei kojenov)的一次演讲,他的网站是kojenov.com,但我找不到他的电子邮件亲自询问他。
1条答案
按热度按时间e1xvtsh31#
序列化是一种递归过程,这意味着在序列化复杂对象时,首先需要序列化其所有属性。反序列化也会发生同样的情况。
Planet
对象包含类型为的字段int
,double
以及java.lang.String
它们是原语,不需要特殊的(反)序列化。LocalDate
或者LocalDateTime
不是原语,它们被序列化然后反序列化SafeObjectInputStream
.序列化黑客
正如书中所说
java.io.Serializable
对象可以修改它们的序列化行为,甚至通过定义方法将序列化委托给另一个类writeReplace
.javadoc引用:
在将对象写入流时,需要指定备用对象的可序列化类应使用精确签名实现此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
如果存在此writereplace方法,并且可以从正在序列化的对象的类中定义的方法访问它,则序列化将调用此writereplace方法。因此,该方法可以具有私有、受保护和包私有访问。对这个方法的子类访问遵循java可访问性规则。两者
LocalDate
以及LocalDateTime
利用这种可能性并定义writeReplace
方法。举个例子,
java.time.LocalDate
的实现:@Override
protected Class<?> resolveClass(ObjectStreamClass input)
throws IOException, ClassNotFoundException
{
if (!input.getName().equals(Planet.class.getName())) {
throw new InvalidClassException("Unsupported class", input.getName());
}
return super.resolveClass(input);
}
public class SafeObjectInputStream extends ObjectInputStream {
private final List supportedClasses = List.of(Planet.class.getName(), "java.time.Ser");
public SafeObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}
@Override
protected Class<?> resolveClass(ObjectStreamClass input)
throws IOException, ClassNotFoundException
{
if (!supportedClasses.contains(input.getName())) {
throw new InvalidClassException("Unsupported class ", input.getName());
}
return super.resolveClass(input);
}
}