EnsureCollectedClassesAreBeansBuildStepProcessor.java
package io.vanillabp.integration.deployment.validation;
import java.util.List;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem;
import io.quarkus.arc.deployment.ValidationPhaseBuildItem;
import io.quarkus.arc.deployment.ValidationPhaseBuildItem.ValidationErrorBuildItem;
import io.quarkus.arc.processor.BeanInfo;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
public class EnsureCollectedClassesAreBeansBuildStepProcessor {
@BuildStep
void ensureCollectedClassesAreBeans(
final BeanRegistrationPhaseBuildItem beanRegistrationPhase,
final List<EnsureClassIsBeanValidationBuildItem> classIsBeanValidationBuildItems,
final BuildProducer<ValidationErrorBuildItem> validationErrors) {
final var index = beanRegistrationPhase
.getBeanProcessor()
.getBeanDeployment()
.getBeanArchiveIndex();
final var beans = beanRegistrationPhase
.getContext()
.beans()
.stream()
.toList();
classIsBeanValidationBuildItems
.forEach(buildItem -> {
final var requiredType = buildItem.getClassName();
final var found = beans.stream()
.anyMatch(bean -> isBeanAssignableTo(bean, requiredType, index));
if (!found) {
validationErrors.produce(new ValidationPhaseBuildItem.ValidationErrorBuildItem(
new IllegalStateException(
"""
Class
%s
was found by the VanillaBP extension as a
%s
but neither the class itself nor any implementation is a CDI bean.
Please annotate it with a bean-defining annotation such as @ApplicationScoped."""
.formatted(buildItem.getClassName(), buildItem.getUsageDescription()))));
}
});
}
private boolean isBeanAssignableTo(
final BeanInfo bean,
final DotName requiredType,
final IndexView index) {
final var beanClass = bean.getBeanClass();
if (beanClass.equals(requiredType)) {
return true;
}
final var classInfo = index.getClassByName(beanClass);
if (classInfo == null) {
return false;
}
// Interfaces prüfen
for (final var iface : classInfo.interfaceNames()) {
if (iface.equals(requiredType)) {
return true;
}
if (isAssignableViaHierarchy(iface, requiredType, index)) {
return true;
}
}
// Superklasse prüfen
final var superClass = classInfo.superName();
return superClass != null && isAssignableViaHierarchy(superClass, requiredType, index);
}
private boolean isAssignableViaHierarchy(
final DotName current,
final DotName target,
final IndexView index) {
if (current.equals(target)) {
return true;
}
final var info = index.getClassByName(current);
if (info == null) {
return false;
}
for (final var iface : info.interfaceNames()) {
if (isAssignableViaHierarchy(iface, target, index)) {
return true;
}
}
final var superClass = info.superName();
return superClass != null && isAssignableViaHierarchy(superClass, target, index);
}
}