From de13ac28e662fa295bc9900b6bc0912de68ff744 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Wed, 21 Jun 2023 11:13:16 +0200 Subject: [PATCH] Rework DefaultMethodTest to use InterceptionFactory --- .../InterceptingInvocationHandler.java | 204 ------------------ .../InterfaceBasedExtension.java | 27 +-- 2 files changed, 15 insertions(+), 216 deletions(-) delete mode 100644 testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterceptingInvocationHandler.java diff --git a/testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterceptingInvocationHandler.java b/testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterceptingInvocationHandler.java deleted file mode 100644 index 9ebca670..00000000 --- a/testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterceptingInvocationHandler.java +++ /dev/null @@ -1,204 +0,0 @@ -package io.smallrye.faulttolerance.defaultmethod; - -import static io.smallrye.faulttolerance.core.util.SneakyThrow.sneakyThrow; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import jakarta.enterprise.context.spi.CreationalContext; -import jakarta.enterprise.inject.spi.BeanManager; -import jakarta.enterprise.inject.spi.InterceptionType; -import jakarta.enterprise.inject.spi.Interceptor; -import jakarta.interceptor.InvocationContext; - -// adapted from https://github.com/resteasy/resteasy-microprofile/tree/main/rest-client-base/src/main/java/org/jboss/resteasy/microprofile/client -// which is Apache 2.0 licensed -public class InterceptingInvocationHandler implements InvocationHandler { - private final Object target; - - private final Map> interceptorChains; - - public InterceptingInvocationHandler(Class iface, Object target, BeanManager beanManager) { - this.target = target; - - // this CreationalContext is never released, but that's ok _in a test_ - CreationalContext creationalContext = beanManager.createCreationalContext(null); - this.interceptorChains = initInterceptorChains(beanManager, creationalContext, iface); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - List chain = interceptorChains.get(method); - if (chain != null) { - return new InvocationContextImpl(target, method, args, chain).proceed(); - } else { - try { - return method.invoke(target, args); - } catch (InvocationTargetException e) { - throw e.getCause(); - } - } - } - - private static Map> initInterceptorChains(BeanManager beanManager, - CreationalContext creationalContext, Class iface) { - - Map> chains = new HashMap<>(); - Map, Object> interceptorInstances = new HashMap<>(); - - List classLevelBindings = getBindings(iface, beanManager); - - for (Method method : iface.getMethods()) { - if (method.isDefault() || Modifier.isStatic(method.getModifiers())) { - continue; - } - - List methodLevelBindings = getBindings(method, beanManager); - if (!classLevelBindings.isEmpty() || !methodLevelBindings.isEmpty()) { - Annotation[] interceptorBindings = mergeBindings(methodLevelBindings, classLevelBindings); - - List> interceptors = beanManager.resolveInterceptors(InterceptionType.AROUND_INVOKE, - interceptorBindings); - if (!interceptors.isEmpty()) { - List chain = new ArrayList<>(); - for (Interceptor interceptor : interceptors) { - chain.add(new InterceptorInvocation((Interceptor) interceptor, - interceptorInstances.computeIfAbsent(interceptor, - i -> beanManager.getReference(i, i.getBeanClass(), creationalContext)))); - } - chains.put(method, chain); - } - } - } - - return chains; - } - - private static List getBindings(AnnotatedElement annotated, BeanManager beanManager) { - Annotation[] annotations = annotated.getAnnotations(); - if (annotations.length == 0) { - return Collections.emptyList(); - } - List bindings = new ArrayList<>(); - for (Annotation annotation : annotations) { - if (beanManager.isInterceptorBinding(annotation.annotationType())) { - bindings.add(annotation); - } - } - return bindings; - } - - private static Annotation[] mergeBindings(List methodLevel, List classLevel) { - Set> methodLevelTypes = methodLevel.stream() - .map(Annotation::annotationType) - .collect(Collectors.toSet()); - - List result = new ArrayList<>(methodLevel); - for (Annotation classLevelBinding : classLevel) { - if (!methodLevelTypes.contains(classLevelBinding.annotationType())) { - result.add(classLevelBinding); - } - } - return result.toArray(new Annotation[0]); - } - - private static class InvocationContextImpl implements InvocationContext { - private final Object target; - private final Method method; - private Object[] arguments; - private final Map contextData; - - private final List chain; - private final int position; - - public InvocationContextImpl(Object target, Method method, Object[] arguments, - List chain) { - this(target, method, arguments, chain, 0); - } - - private InvocationContextImpl(Object target, Method method, Object[] arguments, - List chain, int position) { - this.target = target; - this.method = method; - this.arguments = arguments; - this.contextData = new HashMap<>(); - this.chain = chain; - this.position = position; - } - - @Override - public Object proceed() throws Exception { - try { - if (position < chain.size()) { - InvocationContextImpl ctx = new InvocationContextImpl(target, method, arguments, chain, position + 1); - return chain.get(position).invoke(ctx); - } else { - return method.invoke(target, arguments); - } - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } - } - - @Override - public Object getTarget() { - return target; - } - - @Override - public Method getMethod() { - return method; - } - - @Override - public Constructor getConstructor() { - return null; - } - - @Override - public Object[] getParameters() throws IllegalStateException { - return arguments; - } - - @Override - public void setParameters(Object[] args) throws IllegalStateException, IllegalArgumentException { - this.arguments = args; - } - - @Override - public Map getContextData() { - return contextData; - } - - @Override - public Object getTimer() { - return null; - } - } - - private static class InterceptorInvocation { - private final Interceptor interceptorBean; - private final Object interceptorInstance; - - public InterceptorInvocation(Interceptor interceptorBean, Object interceptorInstance) { - this.interceptorBean = interceptorBean; - this.interceptorInstance = interceptorInstance; - } - - public Object invoke(InvocationContext ctx) throws Exception { - return interceptorBean.intercept(InterceptionType.AROUND_INVOKE, interceptorInstance, ctx); - } - } -} diff --git a/testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterfaceBasedExtension.java b/testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterfaceBasedExtension.java index 5b11f924..3ed54c5a 100644 --- a/testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterfaceBasedExtension.java +++ b/testsuite/basic/src/test/java/io/smallrye/faulttolerance/defaultmethod/InterfaceBasedExtension.java @@ -16,6 +16,7 @@ import jakarta.enterprise.inject.spi.Extension; import jakarta.enterprise.inject.spi.ProcessAnnotatedType; import jakarta.enterprise.inject.spi.WithAnnotations; +import jakarta.enterprise.inject.spi.configurator.BeanConfigurator; public class InterfaceBasedExtension implements Extension { private static final Logger LOG = Logger.getLogger(InterfaceBasedExtension.class.getName()); @@ -39,21 +40,23 @@ public void rememberInterfaces(@Observes @WithAnnotations(RegisterInterfaceBased public void registerBeans(@Observes AfterBeanDiscovery abd, BeanManager beanManager) { for (Class iface : interfaces) { - abd.addBean() - .beanClass(iface) - .types(iface) - .scope(Dependent.class) - .qualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE, InterfaceBased.Literal.INSTANCE) - .createWith(ctx -> { - Object target = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), - new Class[] { iface }, InterfaceBasedExtension::invoke); - return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), - new Class[] { iface }, new InterceptingInvocationHandler(iface, target, beanManager)); - }); - LOG.info("Registered bean for " + iface); + registerBean(iface, abd.addBean(), beanManager); } } + private void registerBean(Class beanType, BeanConfigurator beanConfigurator, BeanManager bm) { + beanConfigurator.beanClass(beanType) + .types(beanType) + .scope(Dependent.class) + .qualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE, InterfaceBased.Literal.INSTANCE) + .createWith(ctx -> { + T instance = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + new Class[] { beanType }, InterfaceBasedExtension::invoke); + return bm.createInterceptionFactory(ctx, beanType).createInterceptedInstance(instance); + }); + LOG.info("Registered bean for " + beanType); + } + private static Object invoke(Object proxy, Method method, Object[] args) { throw new IllegalArgumentException("Always an exception"); }