Gor*_*onM 2 java generics serialization network-programming
我有一个使用泛型和对象序列化的简单服务器.(T是输入格式,U是输出格式).仅处理输入的简化版本如下所示:
public class Server <T, U> implements Runnable {
@override
public void run () {
try (ObjectInputStream inReader = new ObjectInputStream (this.connection.getInputStream ())) {
T lastObj;
while (true) {
lastObj = (T) inReader.readObject ();
System.out.println (lastObj.getClass ().getName ());
if (null != lastObj) {
this.acceptMessage (lastObj);
}
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger (this.getClass ().getName ()).log (Level.SEVERE, ex.getMessage (), ex);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果我启动服务器
Server <Integer, String> thisServer = new Server ();
Run Code Online (Sandbox Code Playgroud)
那么我希望它只接受Integer对象并返回Strings作为输出.
但是,我使用的是从System.in读取的简单客户端,用于测试和发送字符串到服务器.令我惊讶的是,服务器接受了输入.只是为了确保它真的接受了一个非TI类型的对象,添加了一行来回显出最后一个对象是什么类.
System.out.println (lastObj.getClass ().getName ());
Run Code Online (Sandbox Code Playgroud)
这确实输出了Java.lang.String.
这完全出乎意料.我认为Generics应该允许你传递类本身没有指定的类型的对象,而不必抛出对象?对T的演员似乎也没有效果.
这意味着理论上我可以通过提供它不期望的类型的Java对象来攻击服务器(或其消费者).虽然这不一定非常强大(因为它是一个学术项目,而不是生产软件),但我想知道你用readObject获得的对象不是你想要的那个,所以你可以处理它很重要.
我尝试添加以下内容,但它被标记为编译时错误.
if (lastObj instanceof T) {
}
Run Code Online (Sandbox Code Playgroud)
我该如何正确处理?
正如其他人所指出的,这个问题与类型擦除有关.在运行时,T已被删除到其上限,Object.
当你强制转换时T,它被称为未经检查的强制转换,因为它在运行时不存在.相反,编译器在其中将实例T分配回到类似的实例类型的位置插入了其他强制类型转换Integer.当run消耗类似的意外类型时String,JVM无法区分它,并且它不会快速失败.如果有方法T getLastObject,则该方法的调用方可能会失败:
Server<Integer, String> thisServer = ...;
thisServer.run(); // consumes a String, but doesn't fail
Integer i = thisServer.getLastObject(); // ClassCastException thrown here
Run Code Online (Sandbox Code Playgroud)
解决方法是提供Server一个Class<T>表示要使用的对象类型的对象并使用该cast方法:
public class Server <T, U> implements Runnable {
private final Class<T> readObjectType;
public Server(final Class<T> readObjectType) {
this.readObjectType = readObjectType;
}
@Override
public void run () {
try (ObjectInputStream inReader = new ObjectInputStream (this.connection.getInputStream ())) {
T lastObj;
while (true) {
lastObj = readObjectType.cast(inReader.readObject());
System.out.println (lastObj.getClass ().getName ());
if (null != lastObj) {
this.acceptMessage (lastObj);
}
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger (this.getClass ().getName ()).log (Level.SEVERE, ex.getMessage (), ex);
}
}
}
Run Code Online (Sandbox Code Playgroud)
readObjectType.cast(inReader.readObject()) 现在,当读取错误类型的对象时,它将快速失败.
| 归档时间: |
|
| 查看次数: |
2084 次 |
| 最近记录: |