Dynamically overwriting methods prevents Serialization

A

alex

Hi,

I have the following problem:

I have a base class Foo

public class Foo implements Serializable {
public int a = 0;
public void setA() { a = 1;}
}

when I try to serialize the instance of the class I have no problem:

Foo of = new Foo();
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(of);

however, when I dynamically extend Foo I'm getting
NotSerializableException:

Foo of = new Foo() {
public void setA() { a = 2;}
};
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(of);

NotSerializableException thrown....

I'd appreciate any idea on how to solve this problem

Thanks,
-Alex
 
E

Eric Sosman

alex wrote On 10/10/05 15:00,:
Hi,

I have the following problem:

I have a base class Foo

public class Foo implements Serializable {
public int a = 0;
public void setA() { a = 1;}
}

when I try to serialize the instance of the class I have no problem:

Foo of = new Foo();
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(of);

however, when I dynamically extend Foo I'm getting
NotSerializableException:

Foo of = new Foo() {
public void setA() { a = 2;}
};
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(of);

NotSerializableException thrown....

I'd appreciate any idea on how to solve this problem

Works fine for me. Could you post your exact,
complete program source?
 
R

Roedy Green

Foo of = new Foo() {
public void setA() { a = 2;}
};
you have created a NEW anonymous class.

Apparently the Serializable is not inherited. You could check to see
if it is with ordinary subclasses.
 
R

Roedy Green

I'd appreciate any idea on how to solve this problem

Logically you SHOULD not be able to serialise an anonymous class. How
could the other end have access to the class description to
reconstitute it without a proper name?
 
L

Lasse Reichstein Nielsen

Roedy Green said:
Logically you SHOULD not be able to serialise an anonymous class. How
could the other end have access to the class description to
reconstitute it without a proper name?

Well, to the JVM, there is no such thing as an anonymous class. It
will have a name like "OuterClass$1", and if the outer class is
available to the other end, it's highly likely that nested classes are
too.

The problem is more likely to be that the outer class is not
serializable. An anonymous class is an inner class, so it contains a
reference to the outer instance, which will then be serialized too ...
or try and fail, as it might be.

/L
 
L

Lasse Reichstein Nielsen

Roedy Green said:
Apparently the Serializable is not inherited. You could check to see
if it is with ordinary subclasses.

Serializable is just an (empty) interface, so it is inherited. It's
also easily checkable by adding an
if (of instanceof Serializable) { // do something }

/L
 
R

Roedy Green

Well, to the JVM, there is no such thing as an anonymous class. It
will have a name like "OuterClass$1", and if the outer class is
available to the other end, it's highly likely that nested classes are
too.

I was thinking if the other end compiled the same code the anonymous
inner classes would not necessarily get the same names, but presumably
those numbers are not arbitrarily assigned.
..
And of course the class names are not stable. If you add new anonymous
classes, everything would get renumbered, so your datastreams are not
very persistent if you let them contain anonymous inner classes, and
you could expect some very strange behaviour if you had added a new
anonymous class and tried to restore old data.
 
A

alex

Lasse, You are right - outer class is not serializable. So far the
only work around I found is to create this new class in static method.
Is there a more generic method to serialize an object by stepping over
the outer class reference?
Thanks
-Alex
 
T

Thomas Hawtin

Roedy said:
I was thinking if the other end compiled the same code the anonymous
inner classes would not necessarily get the same names, but presumably
those numbers are not arbitrarily assigned.

JLS3 tightens the rules for binary names of inner classes (section 13.1,
p335). However, there is no standard for assigning the "non-empty
sequence of digits". Perhaps a better technique than the count, is to
use the serialisation version UID.
And of course the class names are not stable. If you add new anonymous
classes, everything would get renumbered, so your datastreams are not
very persistent if you let them contain anonymous inner classes, and
you could expect some very strange behaviour if you had added a new
anonymous class and tried to restore old data.

Which is why the serialisation spec says that you shouldn't serialise
anonymous inner classes, apparently.

I don't think anything is done to prevent serialisation of anonymous
inner classes, but the exception should state which class failed. My
money is on the outer class.

Tom Hawtin
 
L

Lasse Reichstein Nielsen

alex said:
outer class is not serializable. So far the only work around I found
is to create this new class in static method.
Is there a more generic method to serialize an object by stepping over
the outer class reference?

Your problem is that your class is an inner class. There are
essentially two ways to avoid that (and I'm probably forgetting some):
- create the anonymous class in a static context instead of in the
scope of an instance (what you do with a static method)
- Declare the class statically somewhere else, instead of as an anonymous
class where you use it.

I prefer to the latter, because it makes everything explicit, instead
of depending on whether a method unrelated to the problem is static or not.

/L
 
R

Roedy Green

- create the anonymous class in a static context instead of in the
scope of an instance (what you do with a static method)

I never realised you could do that. So you would put it in static {
..... } or inside a static method?
 
L

Lasse Reichstein Nielsen

Roedy Green said:
I never realised you could do that. So you would put it in static {
.... } or inside a static method?

Neither did I, and the JLS even states that an anonymous class is always
inner and never static.
<URL:http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#252986>
But that doesn't prevent it from not having an eclising instance
<URL:http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.9.2>

It appears to work either way:
---
class Foo {
private static int foo = 42;
static { // static block context
int tmp = new Callable<Integer>() {
public Integer call() {
return foo;
}
}.call();
System.out.println(tmp);
}
private static void test() { // static method context
new Runnable(){
public void run() {
System.out.println(foo);
}
}.run();
}
public static void main(String[] args) {
test();
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top