Open GoogleCodeExporter opened 9 years ago
Original comment by crazybob...@gmail.com
on 14 Feb 2007 at 7:13
I think I have a possible strategy for the fix, but its tricky.
Suppose the intercepted class looks like this:
class Foo implements Serializable {
private final String a;
private final long createdTime;
private boolean haveIBeenSerialized;
@Inject public Foo(String a) {
this.a = a;
this.b = System.currentTimeMillis();
}
public void bar() {
System.out.println(a);
}
}
Then the Guice generated AOP class looks approximately like this. This is my
speculation, I'm not actually
familiar with the implementation:
class Foo$EnhancedByGuice extends Foo {
Interceptors interceptors;
Foo$EnhancedByGuice(String a) {
super(a);
}
@Override public void bar() {
interceptors.intercept(...);
}
}
The problem is that it's very unlikely that the other end is going to have a
class like Foo$EnhancedByGuice.
Basically, serializing generated classes is about as unreliable as it gets. So
what we want to do kind of might
look approximately like this:
class SerializedInterceptable<T> implements Serializable {
T base;
Interceptors interceptors;
public SerializedInterceptable(T base, Interceptors interceptors) { ... }
public void readResolve() {
Foo$EnhancedByGuice enhanced = asSubclass(Foo$EnhancedByGuice.class, base);
enhanced.interceptors = interceptors;
return enhanced;
}
}
class Foo$EnhancedByGuice extends Foo {
...
public Object writeReplace() {
Foo baseFoo = removeSubclass(this);
return new SerializedInterceptable(baseFoo, interceptors);
}
}
Of course, the removeSuperclass() and asSubclass() methods need to do something
quite magical. They need
to reflectively turn a Foo$EnhancedByGuice into the corresponding Foo and vice
versa. I suspect this will need
Sun's Unsafe class, since we must not invoke the Foo constructor a second time
(it could have side effects).
One requirement is that we must use the user's provided Foo.writeReplace() and
Foo.readResolve() methods.
This opens the door to the user type changing from say Foo to Bar during
serialization. Another trick is that
we don't have any idea of what Foo will look like upon deserialization. In
particular, it may have a completely
different set of methods. I suspect the best heuristic to solve these problems
will be to re-run the matchers
post-serialization. So any newly-added methods will be intercepted if they
match the initial criteria.
One way to get around Unsafe would be to get Java's serialization to do the
unsafe stuff for us. Perhaps a
clever implementation of asSubclass() could create a byte[] that looked like
just the Foo-parts of the class.
We'd get reflection to do the unsafety for us. Whichever way we go we're going
to need to try to conserve
complexity!
Original comment by limpbizkit
on 30 May 2008 at 4:22
I talked to Bob about this. We're not going to implement this since it has
dangerous consequences, especially if it
were to work "transparently".
* - serializing interceptors is dangerous (they require heavyweight
configuration, like transaction managers,
which aren't serializable in general)
* - not serializing interceptors is dangerous (transaction management shouldn't
disappear upon serialization)
Original comment by limpbizkit
on 3 Jun 2008 at 9:39
Turns out it isn't too difficult to implement removeSuperclass() and
asSubclass() using reflection and
serialization. You'll need this tip:
http://sixlegs.com/blog/java/skipping-constructors.html
Original comment by limpbizkit
on 4 Jun 2008 at 12:29
Original issue reported on code.google.com by
crazybob...@gmail.com
on 14 Feb 2007 at 7:13