问题
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