in knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/OpenWebBeansExtension.java [117:300]
public void execute(final Context context) {
final Properties original = new Properties();
original.putAll(System.getProperties());
try (final SeContainer container = configureInitializer(context, SeContainerInitializer.newInstance()).initialize()) {
final WebBeansContext webBeansContext = WebBeansContext.currentInstance();
final BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl();
final Set<Bean<?>> beans = beanManager.getBeans();
final Collection<javax.enterprise.inject.spi.Interceptor<?>> interceptors = webBeansContext.getInterceptorsManager().getCdiInterceptors();
final Predicate<String> classFilter = context.createIncludesExcludes(
"extension.openwebbeans.classes.filter.", PredicateType.STARTS_WITH);
// 1. capture all proxies
dumpProxies(context, webBeansContext, beans, classFilter);
// 2. register all classes which will require reflection + proxies
final String beanClassesList = registerBeansForReflection(context, beans, classFilter, interceptors);
getProxies(webBeansContext).keySet().stream()
.filter(classFilter)
.flatMap(it -> {
try {
return hierarchy(context.loadClass(it))
.map(Class::getName);
} catch (final RuntimeException re) {
return Stream.of(it);
}
})
.sorted()
.forEach(name -> {
final ClassReflectionModel model = new ClassReflectionModel();
model.setName(name);
model.setAllDeclaredConstructors(true);
model.setAllDeclaredFields(true);
model.setAllDeclaredMethods(true);
context.register(model);
});
// 3. dump owb properties for runtime
final Properties properties = initProperties(context, webBeansContext.getOpenWebBeansConfiguration(), beanClassesList);
// 4. register CDI/OWB API which require some reflection
// 4.1 SPI (interface)
Stream.of(
ScannerService.class, LoaderService.class, BeanArchiveService.class, SecurityService.class,
ContainerLifecycle.class, JNDIService.class, ApplicationBoundaryService.class, ContextsService.class,
InjectionPointService.class, ResourceInjectionService.class, DefiningClassService.class,
Filter.class)
.forEach(clazz -> {
final ClassReflectionModel model = new ClassReflectionModel();
model.setName(clazz.getName());
model.setAllPublicMethods(true);
context.register(model);
});
// 4.2 classes which must be instantiable
Stream.concat(Stream.of(
ClassLoaderProxyService.LoadOnly.class, StandaloneLifeCycle.class, StandaloneContextsService.class,
DefaultLoaderService.class, InjectionPointImpl.class, ConversationImpl.class, SimpleApplicationBoundaryService.class,
ApplicationScopedBeanInterceptorHandler.class, RequestScopedBeanInterceptorHandler.class,
SessionScopedBeanInterceptorHandler.class, NormalScopedBeanInterceptorHandler.class,
CDISeScannerService.class, PreScannedCDISeScannerService.class, DefaultScannerService.class),
findServices(properties))
.distinct()
.forEach(clazz -> {
final ClassReflectionModel model = new ClassReflectionModel();
model.setName(clazz.getName());
model.setAllDeclaredConstructors(true);
context.register(model);
});
// 4.3 needed by prescanned scanner
final ClassReflectionModel owbFinder = new ClassReflectionModel();
owbFinder.setName(AnnotationFinder.class.getName());
final ClassReflectionModel.FieldReflectionModel owbFinderLinking = new ClassReflectionModel.FieldReflectionModel();
owbFinderLinking.setAllowWrite(true);
owbFinderLinking.setName("linking");
owbFinder.setFields(singletonList(owbFinderLinking));
context.register(owbFinder);
// 5 annotations
final Collection<Class<?>> customAnnotations = Stream.concat(
context.findAnnotatedClasses(Qualifier.class).stream(),
context.findAnnotatedClasses(NormalScope.class).stream())
.collect(toList());
Stream.concat(Stream.concat(Stream.of(
Initialized.class, Destroyed.class, NormalScope.class, ApplicationScoped.class, Default.class,
Dependent.class, ConversationScoped.class, RequestScoped.class, Observes.class, ObservesAsync.class,
Qualifier.class, InterceptorBinding.class, Priority.class),
beanManager.getAdditionalQualifiers().stream()),
customAnnotations.stream())
.distinct()
.map(Class::getName)
.sorted()
.forEach(clazz -> {
final ClassReflectionModel model = new ClassReflectionModel();
model.setName(clazz);
model.setAllDeclaredMethods(true);
context.register(model);
});
customAnnotations.stream() // DefaultAnnotation.of
.filter(it -> !it.getName().startsWith("javax.") && !it.getName().startsWith("jakarta."))
.map(Class::getName)
.sorted()
.map(it -> {
final DynamicProxyModel proxyModel = new DynamicProxyModel();
proxyModel.setClasses(singleton(it));
return proxyModel;
})
.forEach(context::register);
// 6 extensions - normally taken by graalvm service loader but we need a bit more reflection
final ExtensionLoader extensionLoader = webBeansContext.getExtensionLoader();
try {
final Field extensionClasses = ExtensionLoader.class.getDeclaredField("extensionClasses");
if (!extensionClasses.isAccessible()) {
extensionClasses.setAccessible(true);
}
final Predicate<String> extensionFilter = context.createPredicate("extension.openwebbeans.extension.excludes", PredicateType.STARTS_WITH)
.map(Predicate::negate)
.orElseGet(() -> n -> true);
final Set<Class<?>> classes = (Set<Class<?>>) extensionClasses.get(extensionLoader);
classes.stream()
.filter(it -> extensionFilter.test(it.getName()))
.flatMap(this::hierarchy)
.distinct()
.map(Class::getName)
.filter(classFilter)
.sorted()
.forEach(clazz -> {
final ClassReflectionModel model = new ClassReflectionModel();
model.setName(clazz);
model.setAllDeclaredConstructors(true);
model.setAllDeclaredMethods(true);
model.setAllDeclaredMethods(true);
context.register(model);
});
} catch (final NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException("Incompatible OpenWebBeans version", e);
}
// 7. producer types must be reflection friendly
findProducedClasses(beans)
.map(Class::getName)
.sorted()
.forEach(name -> {
final ClassReflectionModel model = new ClassReflectionModel();
model.setName(name);
model.setAllDeclaredConstructors(true);
model.setAllDeclaredFields(true);
model.setAllDeclaredMethods(true);
context.register(model);
});
// 8. enforce some build time init for annotations and some specific classes
context.initializeAtBuildTime(
Reception.class.getName(),
TransactionPhase.class.getName(),
DefaultSingletonService.class.getName(),
WebBeansLoggerFacade.class.getName());
try { // openwebbeans-slf4j is an optional module
final Class<?> logger = context.loadClass("org.apache.openwebbeans.slf4j.Slf4jLogger");
context.initializeAtBuildTime(logger.getName());
} catch (final RuntimeException e) {
// ignore, not there
}
// 9. we add the resource bundle + the bundle as resource for some extensions (thank you JUL)
context.includeResourceBundle("openwebbeans/Messages");
final ResourceModel resourceModel = new ResourceModel();
resourceModel.setPattern("openwebbeans/Messages\\.properties");
context.register(resourceModel);
// 10. OWB creates proxies on TypeVariable (generics checks) so enable it
final DynamicProxyModel typeVariableProxyModel = new DynamicProxyModel();
typeVariableProxyModel.setClasses(singleton(TypeVariable.class.getName()));
context.register(typeVariableProxyModel);
// 11. interceptor bindings
context.findAnnotatedClasses(InterceptorBinding.class).forEach(clazz -> {
final ClassReflectionModel model = new ClassReflectionModel();
model.setName(clazz.getName());
model.setAllPublicMethods(true);
context.register(model);
});
} finally {
System.setProperties(original);
}
}