java.io.InvalidClassException:

时间:2011-08-24 09:43:26

标签: java serialization

InvalidClassException: local class incompatible: stream classdesc serialVersionUID = -196410440475012755, local class serialVersionUID = -6675950253085108747

我在以下场景中使用InvalidClassException进行结构化。在这里,我的EAR安装在4个Websphere App服务器中,并在此之间共享执行。有时我从POJO类得到异常InvalidClassException,它实现了Serializable接口。请对此有任何线索。我对此没有任何线索。

5 个答案:

答案 0 :(得分:32)

当您实现java.io.Serializable接口以使类可序列化时,编译器会查找类型为long的名为“serialVersionUID”的静态最终字段。如果类没有明确声明该字段,那么编译器将创建一个这样的字段并为其分配一个值,该值来自serialVersionUID的依赖于实现的计算。此计算取决于类的各个方面,并遵循Sun提供的对象序列化规范。但是,并不保证所有编译器实现的值都相同。

此值用于检查类与序列化的兼容性,这是在对已保存对象进行反序列化时完成的。 Serialization Runtime验证发送方类的serialVersionUID(用于保存流上对象的状态)和接收方类(用于恢复对象的类,可能在某些其他系统中)的serialVersionUID两者完全相同。如果接收器系统加载的类具有一些其他serialVersionUID而不是序列化过程中使用的类,那么我们会得到一个InvalidClassException。

NOTE-- 强烈建议您显式声明并初始化long类型的static,final字段,并在要使Serializable的所有类中命名为“serialVersionUID”,而不是依赖于此字段值的默认计算。这种计算非常敏感,并且可能因编译器实现而异,因此即使对于同一个类,您也可能因为在发送器和接收器端序列化过程中使用了不同的编译器实现而获得InvalidClassException。

在大多数情况下,您将仅对此字段使用“私有”访问说明符,因为声明通常仅适用于声明它的类,我们实际上不需要在子类中继承此字段或访问它来自外面。因此,几乎没有任何理由我们不应该将其保持为“私密”。

答案 1 :(得分:8)

当您尝试反序列化使用同一类的不兼容(通常更早)版本序列化的对象时,会出现该异常。

如果您未在实施serialVersionUID的班级中明确指定Serializable,则会根据班级的(非transient)字段生成一个值。这样做是为了确保不会恢复部分对象(最好是失败而不是盲目地继续使用可能已损坏的对象)。

在Web应用程序系统中,序列化的常见用途是用于会话:如果您将值放入会话中,则最终可能会将其序列化(用于群集支持或仅用于获取持久会话)。

所以要么要保持所有类在版本之间兼容,请确保不恢复它们不会破坏您的应用程序(即不以这种方式存储重要信息)。< / p>

答案 2 :(得分:2)

如果有人再次讨论EJB TimerTask这个问题 - 就像我刚刚做的那样 - 如果您使用的是WebSphere Application Server,这里有一个提示:

配置文件的bin文件夹中有2个批处理文件/ shell脚本,可以列出和删除EJB计时器任务。在我的情况下,我有一些计时器任务,使用不同的,过时的serialVersionUID序列化对象。我无法摆脱它们,因为序列化的对象确实发生了变化。所以我只是用了那些:

findEJBTimers.bat cancelEJBTimers.bat

您的计时器任务已经消失,错误消息也是如此。在我的情况下,这正是我所需要的,但很难得到这个信息。

答案 3 :(得分:0)

好的,所以我会问一个例子和我的作品:

Here is a list以及各种形式的PoJos序列化的性能指标

您必须判断性能和便利性的权衡。但是,因为我说'JSON&#39;作为序列化的一种手段,这里是一个简单的例子,不依赖于编译器。基本上,除非你在接收端更改了pojo的结构,否则在编译它的时间/方式/位置完全无关紧要(事实上,它甚至不必在2个JVM之间)。正如您从链接中看到的那样,JSON实际上是最慢的,而XML只是一个有效载荷猪。但是它们都具有得到普遍支持的决定性优势。 XML甚至允许应用样式表。

    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.3.1</version>
        <scope>test</scope>
    </dependency>

代码

  @Test
    public void testJSON() throws Exception {
        Foo expected = new Foo(1,"Christian",1000000.00d);
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String testJson = gson.toJson(expected);

        System.out.println(testJson);

        Foo result = gson.fromJson(testJson, Foo.class);
        assertEquals(expected,result);

    }

    public static class Foo {

        private String name;
        private Integer age;
        private Double paycheck;

        public Foo(Integer age, String name, Double paycheck) {
            this.age = age;
            this.name = name;
            this.paycheck = paycheck;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Foo foo = (Foo) o;

            if (age != null ? !age.equals(foo.age) : foo.age != null) return false;
            if (name != null ? !name.equals(foo.name) : foo.name != null) return false;
            if (paycheck != null ? !paycheck.equals(foo.paycheck) : foo.paycheck != null) return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = name != null ? name.hashCode() : 0;
            result = 31 * result + (age != null ? age.hashCode() : 0);
            result = 31 * result + (paycheck != null ? paycheck.hashCode() : 0);
            return result;
        }
    }

输出

{
  "name": "Christian",
  "age": 1,
  "paycheck": 1000000.0
}

答案 4 :(得分:0)

序列化一个对象时,serialVersionUID与其他内容一起序列化。

稍后将其反序列化时,将从反序列化的对象中提取serialVersionUID并将其与已加载类的serialVersionUID进行比较。

如果数字不匹配,则抛出InvalidClassException。