给出以下代码
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中的错误?有解决方法吗?或者我们应该放弃在服务中使用泛型?
答案 0 :(得分:3)
由于我们正在处理Java,因此在运行时类型擦除会占用,而您的业务接口将只包含:
public Object get();
您正在将接口转换为Bar
并且没有(没有运行时类转换异常),但是被调用的业务方法是业务接口中存在的业务方法(因为这是客户端知道的唯一方法) :Object get()
版本。
此外,由于设计上只拦截了业务方法调用,因此Object get()
上的String get()
委托不会被截获(它只是一种调用另一种方法的方法)。这意味着,在您的初始场景中,您试图拦截不属于业务接口的方法,因此永远不会被截获。
由于EJB3规范实际上并不清楚泛型(通常没有说明),实现确实将该部分委托给JVM。在这种情况下无法获得真正的通用支持,我会说你被类拦截器或改变业务接口所困扰。