我有两个简单的应用程序:客户端和服务器。客户端加密(简单AES)自定义对象,然后通过TCP套接字将其作为字节发送到服务器。服务器解密这些字节并调用重新创建此对象的方法,如下所示:
private static Object getObjectFromBytes(byte[] credentials) throws IOException, ClassNotFoundException{
ByteArrayInputStream bis = new ByteArrayInputStream(credentials);
ObjectInput in = null;
Object credentialsObj = null;
try {
in = new ObjectInputStream(bis);
credentialsObj = in.readObject();
} finally {
bis.close();
in.close();
}
return credentialsObj;
}
在客户端,当我加密该对象时,它的类型为mds.hm5.client.ITU_Credentials
。在服务器端,当我解密它并转换回对象时,它应该是mds.hm5.tokenservice.ITU_Credentials
。相反,我得到以下异常:
java.lang.ClassNotFoundException: mds.hm5.client.ITU_Credentials
他正在通过旧的类路径查找此对象。为什么会发生,该如何解决?
其他信息:
这是在客户端将对象转换为字节数组的方式:
private static byte[] getBytesFromObject(Object credentials) throws IOException{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
byte[] newBytes = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(credentials);
newBytes = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
out.close();
bos.close();
}
return newBytes;
}
之所以使用通用类型Object
,是因为我要使用这些方法来转换/加密/解密多种类型。这是正确的方法吗?
在客户端上,当我加密该对象时,它的类型为mds.hm5.client.ITU_Credentials。
所以这就是序列化流中的内容。
在服务器端,当我解密它并转换回对象时,它应该是mds.hm5.tokenservice.ITU_Credentials。
不,不应该。它应该与序列化时的相同[除非您采取了某些魔术步骤,但显然没有。没有这些魔术步骤,就没有魔术,也就没有将mds.hm5.client.ITU_Credentials
与mds.hm5.tokenservice.ITU_Credentials
连接起来的任何方法。您有两个具有相同名称和包的不同类,每个位置一个。他们不一样。
他正在通过旧的类路径查找此对象。
您在CLASSPATH和程序包名称之间感到困惑。他们不是同一回事。它正在通过其实际的程序包名称。查找该对象,它还能做什么?
对象输出流不会序列化类本身,而只会序列化其状态(字段值)。接收者需要在其类路径上的类文件。
也可以转让课程。您必须找到(或编写)可以从您的连接中加载类的类加载器。如果您的类文件具有URL,则可以使用URLClassloader。然后,您不必将类添加到您的类路径中。
您的客户需要在其类路径中包含定义该对象的.class文件。您正在执行的是序列化/反序列化实例,而不是类。
后,但将来可能对某人有用:我想在客户端发送其包为entities的对象Message,但是在服务器端,此[[Message类未嵌套在entities包中,因此引发异常。可能是愚蠢的,但我花了很多时间才弄清楚。