diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/ArcDevConsoleProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/ArcDevConsoleProcessor.java index 6aa525cec7768..8b7b4b1aad38d 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/ArcDevConsoleProcessor.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/ArcDevConsoleProcessor.java @@ -18,6 +18,7 @@ import io.quarkus.arc.processor.BeanDeploymentValidator; import io.quarkus.arc.processor.BeanInfo; import io.quarkus.arc.processor.BuildExtension; +import io.quarkus.arc.processor.InterceptorInfo; import io.quarkus.arc.processor.ObserverInfo; import io.quarkus.arc.runtime.ArcContainerSupplier; import io.quarkus.arc.runtime.ArcRecorder; @@ -92,14 +93,17 @@ public DevConsoleTemplateInfoBuildItem collectBeanInfo(ValidationPhaseBuildItem CompletedApplicationClassPredicateBuildItem predicate) { BeanDeploymentValidator.ValidationContext validationContext = validationPhaseBuildItem.getContext(); DevBeanInfos beanInfos = new DevBeanInfos(); - for (BeanInfo beanInfo : validationContext.beans()) { - beanInfos.addBean(DevBeanInfo.from(beanInfo, predicate)); + for (BeanInfo bean : validationContext.beans()) { + beanInfos.addBean(DevBeanInfo.from(bean, predicate)); } - for (BeanInfo beanInfo : validationContext.removedBeans()) { - beanInfos.addRemovedBean(DevBeanInfo.from(beanInfo, predicate)); + for (BeanInfo bean : validationContext.removedBeans()) { + beanInfos.addRemovedBean(DevBeanInfo.from(bean, predicate)); } - for (ObserverInfo observerInfo : validationContext.get(BuildExtension.Key.OBSERVERS)) { - beanInfos.addObserver(DevObserverInfo.from(observerInfo, predicate)); + for (ObserverInfo observer : validationContext.get(BuildExtension.Key.OBSERVERS)) { + beanInfos.addObserver(DevObserverInfo.from(observer, predicate)); + } + for (InterceptorInfo interceptor : validationContext.get(BuildExtension.Key.INTERCEPTORS)) { + beanInfos.addInterceptor(DevInterceptorInfo.from(interceptor, predicate)); } beanInfos.sort(); return new DevConsoleTemplateInfoBuildItem("devBeanInfos", beanInfos); diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfo.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfo.java index 85809f19c0bbd..dc4026c3271ad 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfo.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfo.java @@ -1,6 +1,8 @@ package io.quarkus.arc.deployment.devconsole; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import org.jboss.jandex.AnnotationInstance; @@ -14,6 +16,7 @@ import io.quarkus.arc.deployment.CompletedApplicationClassPredicateBuildItem; import io.quarkus.arc.processor.BeanInfo; import io.quarkus.arc.processor.DotNames; +import io.quarkus.arc.processor.InterceptorInfo; public class DevBeanInfo implements Comparable { @@ -29,6 +32,17 @@ public static DevBeanInfo from(BeanInfo bean, CompletedApplicationClassPredicate Name scope = Name.from(bean.getScope().getDotName()); Name providerType = Name.from(bean.getProviderType()); + List interceptors; + List boundInterceptors = bean.getBoundInterceptors(); + if (boundInterceptors.isEmpty()) { + interceptors = List.of(); + } else { + interceptors = new ArrayList<>(); + for (InterceptorInfo interceptor : boundInterceptors) { + interceptors.add(interceptor.getIdentifier()); + } + } + if (bean.getTarget().isPresent()) { AnnotationTarget target = bean.getTarget().get(); DevBeanKind kind; @@ -56,15 +70,17 @@ public static DevBeanInfo from(BeanInfo bean, CompletedApplicationClassPredicate } else { throw new IllegalArgumentException("Invalid annotation target: " + target); } - return new DevBeanInfo(kind, isApplicationBean, providerType, memberName, types, qualifiers, scope, declaringClass); + return new DevBeanInfo(kind, isApplicationBean, providerType, memberName, types, qualifiers, scope, declaringClass, + interceptors); } else { // Synthetic bean - return new DevBeanInfo(DevBeanKind.SYNTHETIC, false, providerType, null, types, qualifiers, scope, null); + return new DevBeanInfo(DevBeanKind.SYNTHETIC, false, providerType, null, types, qualifiers, scope, null, + interceptors); } } public DevBeanInfo(DevBeanKind kind, boolean isApplicationBean, Name providerType, String memberName, Set types, - Set qualifiers, Name scope, Name declaringClass) { + Set qualifiers, Name scope, Name declaringClass, List boundInterceptors) { this.kind = kind; this.isApplicationBean = isApplicationBean; this.providerType = providerType; @@ -73,6 +89,7 @@ public DevBeanInfo(DevBeanKind kind, boolean isApplicationBean, Name providerTyp this.qualifiers = qualifiers; this.scope = scope; this.declaringClass = declaringClass; + this.interceptors = boundInterceptors; } private final DevBeanKind kind; @@ -83,6 +100,7 @@ public DevBeanInfo(DevBeanKind kind, boolean isApplicationBean, Name providerTyp private final Set qualifiers; private final Name scope; private final Name declaringClass; + private final List interceptors; public DevBeanKind getKind() { return kind; @@ -129,6 +147,10 @@ public Name getDeclaringClass() { return declaringClass; } + public List getInterceptors() { + return interceptors; + } + @Override public int compareTo(DevBeanInfo o) { // Application beans should go first diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfos.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfos.java index e9e7b6200de8e..d704a9e8c3aa9 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfos.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevBeanInfos.java @@ -9,11 +9,13 @@ public class DevBeanInfos { private final List beans; private final List removedBeans; private final List observers; + private final List interceptors; public DevBeanInfos() { beans = new ArrayList<>(); removedBeans = new ArrayList<>(); observers = new ArrayList<>(); + interceptors = new ArrayList<>(); } public List getRemovedBeans() { @@ -28,6 +30,19 @@ public List getObservers() { return observers; } + public List getInterceptors() { + return interceptors; + } + + public DevInterceptorInfo getInterceptor(String id) { + for (DevInterceptorInfo interceptor : interceptors) { + if (interceptor.getId().equals(id)) { + return interceptor; + } + } + return null; + } + void addBean(DevBeanInfo beanInfo) { beans.add(beanInfo); } @@ -40,9 +55,14 @@ void addObserver(DevObserverInfo observer) { observers.add(observer); } + void addInterceptor(DevInterceptorInfo interceptor) { + interceptors.add(interceptor); + } + void sort() { Collections.sort(beans); Collections.sort(removedBeans); Collections.sort(observers); + Collections.sort(interceptors); } } diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevInterceptorInfo.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevInterceptorInfo.java new file mode 100644 index 0000000000000..f4e5670e70b17 --- /dev/null +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DevInterceptorInfo.java @@ -0,0 +1,88 @@ +package io.quarkus.arc.deployment.devconsole; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.enterprise.inject.spi.InterceptionType; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.MethodInfo; + +import io.quarkus.arc.deployment.CompletedApplicationClassPredicateBuildItem; +import io.quarkus.arc.processor.InterceptorInfo; + +public class DevInterceptorInfo implements Comparable { + + public static DevInterceptorInfo from(InterceptorInfo interceptor, CompletedApplicationClassPredicateBuildItem predicate) { + boolean isApplicationBean = predicate.test(interceptor.getBeanClass()); + Set bindings = new HashSet<>(); + for (AnnotationInstance binding : interceptor.getBindings()) { + bindings.add(Name.from(binding)); + } + Map intercepts = new HashMap<>(); + if (interceptor.intercepts(InterceptionType.AROUND_INVOKE)) { + intercepts.put(InterceptionType.AROUND_INVOKE, interceptor.getAroundInvoke()); + } + if (interceptor.intercepts(InterceptionType.AROUND_CONSTRUCT)) { + intercepts.put(InterceptionType.AROUND_CONSTRUCT, interceptor.getAroundInvoke()); + } + if (interceptor.intercepts(InterceptionType.POST_CONSTRUCT)) { + intercepts.put(InterceptionType.POST_CONSTRUCT, interceptor.getPostConstruct()); + } + if (interceptor.intercepts(InterceptionType.PRE_DESTROY)) { + intercepts.put(InterceptionType.PRE_DESTROY, interceptor.getPreDestroy()); + } + return new DevInterceptorInfo(interceptor.getIdentifier(), Name.from(interceptor.getBeanClass()), bindings, + interceptor.getPriority(), intercepts, + isApplicationBean); + } + + private final String id; + private final Name interceptorClass; + private final Set bindings; + private final int priority; + private final Map intercepts; + private final boolean isApplicationBean; + + DevInterceptorInfo(String id, Name interceptorClass, Set bindings, int priority, + Map intercepts, boolean isApplicationBean) { + this.id = id; + this.interceptorClass = interceptorClass; + this.bindings = bindings; + this.priority = priority; + this.intercepts = intercepts; + this.isApplicationBean = isApplicationBean; + } + + public String getId() { + return id; + } + + public Name getInterceptorClass() { + return interceptorClass; + } + + public Set getBindings() { + return bindings; + } + + public int getPriority() { + return priority; + } + + public Map getIntercepts() { + return intercepts; + } + + @Override + public int compareTo(DevInterceptorInfo o) { + // Application beans should go first + if (isApplicationBean == o.isApplicationBean) { + return interceptorClass.compareTo(o.interceptorClass); + } + return isApplicationBean ? -1 : 1; + } + +} diff --git a/extensions/arc/deployment/src/main/resources/dev-templates/beans.html b/extensions/arc/deployment/src/main/resources/dev-templates/beans.html index e00309161893b..e4f6f7255beb4 100644 --- a/extensions/arc/deployment/src/main/resources/dev-templates/beans.html +++ b/extensions/arc/deployment/src/main/resources/dev-templates/beans.html @@ -1,4 +1,4 @@ -{#include main} +{#include main fluid=true} {#style} .annotation { color: gray; @@ -31,17 +31,23 @@ openInIDE($(this).text()); }); }); - {/script} {#title}Beans{/title} {#body} + + @@ -54,6 +60,15 @@ + {/for}
# Bean KindAssociated Interceptors
{#bean-declaration bean/} +
    + {#for interceptorId in bean.interceptors} + {#set interceptor=info:devBeanInfos.getInterceptor(interceptorId)} +
  • {interceptor.interceptorClass} {interceptor.priority}
  • + {/set} + {/for} +
+
diff --git a/extensions/arc/deployment/src/main/resources/dev-templates/embedded.html b/extensions/arc/deployment/src/main/resources/dev-templates/embedded.html index dd2fe654bde0d..3fc6a00f563ea 100644 --- a/extensions/arc/deployment/src/main/resources/dev-templates/embedded.html +++ b/extensions/arc/deployment/src/main/resources/dev-templates/embedded.html @@ -4,18 +4,22 @@
- Observers {info:arcContainer.observers.size} + Observers {info:devBeanInfos.observers.size} +
+ + + Interceptors {info:devBeanInfos.interceptors.size}
{#if config:property('quarkus.arc.dev-mode.monitoring-enabled') is "true"} - + Fired Events
- + Invocation Trees
{/if} - Removed Beans {info:arcContainer.removedBeans.size} \ No newline at end of file + Removed Beans {info:devBeanInfos.removedBeans.size} \ No newline at end of file diff --git a/extensions/arc/deployment/src/main/resources/dev-templates/interceptors.html b/extensions/arc/deployment/src/main/resources/dev-templates/interceptors.html new file mode 100644 index 0000000000000..5397a433faccc --- /dev/null +++ b/extensions/arc/deployment/src/main/resources/dev-templates/interceptors.html @@ -0,0 +1,76 @@ +{#include main fluid=true} + {#style} + .annotation { + color: gray; + font-style: italic; + } + span.larger-badge { + font-size: 0.9em; + } + span.app-class { + cursor:pointer; + color:blue; + text-decoration:underline; + } + {/style} + + {#script} + $(document).ready(function(){ + if (!ideKnown()) { + return; + } + $(".class-candidate").each(function() { + var className = $(this).text(); + if (appClassLang(className)) { + $(this).addClass("app-class"); + } + }); + + $(".app-class").on("click", function() { + openInIDE($(this).text()); + }); + }); + + {/script} + + {#title}Interceptors{/title} + {#body} + + + + + + + + + + + + + {#for interceptor in info:devBeanInfos.interceptors} + + + + + + + {/for} + +
#Interceptor classPriorityBindingsInterception Types
{count}.{interceptor.interceptorClass}{interceptor.priority} + {#for b in interceptor.bindings} + {b.simpleName}
+ {/for} +
+
    + {#each interceptor.intercepts} +
  • {#interception-type it.key /} {interceptor.interceptorClass.simpleName}#{it.value.name}()
  • + {/each} +
+
+ {/body} +{/include} diff --git a/extensions/arc/deployment/src/main/resources/dev-templates/observers.html b/extensions/arc/deployment/src/main/resources/dev-templates/observers.html index b378d9a7f56bf..957d79d6752b3 100644 --- a/extensions/arc/deployment/src/main/resources/dev-templates/observers.html +++ b/extensions/arc/deployment/src/main/resources/dev-templates/observers.html @@ -8,6 +8,23 @@ font-size: 0.9em; } {/style} + {#script} + $(document).ready(function(){ + if (!ideKnown()) { + return; + } + $(".class-candidate").each(function() { + var className = $(this).text(); + if (appClassLang(className)) { + $(this).addClass("app-class"); + } + }); + + $(".app-class").on("click", function() { + openInIDE($(this).text()); + }); + }); + {/script} {#title}Observers{/title} {#body} @@ -28,7 +45,7 @@ - + diff --git a/extensions/arc/deployment/src/main/resources/dev-templates/tags/interception-type.html b/extensions/arc/deployment/src/main/resources/dev-templates/tags/interception-type.html new file mode 100644 index 0000000000000..cb86a9ea15499 --- /dev/null +++ b/extensions/arc/deployment/src/main/resources/dev-templates/tags/interception-type.html @@ -0,0 +1,10 @@ +{#switch it} + {#case AROUND_INVOKE} + @AroundInvoke + {#case AROUND_CONSTRUCT} + @AroundConstruct + {#case POST_CONSTRUCT} + @PostConstruct + {#case PRE_DESTROY} + @PreDestroy +{/switch} \ No newline at end of file diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java index 2998735d5d62f..3ada64bb4d144 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java @@ -226,10 +226,12 @@ BeanRegistrar.RegistrationContext registerBeans(List beanRegistra List injectionPoints = new ArrayList<>(); this.beans.addAll(findBeans(initBeanDefiningAnnotations(beanDefiningAnnotations, stereotypes.keySet()), observers, injectionPoints, jtaCapabilities)); + // Note that we need to use view of the collections to reflect further additions, e.g. synthetic beans and observers buildContextPut(Key.BEANS.asString(), Collections.unmodifiableList(beans)); buildContextPut(Key.OBSERVERS.asString(), Collections.unmodifiableList(observers)); this.interceptors.addAll(findInterceptors(injectionPoints)); + buildContextPut(Key.INTERCEPTORS.asString(), Collections.unmodifiableList(interceptors)); this.decorators.addAll(findDecorators(injectionPoints)); this.injectionPoints.addAll(injectionPoints); buildContextPut(Key.INJECTION_POINTS.asString(), Collections.unmodifiableList(this.injectionPoints)); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanInfo.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanInfo.java index 0e1c39afb31ee..f43294f648a76 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanInfo.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanInfo.java @@ -348,7 +348,7 @@ public boolean isForceApplicationClass() { * * @return an ordered list of all interceptors associated with the bean */ - List getBoundInterceptors() { + public List getBoundInterceptors() { if (lifecycleInterceptors.isEmpty() && interceptedMethods.isEmpty()) { return Collections.emptyList(); } @@ -371,7 +371,7 @@ List getBoundInterceptors() { return bound; } - List getBoundDecorators() { + public List getBoundDecorators() { if (decoratedMethods.isEmpty()) { return Collections.emptyList(); } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuildExtension.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuildExtension.java index 98eb601bc4f3c..e3310487b3771 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuildExtension.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BuildExtension.java @@ -55,6 +55,7 @@ interface Key { static Key> BEANS = new SimpleKey<>(BUILT_IN_PREFIX + "beans"); static Key> REMOVED_BEANS = new SimpleKey<>(BUILT_IN_PREFIX + "removedBeans"); static Key> OBSERVERS = new SimpleKey<>(BUILT_IN_PREFIX + "observers"); + static Key> INTERCEPTORS = new SimpleKey<>(BUILT_IN_PREFIX + "interceptors"); static Key ANNOTATION_STORE = new SimpleKey<>(BUILT_IN_PREFIX + "annotationStore"); static Key> SCOPES = new SimpleKey<>(BUILT_IN_PREFIX + "scopes"); static Key> QUALIFIERS = new SimpleKey<>(BUILT_IN_PREFIX + "qualifiers"); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorInfo.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorInfo.java index 117d1ba6ee775..a97c37775ff0c 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorInfo.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorInfo.java @@ -116,19 +116,19 @@ public int getPriority() { return priority; } - MethodInfo getAroundInvoke() { + public MethodInfo getAroundInvoke() { return aroundInvoke; } - MethodInfo getAroundConstruct() { + public MethodInfo getAroundConstruct() { return aroundConstruct; } - MethodInfo getPostConstruct() { + public MethodInfo getPostConstruct() { return postConstruct; } - MethodInfo getPreDestroy() { + public MethodInfo getPreDestroy() { return preDestroy; } diff --git a/integration-tests/devmode/src/test/java/io/quarkus/test/devconsole/DevConsoleArcSmokeTest.java b/integration-tests/devmode/src/test/java/io/quarkus/test/devconsole/DevConsoleArcSmokeTest.java index e6200af03b290..4ee30ed9a320b 100644 --- a/integration-tests/devmode/src/test/java/io/quarkus/test/devconsole/DevConsoleArcSmokeTest.java +++ b/integration-tests/devmode/src/test/java/io/quarkus/test/devconsole/DevConsoleArcSmokeTest.java @@ -34,7 +34,8 @@ public void testPages() { .get("q/dev/io.quarkus.quarkus-arc/observers") .then() .statusCode(200) - .body(Matchers.containsString("io.quarkus.test.devconsole.DevConsoleArcSmokeTest$Foo#onStr")); + .body(Matchers.containsString( + "io.quarkus.test.devconsole.DevConsoleArcSmokeTest$Foo#onStr")); RestAssured .get("q/dev/io.quarkus.quarkus-arc/events") .then()
{count}. {#if observer.declaringClass} - {observer.declaringClass}#{observer.methodName}() + {observer.declaringClass}#{observer.methodName}() {#else} Synthetic {/if} @@ -39,9 +56,7 @@ {/each} {observer.observedType} - {observer.priority} - {observer.priority} {observer.reception}