InvalidClassException:<class>;字段<fieldname> </fieldname> </class>的不兼容类型

时间:2011-07-27 10:32:18

标签: java serialization 64-bit rmi

在从一个VM到另一个VM进行轮询RMI调用时,我遇到了一些零星的异常。 类路径在VM之间看起来是一致的。我使用64位java - jres是一致的(jdk / v1.6.0_23-64bit)。 虚拟机之间的-XX:+UseCompressedOops flag & -XX:+UseConcMarkSweepGC存在不一致,但我不知道这两者是否可能是根本原因?

呼叫(客户端)虚拟机已设置-XX:+UseCompressedOops & -XX:+UseConcMarkSweepGC,而 getStatistics()调用的服务器虚拟机没有设置。

值得注意的一点: -

  1. 遇到异常后,之间的后续调用相同 VM在一段时间内都可以正常运行 - 即无效的ClassException 是一个短暂的问题。

  2. [class]和[fieldname]每次都有所不同 在异常的情况下遇到异常 java.io.InvalidClassException:[class];不兼容的类型 字段[fieldname]

  3. 从具有-XX:+UseCompressedOops 64位 VM到另一个未设置为使用压缩oops的64位VM进行RMI调用(序列化)是否有任何问题?

    筹码:

    java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
        java.io.InvalidClassException: testserver.cluster.Status; incompatible types for field committed
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
        at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
        at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
        at $Proxy14.getStatistics(Unknown Source)
        at testserver.rm.RM$Check.run(RM.java:1593)
    Caused by: java.io.InvalidClassException: testserver.cluster.Status; incompatible types for field committed
        at java.io.ObjectStreamClass.matchFields(ObjectStreamClass.java:2210)
        at java.io.ObjectStreamClass.getReflector(ObjectStreamClass.java:2105)
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:602)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
        at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
        at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:155)
        ... 4 more
    

    感谢您的帮助

4 个答案:

答案 0 :(得分:0)

Hmmh。是否可以通过附加的调试器重现这种情况?在ObjectStreamClass中的throw处有一个断点,抛出异常:

if ((f.isPrimitive() || lf.isPrimitive())
        && f.getTypeCode() != lf.getTypeCode()) {
    throw new InvalidClassException(localDesc.name,
        "incompatible types for field "
                    + f.getName());
}

抛出异常时,您至少可以检查getTypeCode返回值。我知道,这不是解决方案,但可能会提供一些线索/更多细节,以包含在可能的错误报告中。

答案 1 :(得分:0)

此选项(-XX:+ UseCompressedOops)默认为您正在使用的VM启用,如果不是,我建议您禁用它并尝试使用它。

可能是您正在使用的JRE更新中的错误,您可以在Oracle论坛中使用它。

答案 2 :(得分:0)

首先注意-XX:+ UseCompressedOops默认设置为6u23版本,即使您没有明确禁用它。

此外,此选项仅影响指向RAM内存的指针的内部表示,不会在序列化对象中进行编码,因此它不得影响RMI调用。

我敢打赌这个问题与在内存中动态创建的一些字节码有关,因为某些原因在第一次反序列化时尚未提供。这可能是像Hibernate这样的库和其他用新的自定义字节码包装原始类的情况。

答案 3 :(得分:0)

可以肯定的是,两个虚拟机中的类共享同一个类的编译版本? 您可以尝试重新编译并向两个VM添加相同的jar。

我希望这已经得到了照顾。