Skip to content

Commit d27d2b2

Browse files
authored
Merge pull request #49931 from Ladicek/arc-fix-construction-of-interception-proxies
ArC: fix construction of interception proxies
2 parents a28fac8 + 4d60fcd commit d27d2b2

File tree

3 files changed

+104
-20
lines changed

3 files changed

+104
-20
lines changed

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptionProxyGenerator.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,7 @@ private void createInterceptionSubclass(ClassOutput classOutput, InterceptionPro
201201

202202
for (MethodInfo method : pseudoBean.getInterceptedMethods().keySet()) {
203203
forwardingMethods.put(MethodDescriptor.of(method), SubclassGenerator.createForwardingMethod(clazz,
204-
pseudoBeanClassName, method, (bytecode, virtualMethod, params) -> {
205-
ResultHandle delegateHandle = bytecode.readInstanceField(delegate.getFieldDescriptor(),
206-
bytecode.getThis());
207-
return isInterface
208-
? bytecode.invokeInterfaceMethod(virtualMethod, delegateHandle, params)
209-
: bytecode.invokeVirtualMethod(virtualMethod, delegateHandle, params);
210-
}));
204+
pseudoBeanClassName, method));
211205
}
212206

213207
FieldCreator constructedField = clazz.getFieldCreator(SubclassGenerator.FIELD_NAME_CONSTRUCTED, boolean.class)
@@ -364,16 +358,22 @@ private void createInterceptionSubclass(ClassOutput classOutput, InterceptionPro
364358
MethodCreator getDelegate = clazz.getMethodCreator("arc_delegate", Object.class);
365359
getDelegate.returnValue(getDelegate.readInstanceField(delegate.getFieldDescriptor(), getDelegate.getThis()));
366360

367-
// forward non-intercepted methods to the delegate unconditionally
361+
// forward non-intercepted methods to the delegate
368362
Collection<MethodInfo> methodsToForward = collectMethodsToForward(pseudoBean,
369363
bytecodeTransformerConsumer, transformUnproxyableClasses);
370364
for (MethodInfo method : methodsToForward) {
371365
MethodCreator mc = clazz.getMethodCreator(MethodDescriptor.of(method));
372-
ResultHandle dlgt = mc.readInstanceField(delegate.getFieldDescriptor(), mc.getThis());
366+
373367
ResultHandle[] args = new ResultHandle[method.parametersCount()];
374368
for (int i = 0; i < method.parametersCount(); i++) {
375369
args[i] = mc.getMethodParam(i);
376370
}
371+
372+
BytecodeCreator notConstructed = mc.ifFalse(
373+
mc.readInstanceField(constructedField.getFieldDescriptor(), mc.getThis())).trueBranch();
374+
notConstructed.returnValue(notConstructed.invokeSpecialMethod(method, notConstructed.getThis(), args));
375+
376+
ResultHandle dlgt = mc.readInstanceField(delegate.getFieldDescriptor(), mc.getThis());
377377
ResultHandle result = method.declaringClass().isInterface()
378378
? mc.invokeInterfaceMethod(method, dlgt, args)
379379
: mc.invokeVirtualMethod(method, dlgt, args);

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,7 @@ protected FieldDescriptor createConstructor(ClassOutput classOutput, BeanInfo be
190190
Map<MethodDescriptor, MethodDescriptor> forwardingMethods = new HashMap<>();
191191
List<MethodInfo> interceptedOrDecoratedMethods = bean.getInterceptedOrDecoratedMethods();
192192
for (MethodInfo method : interceptedOrDecoratedMethods) {
193-
forwardingMethods.put(MethodDescriptor.of(method), createForwardingMethod(subclass, providerTypeName, method,
194-
(bytecode, virtualMethod, params) -> bytecode.invokeSpecialMethod(virtualMethod, bytecode.getThis(),
195-
params)));
193+
forwardingMethods.put(MethodDescriptor.of(method), createForwardingMethod(subclass, providerTypeName, method));
196194
}
197195

198196
// If a decorator is associated:
@@ -864,13 +862,7 @@ private boolean isDecorated(Set<MethodDescriptor> decoratedMethodDescriptors, Me
864862
return false;
865863
}
866864

867-
@FunctionalInterface
868-
interface ForwardInvokeGenerator {
869-
ResultHandle generate(BytecodeCreator bytecode, MethodDescriptor virtualMethod, ResultHandle[] params);
870-
}
871-
872-
static MethodDescriptor createForwardingMethod(ClassCreator subclass, String providerTypeName, MethodInfo method,
873-
ForwardInvokeGenerator forwardInvokeGenerator) {
865+
static MethodDescriptor createForwardingMethod(ClassCreator subclass, String providerTypeName, MethodInfo method) {
874866
MethodDescriptor methodDescriptor = MethodDescriptor.of(method);
875867
String forwardMethodName = method.name() + "$$superforward";
876868
MethodDescriptor forwardDescriptor = MethodDescriptor.ofMethod(subclass.getClassName(), forwardMethodName,
@@ -884,7 +876,7 @@ static MethodDescriptor createForwardingMethod(ClassCreator subclass, String pro
884876
}
885877
MethodDescriptor virtualMethod = MethodDescriptor.ofMethod(providerTypeName, methodDescriptor.getName(),
886878
methodDescriptor.getReturnType(), methodDescriptor.getParameterTypes());
887-
forward.returnValue(forwardInvokeGenerator.generate(forward, virtualMethod, params));
879+
forward.returnValue(forward.invokeSpecialMethod(virtualMethod, forward.getThis(), params));
888880
return forwardDescriptor;
889881
}
890882

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package io.quarkus.arc.test.interceptors.producer;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
import jakarta.annotation.Priority;
13+
import jakarta.enterprise.context.Dependent;
14+
import jakarta.enterprise.inject.Produces;
15+
import jakarta.interceptor.AroundInvoke;
16+
import jakarta.interceptor.Interceptor;
17+
import jakarta.interceptor.InterceptorBinding;
18+
import jakarta.interceptor.InvocationContext;
19+
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.api.extension.RegisterExtension;
22+
23+
import io.quarkus.arc.Arc;
24+
import io.quarkus.arc.InterceptionProxy;
25+
import io.quarkus.arc.test.ArcTestContainer;
26+
27+
public class ProducerWithInterceptionAndVirtualCallInCtorTest {
28+
@RegisterExtension
29+
public ArcTestContainer container = new ArcTestContainer(MyBinding.class, MyInterceptor.class, MyProducer.class);
30+
31+
@Test
32+
public void test() {
33+
MyNonbean nonbean = Arc.container().instance(MyNonbean.class).get();
34+
assertEquals("intercepted: hello", nonbean.hello());
35+
assertEquals("intercepted: MyNonbean", nonbean.getThisClass_intercepted());
36+
assertEquals("MyNonbean", nonbean.getThisClass_notIntercepted());
37+
38+
assertEquals(List.of(
39+
"MyNonbean",
40+
"ProducerWithInterceptionAndVirtualCallInCtorTest$MyNonbean_InterceptionSubclass"),
41+
MyNonbean.constructedInstances_intercepted);
42+
assertEquals(MyNonbean.constructedInstances_intercepted, MyNonbean.constructedInstances_notIntercepted);
43+
}
44+
45+
@Retention(RetentionPolicy.RUNTIME)
46+
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR })
47+
@InterceptorBinding
48+
@interface MyBinding {
49+
}
50+
51+
@MyBinding
52+
@Priority(1)
53+
@Interceptor
54+
static class MyInterceptor {
55+
@AroundInvoke
56+
Object intercept(InvocationContext ctx) throws Exception {
57+
return "intercepted: " + ctx.proceed();
58+
}
59+
}
60+
61+
static class MyNonbean {
62+
static final List<String> constructedInstances_intercepted = new ArrayList<>();
63+
static final List<String> constructedInstances_notIntercepted = new ArrayList<>();
64+
65+
MyNonbean() {
66+
constructedInstances_intercepted.add(getThisClass_intercepted());
67+
constructedInstances_notIntercepted.add(getThisClass_notIntercepted());
68+
}
69+
70+
@MyBinding
71+
String getThisClass_intercepted() {
72+
return this.getClass().getSimpleName();
73+
}
74+
75+
String getThisClass_notIntercepted() {
76+
return this.getClass().getSimpleName();
77+
}
78+
79+
@MyBinding
80+
String hello() {
81+
return "hello";
82+
}
83+
}
84+
85+
@Dependent
86+
static class MyProducer {
87+
@Produces
88+
MyNonbean produce(InterceptionProxy<MyNonbean> proxy) {
89+
return proxy.create(new MyNonbean());
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)