EJB interceptors not called when using common interfaces

Given the following code

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"); } } } 

When we call the method on the remote control,

 Bar bar = context.lookup(Bar.class.getName()); bar.get(); 

or

 Foo foo = context.lookup(Bar.class.getName()); foo.get(); 

the interceptor is not called (using Glassfish 3.0.1).

The problem seems to be due to the compiled class file for the interface

 javap Foo Compiled from "Foo.java" public interface Foo{ public abstract java.lang.Object get(); } 

whereas for BarImpl it

 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(); } 

So, when we call

 Bar bar = ...; bar.get(); 

Internally method

 public java.lang.Object get(); 

which will delegate

 public java.lang.String get(); 

Interceptors seem to be called only on the first call. When I change the interface panel to

 @Remote public interface Bar extends Foo<String> { @Override String get(); } 

The interceptor is called in the first call (bar.get ()), but not in the second call (foo.get ()). Defining interceptors at the class level can solve the problem, but in our case this is not an option.

Are we doing something wrong, or is this a common java-ee-6 problem, or is it a bug in glass fish? Is there a workaround? Or should we completely abandon the use of generics in our Services?

+4
source share
1 answer

Since we are dealing with Java, type erasure takes care of itself at runtime, and your business interface will ever contain:

 public Object get(); 

You pass the Bar interface and this is normal (an exception of the execution class exception does not exist), but the business method that is called is the one present in the business interface (since this is the only method the client knows about): Object get() version.

In addition, since only business method calls are intercepted during design, Object get() delegation to String get() not intercepted (this is just a method that calls another method). This means that in your original scenario, you are trying to intercept a method that is not related to the business interface and therefore will never be intercepted.

Since the EJB3 specification is really not clear about generics (basically nothing is said), implementations do delegate this part of the JVM. There is no way in this scenario to get real general support, and I would say that you are stuck with class hooks or change your business interface.

+3
source

Source: https://habr.com/ru/post/1344083/


All Articles