给定以下代码
public interface Foo<T> {
T get();
}
@Remote
public interface Bar extends Foo<String> {
}
@Stateless
public class BarImpl implements Bar {
@Interceptors(ExceptionInterceptor.class)
public String get() {
throw new RuntimeException("not implemented");
}
}
public class ExceptionInterceptor {
@AroundInvoke
public Object convertExceptionForExternalSystem(InvocationContext ctx) throws RuntimeException, Error {
try
{
return ctx.proceed();
}
catch (Throwable e)
{
if (e instanceof Error)
throw new Error("Changed");
throw new RuntimeException("Changed");
}
}
}当我们在远程调用一个方法时,
Bar bar = context.lookup(Bar.class.getName());
bar.get();或
Foo foo = context.lookup(Bar.class.getName());
foo.get();不调用拦截器(使用Glassfish 3.0.1)。
这个问题似乎是由于接口的编译类文件是
javap Foo
Compiled from "Foo.java"
public interface Foo{
public abstract java.lang.Object get();
}而对于BarImpl,它是
javap BarImpl
Compiled from "BarImpl.java"
public class BarImpl extends java.lang.Object implements Bar{
public BarImpl();
public java.lang.String get();
public java.lang.Object get();
}所以,当我们调用
Bar bar = ...;
bar.get();在内部,方法
public java.lang.Object get(); ,它将委托给
public java.lang.String get();拦截器似乎只有在直接调用后者时才会被调用。当我将界面栏更改为
@Remote
public interface Bar extends Foo<String> {
@Override
String get();
}拦截器在第一个调用(bar.get())中调用,但在第二个调用(foo.get())中没有调用。在类级别上定义拦截器可能会解决这个问题,但在我们的情况下不是一个选项。
我们是否做错了什么,或者这是java-ee-6的一般问题,或者这是glassfish中的错误?有解决办法吗?或者我们应该放弃在我们的服务中使用泛型吗?
发布于 2011-12-20 02:10:26
因为我们处理的是Java,所以类型擦除会在运行时接管,而您的业务接口将只包含:
public Object get();您正在将接口强制转换为Bar,这没有问题(没有运行时类强制转换异常),但是被调用的业务方法是业务接口中存在的方法(因为这是客户端知道的唯一方法):Object get()版本。
此外,由于设计上只拦截业务方法调用,所以在String get()上委托的Object get()不会被拦截(它只是一个方法调用另一个方法)。这意味着,在最初的场景中,您试图拦截一个不属于业务接口的方法,因此永远不会被拦截。
由于EJB3规范对泛型的定义并不明确(基本上什么也没说),所以实现实际上将这一部分委托给了JVM虚拟机。在这种情况下,没有办法获得真正的通用支持,我要说的是,你不得不使用类拦截器或更改业务接口。
https://stackoverflow.com/questions/5337879
复制相似问题