Class not serializable after methods are overridden

梦想的初衷 提交于 2019-12-31 02:44:04

问题


I override a createSocket() method in my test cases to pas in a mocked Socket. After doing this the objects aren't serializable anymore.

Here's a example of what doesn't work.

Foo.java

import java.io.Serializable;

public class Foo implements Serializable {
    private static final long serialVersionUID = 3109852436898487119L;

    public void bar() {
        System.out.println("Foo");
    }
}

FooTest.java

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

import junit.framework.TestCase;

import org.junit.Test;

public class FooTest extends TestCase {

    // this passes
    @Test
    public void testFooIsSerializable() throws IOException {
        Foo foo = new Foo();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(baos);
        out.writeObject(foo);
    }

    // this throws a java.io.NotSerializableException
    @Test
    public void testFooIsStillSerializableAfterBarIsOverridden()
            throws IOException {

        // Eclipse gives me the warning "The serializable class  does not declare a static final serialVersionUID field of type long"
        // Adding it doesn't help
        Foo foo = new Foo() {
            @Override
            public void bar() {
                System.out.println("Bar");
            }
        };

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(baos);
        out.writeObject(foo);
    }
}

The stack trace when running FooTest with JUnit:

java.io.NotSerializableException: FooTest
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
    at FooTest.testFooIsStillSerializableAfterBarIsOverridden(FooTest.java:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at junit.framework.TestCase.runTest(TestCase.java:168)
    at junit.framework.TestCase.runBare(TestCase.java:134)
    at junit.framework.TestResult$1.protect(TestResult.java:110)
    at junit.framework.TestResult.runProtected(TestResult.java:128)
    at junit.framework.TestResult.run(TestResult.java:113)
    at junit.framework.TestCase.run(TestCase.java:124)
    at junit.framework.TestSuite.runTest(TestSuite.java:232)
    at junit.framework.TestSuite.run(TestSuite.java:227)
    at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

What is the problem with this? I have to admit, that I didn't dive too deep into Java's Serializable interface and more or less just followed Eclipse's quick fixes.

To be more specific to my implementation:

I have a class that should send an instance of itself via a ObjectOutputStream.

Is this a fundamentally wrong approach?


回答1:


The problem is you have an anonymous inner class, which by definition contains a (compiler-generated) reference to the instance of the outer class (FooTest) which created it. Since serialization by default includes all members of the object, the runtime tries to serialize the FooTest object too - and that is not serializable (as it was not meant to be). This is attested by the error message:

java.io.NotSerializableException: FooTest

Thus if you turn your anonymous class into an explicit static inner class, the problem should go away.




回答2:


Just declare a serialVersionUID if you want to serialize/deserialize:

   Foo foo = new Foo() {
     static final serialVersionUID = 348723598723589723L;
        @Override
        public void bar() {
            System.out.println("Bar");
        }
   };



回答3:


After doing this the objects aren't serializable anymore.

You don't have any evidence of that. All you have is an Eclipse warning. What happens when you execute?




回答4:


You are creating a new annyonymous inner class that extends Foo by overriding its bar method. This newly created class does not implement the Serializable interface, and thus cannot be serialized.

EDIT:
Your subclass is withing FooTest, so this class with its inner classes are serialized. This is why FooTest would have to be serializable!



来源:https://stackoverflow.com/questions/6662529/class-not-serializable-after-methods-are-overridden

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!