diff --git a/build-parent/pom.xml b/build-parent/pom.xml index ca27ff3fa1a5d..01644ebc45623 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -137,6 +137,7 @@ 5.62.2 8.9.1 + 6.6.0 0.14.6 @@ -315,6 +316,11 @@ codemirror ${webjar.codemirror.version} + + org.webjars + d3js + ${webjar.d3js.version} + com.github.davidmoten diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/UnremovableBeanBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/UnremovableBeanBuildItem.java index 358b3a0d61d1b..7b1276c942b41 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/UnremovableBeanBuildItem.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/UnremovableBeanBuildItem.java @@ -172,6 +172,11 @@ public boolean test(BeanInfo bean) { return bean.getBeanClass().toString().equals(className); } + @Override + public String toString() { + return "BeanClassNameExclusion [className=" + className + "]"; + } + } public static class BeanClassNamesExclusion implements Predicate { @@ -187,6 +192,11 @@ public boolean test(BeanInfo bean) { return classNames.contains(bean.getBeanClass().toString()); } + @Override + public String toString() { + return "BeanClassNamesExclusion [classNames=" + classNames + "]"; + } + } public static class BeanTypeExclusion implements Predicate { @@ -202,6 +212,11 @@ public boolean test(BeanInfo bean) { return bean.getTypes().stream().anyMatch(t -> dotName.equals(t.name())); } + @Override + public String toString() { + return "BeanTypeExclusion [dotName=" + dotName + "]"; + } + } public static class BeanTypesExclusion implements Predicate { @@ -217,6 +232,11 @@ public boolean test(BeanInfo bean) { return bean.getTypes().stream().anyMatch(t -> dotNames.contains(t.name())); } + @Override + public String toString() { + return "BeanTypesExclusion [dotNames=" + dotNames + "]"; + } + } public static class BeanClassAnnotationExclusion implements Predicate { @@ -248,6 +268,11 @@ public boolean test(BeanInfo bean) { return false; } + @Override + public String toString() { + return "BeanClassAnnotationExclusion [nameStartsWith=" + nameStartsWith + ", name=" + name + "]"; + } + } } diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ValidationPhaseBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ValidationPhaseBuildItem.java index 142234b426b89..1feb7d03825c0 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ValidationPhaseBuildItem.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ValidationPhaseBuildItem.java @@ -5,6 +5,7 @@ import io.quarkus.arc.processor.BeanDeploymentValidator; import io.quarkus.arc.processor.BeanProcessor; +import io.quarkus.arc.processor.BeanResolver; import io.quarkus.builder.item.MultiBuildItem; import io.quarkus.builder.item.SimpleBuildItem; import io.quarkus.deployment.annotations.BuildProducer; @@ -33,6 +34,15 @@ public BeanDeploymentValidator.ValidationContext getContext() { return context; } + /** + * The bean resolver can be used to apply the type-safe resolution rules. + * + * @return the bean resolver + */ + public BeanResolver getBeanResolver() { + return beanProcessor.getBeanDeployment().getBeanResolver(); + } + BeanProcessor getBeanProcessor() { return beanProcessor; } 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 0ddb2f7dfc0ab..7edce828544ab 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 @@ -1,9 +1,12 @@ package io.quarkus.arc.deployment.devconsole; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; @@ -15,11 +18,15 @@ import io.quarkus.arc.deployment.CompletedApplicationClassPredicateBuildItem; import io.quarkus.arc.deployment.CustomScopeAnnotationsBuildItem; import io.quarkus.arc.deployment.ValidationPhaseBuildItem; +import io.quarkus.arc.deployment.devconsole.DependecyGraph.Link; import io.quarkus.arc.processor.AnnotationsTransformer; import io.quarkus.arc.processor.BeanDeploymentValidator; +import io.quarkus.arc.processor.BeanDeploymentValidator.ValidationContext; import io.quarkus.arc.processor.BeanInfo; +import io.quarkus.arc.processor.BeanResolver; import io.quarkus.arc.processor.BuildExtension; import io.quarkus.arc.processor.DecoratorInfo; +import io.quarkus.arc.processor.InjectionPointInfo; import io.quarkus.arc.processor.InterceptorInfo; import io.quarkus.arc.processor.ObserverInfo; import io.quarkus.arc.runtime.ArcContainerSupplier; @@ -124,6 +131,14 @@ public DevConsoleTemplateInfoBuildItem collectBeanInfo(ValidationPhaseBuildItem beanInfos.addRemovedDecorator(DevDecoratorInfo.from(decorator, predicate)); } } + + // Build dependency graphs + BeanResolver resolver = validationPhaseBuildItem.getBeanResolver(); + for (BeanInfo bean : validationContext.beans()) { + beanInfos.addDependencyGraph(bean.getIdentifier(), + buildDependencyGraph(bean, validationContext, resolver, beanInfos)); + } + beanInfos.sort(); return new DevConsoleTemplateInfoBuildItem("devBeanInfos", beanInfos); } @@ -138,4 +153,70 @@ private boolean isAdditionalBeanDefiningAnnotationOn(ClassInfo beanClass, return false; } + DependecyGraph buildDependencyGraph(BeanInfo bean, ValidationContext validationContext, BeanResolver resolver, + DevBeanInfos devBeanInfos) { + Set nodes = new HashSet<>(); + Collection beans = validationContext.get(BuildExtension.Key.BEANS); + Set links = new HashSet<>(); + Map> declaringToProducers = validationContext.beans().producers() + .collect(Collectors.groupingBy(BeanInfo::getDeclaringBean)); + addNodesDependencies(bean, nodes, links, bean, devBeanInfos); + addNodesDependents(bean, nodes, links, bean, beans, declaringToProducers, resolver, devBeanInfos); + return new DependecyGraph(nodes, links); + } + + void addNodesDependencies(BeanInfo root, Set nodes, Set links, BeanInfo bean, + DevBeanInfos devBeanInfos) { + if (nodes.add(devBeanInfos.getBean(bean.getIdentifier()))) { + if (bean.isProducerField() || bean.isProducerMethod()) { + links.add(Link.producer(bean.getIdentifier(), bean.getDeclaringBean().getIdentifier())); + addNodesDependencies(root, nodes, links, bean.getDeclaringBean(), devBeanInfos); + } + for (InjectionPointInfo injectionPoint : bean.getAllInjectionPoints()) { + BeanInfo resolved = injectionPoint.getResolvedBean(); + if (resolved != null && !resolved.equals(bean)) { + links.add(Link.dependency(root.equals(bean), bean.getIdentifier(), resolved.getIdentifier())); + // add transient dependencies + addNodesDependencies(root, nodes, links, injectionPoint.getResolvedBean(), devBeanInfos); + } + } + } + } + + void addNodesDependents(BeanInfo root, Set nodes, Set links, BeanInfo bean, Collection beans, + Map> declaringToProducers, BeanResolver resolver, DevBeanInfos devBeanInfos) { + for (BeanInfo dependent : beans) { + if (!bean.equals(dependent)) { + for (InjectionPointInfo injectionPoint : dependent.getAllInjectionPoints()) { + Link link = null; + if (injectionPoint.isProgrammaticLookup()) { + if (resolver.matches(bean, + injectionPoint.getType().asParameterizedType().arguments().get(0), + injectionPoint.getRequiredQualifiers())) { + link = Link.lookup(dependent.getIdentifier(), bean.getIdentifier()); + } + } else if (bean.equals(injectionPoint.getResolvedBean())) { + link = Link.dependent(root.equals(bean), dependent.getIdentifier(), bean.getIdentifier()); + } + if (link != null) { + links.add(link); + if (nodes.add(devBeanInfos.getBean(dependent.getIdentifier()))) { + // add transient dependents + addNodesDependents(root, nodes, links, dependent, beans, declaringToProducers, resolver, + devBeanInfos); + } + } + } + } + } + for (BeanInfo producer : declaringToProducers.getOrDefault(bean, Collections.emptyList())) { + links.add(Link.producer(producer.getIdentifier(), bean.getIdentifier())); + if (nodes.add(devBeanInfos.getBean(producer.getIdentifier()))) { + // add transient dependents + addNodesDependents(root, nodes, links, producer, beans, declaringToProducers, resolver, + devBeanInfos); + } + } + } + } diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DependecyGraph.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DependecyGraph.java new file mode 100644 index 0000000000000..4db95124708c6 --- /dev/null +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/devconsole/DependecyGraph.java @@ -0,0 +1,66 @@ +package io.quarkus.arc.deployment.devconsole; + +import java.util.Objects; +import java.util.Set; + +public class DependecyGraph { + + public final Set nodes; + public final Set links; + + public DependecyGraph(Set nodes, Set links) { + this.nodes = nodes; + this.links = links; + } + + public static class Link { + + static Link dependent(boolean direct, String source, String target) { + return new Link(source, target, direct ? "directDependent" : "dependency"); + } + + static Link dependency(boolean direct, String source, String target) { + return new Link(source, target, direct ? "directDependency" : "dependency"); + } + + static Link lookup(String source, String target) { + return new Link(source, target, "lookup"); + } + + static Link producer(String source, String target) { + return new Link(source, target, "producer"); + } + + public final String source; + public final String target; + public final String type; + + public Link(String source, String target, String type) { + this.source = source; + this.target = target; + this.type = type; + } + + @Override + public int hashCode() { + return Objects.hash(source, target); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Link other = (Link) obj; + return Objects.equals(source, other.source) && Objects.equals(target, other.target); + } + + } + +} 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 dc4026c3271ad..ab3087a495852 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 @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import org.jboss.jandex.AnnotationInstance; @@ -70,17 +71,21 @@ 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(bean.getIdentifier(), 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(bean.getIdentifier(), DevBeanKind.SYNTHETIC, false, providerType, null, types, qualifiers, + scope, null, interceptors); } } - public DevBeanInfo(DevBeanKind kind, boolean isApplicationBean, Name providerType, String memberName, Set types, + public DevBeanInfo(String id, DevBeanKind kind, boolean isApplicationBean, Name providerType, String memberName, + Set types, Set qualifiers, Name scope, Name declaringClass, List boundInterceptors) { + this.id = id; this.kind = kind; this.isApplicationBean = isApplicationBean; this.providerType = providerType; @@ -92,6 +97,7 @@ public DevBeanInfo(DevBeanKind kind, boolean isApplicationBean, Name providerTyp this.interceptors = boundInterceptors; } + private final String id; private final DevBeanKind kind; private final boolean isApplicationBean; private final Name providerType; @@ -102,6 +108,10 @@ public DevBeanInfo(DevBeanKind kind, boolean isApplicationBean, Name providerTyp private final Name declaringClass; private final List interceptors; + public String getId() { + return id; + } + public DevBeanKind getKind() { return kind; } @@ -151,6 +161,21 @@ public List getInterceptors() { return interceptors; } + public String getDescription() { + switch (kind) { + case CLASS: + return providerType.toString(); + case FIELD: + return declaringClass.toString() + "#" + memberName; + case METHOD: + return declaringClass.toString() + "#" + memberName + "()"; + case SYNTHETIC: + return "Synthetic: " + providerType.toString(); + default: + return providerType.toString(); + } + } + @Override public int compareTo(DevBeanInfo o) { // Application beans should go first @@ -159,4 +184,25 @@ public int compareTo(DevBeanInfo o) { } return isApplicationBean ? -1 : 1; } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + DevBeanInfo other = (DevBeanInfo) obj; + return Objects.equals(id, other.id); + } + } 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 4f57f68fde20a..8c2238f7e8f9c 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 @@ -2,7 +2,9 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class DevBeanInfos { @@ -13,6 +15,7 @@ public class DevBeanInfos { private final List removedInterceptors; private final List decorators; private final List removedDecorators; + private final Map dependencyGraphs; public DevBeanInfos() { beans = new ArrayList<>(); @@ -22,6 +25,7 @@ public DevBeanInfos() { removedInterceptors = new ArrayList<>(); decorators = new ArrayList<>(); removedDecorators = new ArrayList<>(); + dependencyGraphs = new HashMap<>(); } public List getRemovedBeans() { @@ -52,6 +56,15 @@ public List getRemovedDecorators() { return removedDecorators; } + public DevBeanInfo getBean(String id) { + for (DevBeanInfo bean : beans) { + if (bean.getId().equals(id)) { + return bean; + } + } + return null; + } + public DevInterceptorInfo getInterceptor(String id) { for (DevInterceptorInfo interceptor : interceptors) { if (interceptor.getId().equals(id)) { @@ -61,6 +74,10 @@ public DevInterceptorInfo getInterceptor(String id) { return null; } + public DependecyGraph getDependencyGraph(String beanId) { + return dependencyGraphs.get(beanId); + } + public int getRemovedComponents() { return removedBeans.size() + removedInterceptors.size() + removedDecorators.size(); } @@ -93,6 +110,10 @@ void addRemovedDecorator(DevDecoratorInfo decorator) { removedDecorators.add(decorator); } + void addDependencyGraph(String beanId, DependecyGraph graph) { + dependencyGraphs.put(beanId, graph); + } + void sort() { Collections.sort(beans); Collections.sort(removedBeans); diff --git a/extensions/arc/deployment/src/main/resources/dev-templates/beanDependencyGraph.html b/extensions/arc/deployment/src/main/resources/dev-templates/beanDependencyGraph.html new file mode 100644 index 0000000000000..577922578e285 --- /dev/null +++ b/extensions/arc/deployment/src/main/resources/dev-templates/beanDependencyGraph.html @@ -0,0 +1,175 @@ +{#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; + } + .legend-root { + color: red; + } + ul.legend { + padding: 0px; + } + ul.legend li { + list-style: none; + } + + {/style} + + {#script} + // Bean dependency graph built with d3.js + // Based on https://observablehq.com/@d3/mobile-patent-suits + + const nodes = [ + {#each info:devBeanInfos.getDependencyGraph(currentRequest.getParam('beanId')).nodes} + { id:"{it.id}", kind:"{it.kind}", description:"{it.description}", root:{#if it.id == currentRequest.getParam('beanId')}true{#else}false{/if} }, + {/each} + ]; + const links = [ + {#each info:devBeanInfos.getDependencyGraph(currentRequest.getParam('beanId')).links} + { source:"{it.source}", target:"{it.target}", type:"{it.type}" }, + {/each} + ]; + + const beanId = "{currentRequest.getParam('beanId')}"; + + {| + const types = ['directDependency','directDependent','dependency','lookup','producer']; + const height = 600; + const width = 1200; + const color = d3.scaleOrdinal(types, d3.schemeCategory10); + + // Legend colors + const legendDirectDependency = document.querySelector(".legend-direct-dependency"); + legendDirectDependency.style.color = color('directDependency'); + const legendDirectDependent = document.querySelector(".legend-direct-dependent"); + legendDirectDependent.style.color = color('directDependent'); + const legendDependency = document.querySelector(".legend-dependency"); + legendDependency.style.color = color('dependency'); + const legendLookup = document.querySelector(".legend-lookup"); + legendLookup.style.color = color('lookup'); + const legendProducer = document.querySelector(".legend-producer"); + legendProducer.style.color = color('producer'); + + function linkArc(d) { + const r = Math.hypot(d.target.x - d.source.x, d.target.y - d.source.y); + return ` + M${d.source.x},${d.source.y} + A${r},${r} 0 0,1 ${d.target.x},${d.target.y} + `; + } + + const simulation = d3.forceSimulation(nodes) + .force("link", d3.forceLink(links).id(d => d.id).distance(function(d) { + return d.source.id === beanId || d.target.id === beanId ? 150 : 75; + })) + .force("charge", d3.forceManyBody().strength(-400)) + .force("x", d3.forceX()) + .force("y", d3.forceY()); + + function dragstart(event, d){ + // this line is needed, otherwise the simulation stops after few seconds + if (!event.active) simulation.alphaTarget(0.3).restart(); + d.fx = d.x; + d.fy = d.y; + }; + + function dragged(event, d) { + d.fx = event.x; + d.fy = event.y; + } + + function dragended(event, d) { + d.fx = event.x; + d.fy = event.y; + } + + const svg = d3.select("#beanDepGraph_area") + .attr("viewBox", [-width / 3, -height / 3, width, height]) + .style("font", "12px sans-serif"); + + svg.append("defs").selectAll("marker") + .data(types) + .join("marker") + .attr("id", d => `arrow-${d}`) + .attr("viewBox", "0 -5 10 10") + .attr("refX", 15) + .attr("refY", -0.5) + .attr("markerWidth", 6) + .attr("markerHeight", 6) + .attr("orient", "auto") + .append("path") + .attr("fill", color) + .attr("d", "M0,-5L10,0L0,5"); + + const link = svg.append("g") + .attr("fill", "none") + .attr("stroke-width", 1.5) + .selectAll("path") + .data(links) + .join("path") + .attr("stroke", d => color(d.type)) + .attr("marker-end", d => `url(${new URL(`#arrow-${d.type}`, location)})`); + + const node = svg.append("g") + .attr("fill", "currentColor") + .attr("stroke-linecap", "round") + .attr("stroke-linejoin", "round") + .selectAll("g") + .data(nodes) + .join("g") + .call(d3.drag().on("drag", dragged).on("end", dragended).on("start", dragstart)); + + node.append("circle") + .attr("stroke", "white") + .attr("stroke-width", 1) + .attr("r", 5) + .style("fill", d => d.root ? "red" : "black"); + + node.append("a") + .attr("xlink:href", d => "beanDependencyGraph?beanId=" + d.id) + .append("svg:text") + .attr("x", 8) + .attr("y", "0.31em") + .style("fill", "#1f77b4") + .text(d => d.description); + + simulation.on("tick", () => { + link.attr("d", linkArc); + node.attr("transform", d => `translate(${d.x},${d.y})`); + }); + + |} + + {#breadcrumbs} Beans{/breadcrumbs} + {#title}Bean Dependency Graph{/title} + {#body} + {#set bean=info:devBeanInfos.getBean(currentRequest.getParam('beanId'))} +

Bean Dependency Graph: {bean.description}

+ +
    +
  • root
  • +
  • direct dependencies
  • +
  • direct dependents
  • +
  • dependencies
  • +
  • potential dependency - programmatic lookup
  • +
  • declaring bean of a producer
  • +
+ + + + {/set} + {/body} + + {#scriptref} + + {/scriptref} +{/include} 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 30fed8beb18bb..b556d539b4a98 100644 --- a/extensions/arc/deployment/src/main/resources/dev-templates/beans.html +++ b/extensions/arc/deployment/src/main/resources/dev-templates/beans.html @@ -48,12 +48,13 @@ Bean Kind Associated Interceptors + Actions {#for bean in info:devBeanInfos.beans} - {bean_count}. + {bean_count} {#display-bean bean/} @@ -69,6 +70,11 @@ {/for} + + {#if !info:devBeanInfos.getDependencyGraph(bean.id).links.empty} + + {/if} + {/for} diff --git a/extensions/arc/deployment/src/main/resources/dev-templates/tags/display-bean.html b/extensions/arc/deployment/src/main/resources/dev-templates/tags/display-bean.html index a29c121a90abb..bc864d1bc26c4 100644 --- a/extensions/arc/deployment/src/main/resources/dev-templates/tags/display-bean.html +++ b/extensions/arc/deployment/src/main/resources/dev-templates/tags/display-bean.html @@ -2,4 +2,4 @@ {#for q in it.nonDefaultQualifiers} {q.simpleName}
{/for} -{it.providerType} +{#if it.providerType.toString.length > 70}{it.providerType.toString.substring(0,70)}...{#else}{it.providerType}{/if} diff --git a/extensions/vertx-http/deployment/pom.xml b/extensions/vertx-http/deployment/pom.xml index 6dd2485ef19c1..f7e7012b2f75c 100644 --- a/extensions/vertx-http/deployment/pom.xml +++ b/extensions/vertx-http/deployment/pom.xml @@ -67,6 +67,11 @@ codemirror provided
+ + org.webjars + d3js + provided + io.quarkus @@ -286,6 +291,19 @@ + + + org.webjars + d3js + ${webjar.d3js.version} + jar + true + ${project.build.directory}/classes/dev-static/js/ + **/d3.min.js + + + + diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java index 0c4ce80847a04..03a6a0fc2bc7c 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InjectionPointInfo.java @@ -116,7 +116,7 @@ void resolve(BeanInfo bean) { resolvedBean.set(bean); } - BeanInfo getResolvedBean() { + public BeanInfo getResolvedBean() { return resolvedBean.get(); } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/UnusedBeans.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/UnusedBeans.java index 02014277e44ec..341d4b6feb8e0 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/UnusedBeans.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/UnusedBeans.java @@ -10,9 +10,12 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import org.jboss.logging.Logger; final class UnusedBeans { + private static final Logger LOG = Logger.getLogger(UnusedBeans.class); + private UnusedBeans() { } @@ -38,24 +41,29 @@ static Set findRemovableBeans(Collection beans, Collection exclusion : allUnusedExclusions) { if (exclusion.test(bean)) { + LOG.debugf("Unremovable - excluded by %s: %s", exclusion.toString(), bean); continue test; } } // Is injected if (injected.contains(bean)) { + LOG.debugf("Unremovable - injected: %s", bean); continue test; } // Declares an observer method if (declaresObserver.contains(bean)) { + LOG.debugf("Unremovable - declares observer: %s", bean); continue test; } // Instance @@ -63,7 +71,7 @@ static Set findRemovableBeans(Collection beans, Collection findRemovableBeans(Collection beans, Collection