Hey all.
I've been working on
https://issues.jboss.org/browse/WELD-1162
and need your opinion.
Say we have:
public interface Foo<T> {
void doSomething(T t);
}
public interface StringFoo extends Foo<String> {}
public class StringFooImpl implements StringFoo {}
and
@Inject StringFoo stringFoo;
The proxy created by Weld is a subclass of StringFooImpl and
therefore has two declared methods:
void doSomething(Object o) { doSomething((String) o); }
void doSomething(String) {...}
However, when StringFooImpl is a session bean, with
StringFoo as its local interface, the proxy is a subclass of
Object and therefore the proxy only has the following
declared method:
void doSomething(Object o);
In both cases, when a client invokes
stringFoo.doSomething("foo"), the method doSomething(Object)
is invoked. But there's a difference in what happens next:
- In the non-ejb version, the bridge method then
immediately invokes doSomething(String) and only then is
the proxy's method handler invoked. The handler is
therefore dealing with the method doSomething(String)
- in the EJB version, doSomething(Object) is not a
bridge method, and so the method handler is invoked
directly and it (the handler) is operating on
doSomething(Object).
In the second case, this ultimately means that Weld will
check whether doSomething(Object) is intercepted. It
isn't, since Beans.getInterceptableMethods() is ignoring
bridge methods. The interceptor will not be invoked. On
the other hand, in the first case, the interceptor _will_
be invoked, since Weld will be checking whether
doSomething(String) is intercepted.
My initial solution was to make
Beans.getInterceptableMethods() also return bridge
methods, but now I'm thinking the actual problem is in the
proxy itself. IMO, when creating a proxy based on an
interface, we should also generate bridge methods on the
proxy (this should be either done by Weld or by Javassist
directly). These bridge methods should be perfectly normal
bridge methods and should not invoke the method handler
directly. They should simply invoke the non-bridge method
and the non-bridge method should then invoke the method
handler.
The java compiler can't add bridge methods directly to
interfaces which require them, so it adds them to all the
classes implementing the interface (StringFooImpl in our
case). Since we are creating StringFoo$Proxy, which is
also a class implementing an interface which requires
bridge methods, we should add the bridge methods
to it - exactly as the java compiler would.
This would solve the interceptor problem and possibly
other similar problems as well.
What do you think?
Marko