java.io.InvalidClassException: <className>; incompatible types for field <fieldName> 异常追踪
异常信息
后台日志中产生了如下异常信息:
java.io.InvalidClassException: <className>; incompatible types for field <fieldName>
at java.io.ObjectStreamClass.matchFields(ObjectStreamClass.java:2299) ~[?:1.8.0_74]
at java.io.ObjectStreamClass.getReflector(ObjectStreamClass.java:2193) ~[?:1.8.0_74]
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:669) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1707) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1345) ~[?:1.8.0_74]
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) ~[?:1.8.0_74]
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) ~[?:1.8.0_74]
涉及到OutputInputStream.readObject,因此猜测是对象反序列化时,而产生的问题。
异常来源
private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
ObjectStreamClass localDesc)
throws InvalidClassException{
// ...
for (int j = 0; j < localFields.length; j++) {
ObjectStreamField lf = localFields[j];
if (f.getName().equals(lf.getName())) {
if ((f.isPrimitive() || lf.isPrimitive()) &&
f.getTypeCode() != lf.getTypeCode())
{
throw new InvalidClassException(localDesc.name,
"incompatible types for field " + f.getName());
}
if (lf.getField() != null) {
m = new ObjectStreamField(
lf.getField(), lf.isUnshared(), false);
} else {
m = new ObjectStreamField(
lf.getName(), lf.getSignature(), lf.isUnshared());
}
}
}
// ...
}
异常重现
import java.io.Serializable;
public class Request implements Serializable {
private static final long serialVersionUID = 3663364724485038109L;
public Integer status;
public Integer addressStatus;
// setter getter
}
序列化Request对象
public class Serialization {
public static void main(String[] args) throws IOException, ClassNotFoundException{
Request r1 = new Request();
r1.setAddressStatus(100);
r1.setStatus(200);
Request r2 = new Request();
r2.setAddressStatus(300);
r2.setStatus(400);
File file = new File("D:/MySQL/workspace/spring/resources/request.ser");
serializable(file, r1, r2);
Request[] rs = deserializable(file);
for (Request request : rs)
System.out.println(request.getAddressStatus() + " " + request.getStatus());
}
public static void serializable(File file, Request... requests) throws IOException {
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(file));
if (requests != null)
stream.writeObject(requests);
stream.close();
}
public static Request[] deserializable(File file) throws IOException, ClassNotFoundException {
ObjectInputStream stream = new ObjectInputStream(new FileInputStream(file));
Request[] requests = (Request[])stream.readObject();
stream.close();
return requests;
}
}
修改Request作用域类型
import java.io.Serializable;
public class Request implements Serializable {
private static final long serialVersionUID = 3663364724485038109L;
public int status;
public int addressStatus;
// setter getter
}
反序列化对象
public class Serialization {
public static void main(String[] args) throws IOException, ClassNotFoundException{
Request r1 = new Request();
r1.setAddressStatus(100);
r1.setStatus(200);
Request r2 = new Request();
r2.setAddressStatus(300);
r2.setStatus(400);
File file = new File("D:/MySQL/workspace/spring/resources/request.ser");
Request[] rs = deserializable(file);
for (Request request : rs)
System.out.println(request.getAddressStatus() + " " + request.getStatus());
}
public static void serializable(File file, Request... requests) throws IOException {
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(file));
if (requests != null)
stream.writeObject(requests);
stream.close();
}
public static Request[] deserializable(File file) throws IOException, ClassNotFoundException {
ObjectInputStream stream = new ObjectInputStream(new FileInputStream(file));
Request[] requests = (Request[])stream.readObject();
stream.close();
return requests;
}
}
将会抛出如下异常
Exception in thread "main" java.io.InvalidClassException: com.spring.domain.Request; incompatible types for field addressStatus
at java.io.ObjectStreamClass.matchFields(ObjectStreamClass.java:2399)
at java.io.ObjectStreamClass.getReflector(ObjectStreamClass.java:2293)
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:741)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1876)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1966)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1561)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at com.spring.domain.Serialization.deserializable(Serialization.java:38)
at com.spring.domain.Serialization.main(Serialization.java:24)
调试分析,可知反序列化类型为int和对象的序列化类型为Integer, 因此产生异常。
总结
项目中使用了Spring httpinvoker 远程服务。客户端与服务端使用一套服务接口,而接口的具体实现是在服务端。
客户端调用远程方法时,会序列化要调用的(接口)方法和参数,发送到服务端。
服务端会根据请求反序列化还原,调用具体方法获取结果,并将结果序列化发给客户端。
客户端接收响应,将服务端结果反序列化还原。
而如果客户端与服务端代码的版本不一致,就会产生该异常。