[GERONIMO-6796] OpenWebBeans integration
diff --git a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java
index 106367c..c8a6b3f 100644
--- a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java
+++ b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java
@@ -16,10 +16,13 @@
  */
 package org.apache.geronimo.arthur.impl.nativeimage.generator;
 
-import static java.util.Collections.singletonList;
-import static java.util.Optional.ofNullable;
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.Collectors.toSet;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.geronimo.arthur.impl.nativeimage.ArthurNativeImageConfiguration;
+import org.apache.geronimo.arthur.spi.ArthurExtension;
+import org.apache.geronimo.arthur.spi.model.ClassReflectionModel;
+import org.apache.geronimo.arthur.spi.model.DynamicProxyModel;
+import org.apache.geronimo.arthur.spi.model.ResourcesModel;
 
 import java.io.IOException;
 import java.io.Writer;
@@ -30,6 +33,7 @@
 import java.nio.file.StandardOpenOption;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -38,13 +42,12 @@
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
-import org.apache.geronimo.arthur.impl.nativeimage.ArthurNativeImageConfiguration;
-import org.apache.geronimo.arthur.spi.ArthurExtension;
-import org.apache.geronimo.arthur.spi.model.DynamicProxyModel;
-import org.apache.geronimo.arthur.spi.model.ResourcesModel;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
+import static java.util.Collections.singletonList;
+import static java.util.Comparator.comparing;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
 
 @Slf4j
 @RequiredArgsConstructor
@@ -103,7 +106,14 @@
             log.info("Creating reflection model '{}'", json);
             try (final Writer writer = Files.newBufferedWriter(
                     json, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
-                jsonSerializer.accept(context.getReflections(), writer);
+                jsonSerializer.accept(
+                        context.getReflections().stream()
+                                .collect(groupingBy(ClassReflectionModel::getName))
+                                .values().stream()
+                                .map(this::merge)
+                                .sorted(comparing(ClassReflectionModel::getName))
+                                .collect(toList()),
+                        writer);
             }
             context.addReflectionConfigFile(json.toAbsolutePath().toString());
         }
@@ -167,6 +177,39 @@
         }
     }
 
+    private ClassReflectionModel merge(final List<ClassReflectionModel> classReflectionModels) {
+        final Iterator<ClassReflectionModel> modelIterator = classReflectionModels.iterator();
+        final ClassReflectionModel model = modelIterator.next();
+        while (modelIterator.hasNext()) {
+            final ClassReflectionModel next = modelIterator.next();
+            if (next.getAllDeclaredClasses()) {
+                model.setAllDeclaredClasses(true);
+            }
+            if (next.getAllDeclaredFields()) {
+                model.setAllDeclaredFields(true);
+            }
+            if (next.getAllDeclaredConstructors()) {
+                model.setAllDeclaredConstructors(true);
+            }
+            if (next.getAllDeclaredMethods()) {
+                model.setAllDeclaredMethods(true);
+            }
+            if (next.getAllPublicMethods()) {
+                model.setAllPublicMethods(true);
+            }
+            if (next.getAllPublicFields()) {
+                model.setAllPublicFields(true);
+            }
+            if (next.getAllPublicConstructors()) {
+                model.setAllPublicConstructors(true);
+            }
+            if (next.getAllPublicClasses()) {
+                model.setAllPublicClasses(true);
+            }
+        }
+        return model;
+    }
+
     private void ensureWorkingDirectoryExists() throws IOException {
         if (!Files.exists(workingDirectory)) {
             Files.createDirectories(workingDirectory);
diff --git a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java
index 6eb8f29..01dc457 100644
--- a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java
+++ b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java
@@ -19,6 +19,7 @@
 import static java.util.Arrays.asList;
 import static java.util.Optional.of;
 import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toList;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
@@ -119,7 +120,9 @@
         if (configuration.getInitializeAtBuildTime() == null) {
             configuration.setInitializeAtBuildTime(new ArrayList<>());
         }
-        configuration.getInitializeAtBuildTime().addAll(asList(classes));
+        configuration.getInitializeAtBuildTime().addAll(Stream.of(classes)
+                .filter(it -> !configuration.getInitializeAtBuildTime().contains(it))
+                .collect(toList()));
     }
 
     @Override
@@ -156,7 +159,8 @@
 
     @Override
     public Optional<Predicate<String>> createPredicate(final String property, final ArthurExtension.PredicateType type) {
-        return ofNullable(getProperty(property)).flatMap(ex -> Stream.of(ex.split(","))
+        return ofNullable(getProperty(property))
+                .flatMap(ex -> Stream.of(ex.split(","))
                 .map(String::trim)
                 .filter(it -> !it.isEmpty())
                 .map(it -> of((Predicate<String>) n -> type.test(it, n)))
diff --git a/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/ArthurMojo.java b/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/ArthurMojo.java
index 89f08c6..669a78d 100644
--- a/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/ArthurMojo.java
+++ b/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/ArthurMojo.java
@@ -180,8 +180,6 @@
     }
 
     private String buildDownloadUrl(final String graalPlatform) {
-        // defaultValue = "https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${graalSimpleVersion}/graalvm-ce-java${graalJavaVersion}-${githubPlatform}-${graalSimpleVersion}.tar.gz")
-        //            // defaultValue = "https://api.sdkman.io/2/broker/download/java/${graalVersion}-grl/${platform}")
         if (graalDownloadUrl.startsWith("https://api.sdkman.io/2/broker/download/java/")) {
             return graalDownloadUrl
                     .replace("${graalVersion}", graalVersion)
@@ -213,11 +211,4 @@
                         .orElseGet(() -> System.getProperty("os.arch", "64").replace("amd", "")))
                 .toLowerCase(ROOT);
     }
-
-    public static void main(String[] args) {
-        System.out.println((System.getProperty("os.name", "linux") +
-                ofNullable(System.getProperty("sun.arch.data.model"))
-                        .orElseGet(() -> System.getProperty("os.arch", "64").replace("amd", "")))
-                .toLowerCase(ROOT));
-    }
 }
diff --git a/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/NativeImageMojo.java b/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/NativeImageMojo.java
index 18bd42f..30dc0ee 100644
--- a/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/NativeImageMojo.java
+++ b/arthur-maven-plugin/src/main/java/org/apache/geronimo/arthur/maven/mojo/NativeImageMojo.java
@@ -38,6 +38,7 @@
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -63,7 +64,6 @@
 import org.apache.geronimo.arthur.spi.model.ResourceBundleModel;
 import org.apache.geronimo.arthur.spi.model.ResourceModel;
 import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.DefaultArtifact;
 import org.apache.maven.artifact.handler.DefaultArtifactHandler;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.plugins.annotations.Component;
@@ -440,6 +440,7 @@
                                     .jsonSerializer(jsonb::toJson)
                                     .annotatedClassFinder(finder::findAnnotatedClasses)
                                     .annotatedMethodFinder(finder::findAnnotatedMethods)
+                                    .extensionProperties(getExtensionProperties())
                                     .implementationFinder(p -> {
                                         if (finderLinked.compareAndSet(false, true)) {
                                             finder.enableFindImplementations().enableFindSubclasses();
@@ -489,6 +490,12 @@
         }
     }
 
+    private Map<String, String> getExtensionProperties() {
+        final Map<String, String> props = extensionProperties == null ? new HashMap<>() : new HashMap<>(extensionProperties);
+        props.putIfAbsent("classes", project.getBuild().getOutputDirectory());
+        return props;
+    }
+
     private Predicate<Artifact> createScanningFilter() {
         if (scanningExcludedArtifacts != null && scanningExcludedArtifacts.contains("*")) {
             return a -> false;
diff --git a/documentation/src/content/knights.adoc b/documentation/src/content/knights.adoc
index f9a09ef..e276d79 100644
--- a/documentation/src/content/knights.adoc
+++ b/documentation/src/content/knights.adoc
@@ -22,6 +22,8 @@
 == Available knights
 
 - link:jsch-knight.html[JSch]: it contains some end user API integrated with built-in extensions to simplify application graal-ification,
+- link:winegrower-knight.html[Winegrower]: Apache winegrower (Cloud OSGi runtime) support.
+- link:openwebbeans-knight.html[OpenWebBeans]: Apache OpenWebBeans (CDI SE runtime) support.
 
 == Configure a Knight in Arthur Maven plugin
 
diff --git a/documentation/src/content/openwebbeans-knight.adoc b/documentation/src/content/openwebbeans-knight.adoc
new file mode 100644
index 0000000..468a677
--- /dev/null
+++ b/documentation/src/content/openwebbeans-knight.adoc
@@ -0,0 +1,121 @@
+////
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+////
+= Arthur OpenWebBeans Knights
+
+Arthur OpenWebBeans knight is responsible to support Apache OpenWebBeans.
+It preconfigures the most of the reflection and resource inclusion.
+
+It assumes you use `openwebbeans-se` in your project.
+Here is a sample dependencies block for a simple SCR application:
+
+[source,xml]
+----
+<dependencies>
+  <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jcdi_2.0_spec</artifactId>
+      <version>1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-el_2.2_spec</artifactId>
+      <version>1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-annotation_1.3_spec</artifactId>
+      <version>1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-atinject_1.0_spec</artifactId>
+      <version>1.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-interceptor_1.2_spec</artifactId>
+      <version>1.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openwebbeans</groupId>
+      <artifactId>openwebbeans-se</artifactId>
+      <version>2.0.21</version>
+    </dependency>
+</dependencies>
+----
+
+IMPORTANT: this only works out of the box with OpenWebBeans 2.0.21 or later. You'll need to tune the scanner service yourself for older versions.
+
+== Coordinates
+
+[source,xml]
+----
+<dependency>
+  <groupId>org.apache.geronimo.arthur.knights</groupId>
+  <artifactId>openwebbeans-knight</artifactId>
+  <version>${arthur.version}</version>
+</dependency>
+----
+
+== Usage
+
+To make a CDI application compatible with `native-image` there are a few necessary steps to do:
+
+. Generate all CDI proxies (normal scope beans, intercepted/decorated beans)
+. Include the proxies in the final image
+. Include OpenWebBeans log resource bundle
+. Register bean classes for reflection
+
+The `openwebbeans-knight` handles most of that even if you can need to tune a few details in the Arthur configuration.
+
+
+Finally, you must register the openwebbeans knight in `arthur-maven-plugin`:
+
+
+[source,xml]
+----
+<plugin>
+  <groupId>org.apache.geronimo.arthur</groupId>
+  <artifactId>arthur-maven-plugin</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <configuration>
+    <main>org.company.osgi.ScrMain</main>
+    <graalExtensions>
+      <graalExtension>openwebbeans</graalExtension>
+    </graalExtensions>
+  </configuration>
+</plugin>
+----
+
+== Configuration
+
+This knight has several configuration options:
+
+[opts="header",role="table table-bordered",cols="2,1,3"]
+|===
+|Name|Type|Description
+a|`extension.openwebbeans.classes.filter.[includes\|excludes]`|String|Comma separated values for scanning filter (packages).
+a|`extension.openwebbeans.classes.includeAsResources`|boolean|Should classes be included as resources (.class) too.
+a|`extension.openwebbeans.container.se.disableDiscovery`|boolean|Should CDI SE container auto discover the beans or not.
+a|`extension.openwebbeans.container.se.properties`|Properties|CDI SE properties.
+a|`extension.openwebbeans.container.se.services`|Properties|OpenWebBeans services as properties (SPI=IMPL).
+a|`extension.openwebbeans.container.se.classes`|String list|Bean classes to register.
+|===
+
+---
+
+Previous: link:knights.html[Knights]
diff --git a/integration-test/pom.xml b/integration-test/pom.xml
index f59c179..c0b443d 100644
--- a/integration-test/pom.xml
+++ b/integration-test/pom.xml
@@ -60,7 +60,7 @@
       <scope>test</scope>
     </dependency>
 
-    <!-- just for the reactor -->
+    <!-- just for the reactor ordering -->
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>arthur-maven-plugin</artifactId>
@@ -85,6 +85,12 @@
       <version>${project.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}.knights</groupId>
+      <artifactId>openwebbeans-knight</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java b/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java
index 65cab08..8b7c780 100644
--- a/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java
+++ b/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java
@@ -46,6 +46,9 @@
     @Spec(expectedOutput = "Cui-yère")
     void cuilliere() {}
 
+    @Test
+    @Spec(expectedOutput = "counter=1, from proxy=from proxy")
+    void owb() {}
 
     @Test
     @Spec(expectedOutput = "Starting org.apache.geronimo.arthur.integrationtests.Application")
diff --git a/integration-test/src/test/resources/integration-tests/owb/pom.xml b/integration-test/src/test/resources/integration-tests/owb/pom.xml
new file mode 100644
index 0000000..ff66334
--- /dev/null
+++ b/integration-test/src/test/resources/integration-tests/owb/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="
+            http://maven.apache.org/POM/4.0.0
+            http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>21</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.geronimo.arthur.integrationtests</groupId>
+  <artifactId>owb</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>Arthur :: Integration Tests :: OWB</name>
+
+  <!-- not important to not reuse build versions, should be stable -->
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jcdi_2.0_spec</artifactId>
+      <version>1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-el_2.2_spec</artifactId>
+      <version>1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-annotation_1.3_spec</artifactId>
+      <version>1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-atinject_1.0_spec</artifactId>
+      <version>1.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-interceptor_1.2_spec</artifactId>
+      <version>1.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openwebbeans</groupId>
+      <artifactId>openwebbeans-se</artifactId>
+      <version>2.0.21-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>${maven-compiler-plugin.version}</version>
+        <configuration>
+          <source>${maven.compiler.source}</source>
+          <target>${maven.compiler.target}</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.geronimo.arthur</groupId>
+        <artifactId>arthur-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <configuration>
+          <main>org.apache.geronimo.arthur.integrationtests.OWB</main>
+          <graalExtensions>
+            <graalExtension>openwebbeans</graalExtension>
+          </graalExtensions>
+          <graalCacheGav>org.apache.geronimo.arthur.cache:graal-integrationtests</graalCacheGav>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/integration-test/src/test/resources/integration-tests/owb/src/main/java/org/apache/geronimo/arthur/integrationtests/OWB.java b/integration-test/src/test/resources/integration-tests/owb/src/main/java/org/apache/geronimo/arthur/integrationtests/OWB.java
new file mode 100644
index 0000000..4ac5456
--- /dev/null
+++ b/integration-test/src/test/resources/integration-tests/owb/src/main/java/org/apache/geronimo/arthur/integrationtests/OWB.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.integrationtests;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Initialized;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.se.SeContainer;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public final class OWB {
+    private OWB() {
+        // noop
+    }
+
+    public static void main(final String[] args) throws IOException {
+        Logger.getLogger("org.apache").setLevel(Level.WARNING);
+        try (final SeContainer container = SeContainerInitializer.newInstance().initialize()) {
+            // starter is launched automatically
+            final int counter = container.select(Starter.class).get().getCounter();
+            if (counter != 1) {
+                throw new IllegalStateException("Starter didn't start: " + counter);
+            }
+
+            final Proxied proxied = container.select(Proxied.class).get();
+            final String proxyValue = proxied.getAnything();
+            if (!"from proxy".equals(proxyValue)) {
+                throw new IllegalStateException(proxied + ": " + proxyValue);
+            }
+            System.out.println("counter=" + counter + ", from proxy=" + proxyValue);
+        }
+    }
+
+    private static void setIfMissing(final String key, final String value) {
+        System.setProperty(key, System.getProperty(key, value));
+    }
+
+    @ApplicationScoped
+    public static class Starter {
+        private int counter = 0;
+
+        public int getCounter() {
+            return counter;
+        }
+
+        public void onStart(@Observes @Initialized(ApplicationScoped.class) final Object start,
+                            final Proxied proxied) {
+            counter++;
+            Logger.getLogger(getClass().getName() + // who
+                    " started: proxy_class=" + proxied.getClass().getName() + ", " + // uses proxy class
+                    proxied.getAnything()); // proxy works
+        }
+    }
+
+    @ApplicationScoped
+    public static class Proxied {
+        public String getAnything() {
+            return "from proxy";
+        }
+    }
+}
diff --git a/knights/openwebbeans-knight/pom.xml b/knights/openwebbeans-knight/pom.xml
index c38b978..6c3482c 100644
--- a/knights/openwebbeans-knight/pom.xml
+++ b/knights/openwebbeans-knight/pom.xml
@@ -69,7 +69,7 @@
     <dependency>
       <groupId>org.apache.openwebbeans</groupId>
       <artifactId>openwebbeans-se</artifactId>
-      <version>2.0.20</version>
+      <version>2.0.21-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>org.graalvm.nativeimage</groupId>
diff --git a/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/OpenWebBeansExtension.java b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/OpenWebBeansExtension.java
index 61ef51e..68484bb 100644
--- a/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/OpenWebBeansExtension.java
+++ b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/OpenWebBeansExtension.java
@@ -16,11 +16,357 @@
  */
 package org.apache.geronimo.arthur.knight.openwebbeans;
 
+import lombok.extern.slf4j.Slf4j;
 import org.apache.geronimo.arthur.spi.ArthurExtension;
+import org.apache.geronimo.arthur.spi.model.ClassReflectionModel;
+import org.apache.geronimo.arthur.spi.model.ResourceModel;
+import org.apache.openwebbeans.se.CDISeScannerService;
+import org.apache.openwebbeans.se.PreScannedCDISeScannerService;
+import org.apache.webbeans.component.InjectionTargetBean;
+import org.apache.webbeans.component.ManagedBean;
+import org.apache.webbeans.config.OpenWebBeansConfiguration;
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.container.BeanManagerImpl;
+import org.apache.webbeans.conversation.ConversationImpl;
+import org.apache.webbeans.corespi.DefaultSingletonService;
+import org.apache.webbeans.corespi.se.DefaultScannerService;
+import org.apache.webbeans.corespi.se.SimpleApplicationBoundaryService;
+import org.apache.webbeans.corespi.se.StandaloneContextsService;
+import org.apache.webbeans.inject.impl.InjectionPointImpl;
+import org.apache.webbeans.intercept.ApplicationScopedBeanInterceptorHandler;
+import org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler;
+import org.apache.webbeans.intercept.RequestScopedBeanInterceptorHandler;
+import org.apache.webbeans.intercept.SessionScopedBeanInterceptorHandler;
+import org.apache.webbeans.lifecycle.StandaloneLifeCycle;
+import org.apache.webbeans.logger.WebBeansLoggerFacade;
+import org.apache.webbeans.service.ClassLoaderProxyService;
+import org.apache.webbeans.service.DefaultLoaderService;
+import org.apache.webbeans.spi.ApplicationBoundaryService;
+import org.apache.webbeans.spi.BeanArchiveService;
+import org.apache.webbeans.spi.ContainerLifecycle;
+import org.apache.webbeans.spi.ContextsService;
+import org.apache.webbeans.spi.DefiningClassService;
+import org.apache.webbeans.spi.InjectionPointService;
+import org.apache.webbeans.spi.JNDIService;
+import org.apache.webbeans.spi.LoaderService;
+import org.apache.webbeans.spi.ResourceInjectionService;
+import org.apache.webbeans.spi.ScannerService;
+import org.apache.webbeans.spi.SecurityService;
+import org.apache.xbean.finder.filter.Filter;
 
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.ConversationScoped;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.Destroyed;
+import javax.enterprise.context.Initialized;
+import javax.enterprise.context.NormalScope;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Observes;
+import javax.enterprise.event.ObservesAsync;
+import javax.enterprise.event.Reception;
+import javax.enterprise.event.TransactionPhase;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.se.SeContainer;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import javax.enterprise.inject.spi.Bean;
+import javax.inject.Qualifier;
+import javax.interceptor.InterceptorBinding;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static java.util.Objects.requireNonNull;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.joining;
+
+@Slf4j
 public class OpenWebBeansExtension implements ArthurExtension {
     @Override
     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();
 
+            // 1. capture all proxies
+            dumpProxies(context, webBeansContext, beans);
+
+            // 2. register all classes which will require reflection + proxies
+            final String beanClassesList = registerBeansForReflection(context, beans);
+            getProxies(webBeansContext).keySet().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.LoadFirst.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 annotations
+            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),
+                    beanManager.getAdditionalQualifiers().stream()),
+                    Stream.concat(
+                            context.findAnnotatedClasses(Qualifier.class).stream(),
+                            context.findAnnotatedClasses(NormalScope.class).stream()))
+                    .distinct()
+                    .forEach(clazz -> {
+                        final ClassReflectionModel model = new ClassReflectionModel();
+                        model.setName(clazz.getName());
+                        model.setAllDeclaredMethods(true);
+                        context.register(model);
+                    });
+
+            // 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());
+
+            // we add the resource bundle in the feature not here
+        } finally {
+            System.setProperties(original);
+        }
+    }
+
+    private Stream<? extends Class<?>> findServices(final Properties properties) {
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        return properties.stringPropertyNames().stream()
+                .filter(it -> it.startsWith("org.apache.webbeans.spi.") || it.equals(Filter.class.getName()))
+                .map(properties::getProperty)
+                .map(it -> {
+                    try {
+                        return loader.loadClass(it);
+                    } catch (final ClassNotFoundException e) {
+                        if (it.contains(".")) {
+                            log.warn(e.getMessage(), e);
+                        } // else can be "false" so just ignore
+                        return null;
+                    }
+                })
+                .filter(Objects::nonNull);
+    }
+
+    private String registerBeansForReflection(final Context context, final Set<Bean<?>> beans) {
+        final Predicate<String> classFilter = context.createIncludesExcludes("extension.openwebbeans.classes.filter.", PredicateType.STARTS_WITH);
+        final boolean includeClassResources = Boolean.parseBoolean(context.getProperty("extension.openwebbeans.classes.includeAsResources"));
+        return beans.stream()
+                .filter(ManagedBean.class::isInstance)
+                .map(Bean::getBeanClass)
+                .flatMap(this::hierarchy)
+                .distinct()
+                .map(Class::getName)
+                .filter(classFilter)
+                .sorted()
+                .peek(clazz -> {
+                    final ClassReflectionModel model = new ClassReflectionModel();
+                    model.setName(clazz);
+                    model.setAllDeclaredConstructors(true);
+                    model.setAllDeclaredMethods(true);
+                    model.setAllDeclaredFields(true);
+                    context.register(model);
+
+                    if (includeClassResources) {
+                        final ResourceModel resourceModel = new ResourceModel();
+                        resourceModel.setPattern(Pattern.quote(clazz.replace('.', '/') + ".class"));
+                        context.register(resourceModel);
+                    }
+                })
+                .collect(joining(","));
+    }
+
+    private void dumpProxies(final Context context, final WebBeansContext webBeansContext, final Set<Bean<?>> beans) {
+        // interceptors/decorators
+        beans.stream()
+                .filter(InjectionTargetBean.class::isInstance)
+                .map(InjectionTargetBean.class::cast)
+                .forEach(InjectionTargetBean::defineInterceptorsIfNeeded);
+        // normal scope
+        beans.stream()
+                .filter(it -> webBeansContext.getBeanManagerImpl().isNormalScope(it.getScope()))
+                .forEach(webBeansContext.getNormalScopeProxyFactory()::createNormalScopeProxy);
+
+        final Map<String, byte[]> proxies = getProxies(webBeansContext);
+        log.debug("Proxies: {}", proxies.keySet());
+        if (proxies.isEmpty()) {
+            log.info("No proxy found for this application");
+        } else {
+            proxies.forEach((className, bytes) -> {
+                context.registerGeneratedClass(className, bytes);
+                log.info("Registered proxy '{}'", className);
+            });
+        }
+    }
+
+    private Map<String, byte[]> getProxies(final WebBeansContext webBeansContext) {
+        return ClassLoaderProxyService.Spy.class.cast(webBeansContext.getService(DefiningClassService.class)).getProxies();
+    }
+
+    private Stream<Class<?>> hierarchy(final Class<?> it) {
+        return it == null || it == Object.class ?
+                Stream.empty() :
+                Stream.concat(Stream.of(it), hierarchy(it.getSuperclass()));
+    }
+
+    private Properties initProperties(final Context context, final OpenWebBeansConfiguration configuration,
+                                      final String beanClassesList) {
+        try {
+            final Field field = OpenWebBeansConfiguration.class.getDeclaredField("configProperties");
+            field.setAccessible(true);
+
+            final Properties properties = Properties.class.cast(field.get(configuration));
+            enrichProperties(properties, true);
+            if (!Boolean.parseBoolean(context.getProperty("extension.openwebbeans.services.ignoreScannerService"))) {
+                properties.put("org.apache.webbeans.spi.ScannerService", "org.apache.openwebbeans.se.PreScannedCDISeScannerService");
+            }
+            properties.putIfAbsent("org.apache.openwebbeans.se.PreScannedCDISeScannerService.classes", beanClassesList);
+
+            properties.remove("config.ordinal"); // no more needed since it will be unique
+            final StringWriter writer = new StringWriter();
+            try (final StringWriter w = writer) {
+                properties.store(w, "Generated by Geronimo Arthur");
+            }
+
+            final Path workDir = Paths.get(requireNonNull(context.getProperty("workingDirectory"), "workingDirectory property"));
+            context.addNativeImageOption("-H:OpenWebBeansProperties=" +
+                    dump(workDir, "openwebbeans.properties", writer.toString().replaceAll("(?m)^#.*", "")));
+            return properties;
+        } catch (final Exception e) {
+            throw new IllegalStateException("Incompatible OWB version", e);
+        }
+    }
+
+    private void enrichProperties(final Properties properties, final boolean runtime) {
+        properties.setProperty("config.ordinal", "10000");
+
+        properties.setProperty("org.apache.webbeans.proxy.useStaticNames", "true");
+        properties.setProperty("org.apache.webbeans.proxy.staticNames.useXxHash64", "true");
+
+        properties.setProperty("org.apache.webbeans.spi.DefiningClassService", runtime ?
+                "org.apache.webbeans.service.ClassLoaderProxyService$LoadFirst" :
+                "org.apache.webbeans.service.ClassLoaderProxyService$Spy");
+        properties.setProperty("org.apache.webbeans.spi.ApplicationBoundaryService",
+                "org.apache.webbeans.corespi.se.SimpleApplicationBoundaryService");
+    }
+
+    private SeContainerInitializer configureInitializer(final Context context, final SeContainerInitializer initializer) {
+        final Properties config = new Properties();
+        enrichProperties(config, false); // before starting ensure we use a deterministic proxy generation config
+        config.stringPropertyNames().forEach(k -> initializer.addProperty(k, config.getProperty(k)));
+
+        if (Boolean.getBoolean(context.getProperty("extension.openwebbeans.container.se.disableDiscovery"))) {
+            initializer.disableDiscovery();
+        }
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        initializer.setClassLoader(loader);
+        ofNullable(context.getProperty("extension.openwebbeans.container.se.properties"))
+                .ifPresent(props -> {
+                    final Properties properties = readProps(props);
+                    properties.stringPropertyNames().forEach(k -> initializer.addProperty(k, properties.getProperty(k)));
+                });
+        ofNullable(context.getProperty("extension.openwebbeans.container.se.services"))
+                .ifPresent(props -> {
+                    final Properties properties = readProps(props);
+                    properties.stringPropertyNames().forEach(k -> {
+                        try {
+                            initializer.addProperty(k, loader.loadClass(properties.getProperty(k).trim()));
+                        } catch (final ClassNotFoundException e) {
+                            throw new IllegalArgumentException(e);
+                        }
+                    });
+                });
+        ofNullable(context.getProperty("extension.openwebbeans.container.se.classes"))
+                .ifPresent(classes -> initializer.addBeanClasses(Stream.of(classes.split(","))
+                        .map(String::trim)
+                        .filter(it -> !it.isEmpty())
+                        .map(it -> {
+                            try {
+                                return loader.loadClass(it);
+                            } catch (final ClassNotFoundException e) {
+                                throw new IllegalArgumentException(e);
+                            }
+                        })
+                        .toArray(Class<?>[]::new)));
+
+        return initializer;
+    }
+
+    private Properties readProps(final String props) {
+        final Properties properties = new Properties();
+        try (final StringReader reader = new StringReader(props)) {
+            properties.load(reader);
+        } catch (final IOException e) {
+            throw new IllegalStateException(e);
+        }
+        return properties;
+    }
+
+    private String dump(final Path workDir, final String name, final String value) {
+        if (!java.nio.file.Files.isDirectory(workDir)) {
+            try {
+                java.nio.file.Files.createDirectories(workDir);
+            } catch (final IOException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+        final Path out = workDir.resolve(name);
+        try {
+            Files.write(
+                    out, value.getBytes(StandardCharsets.UTF_8),
+                    StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+        log.info("Created '{}'", out);
+        return out.toAbsolutePath().toString();
     }
 }
diff --git a/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/feature/OpenWebBeansFeature.java b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/feature/OpenWebBeansFeature.java
new file mode 100644
index 0000000..d15a1ef
--- /dev/null
+++ b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/feature/OpenWebBeansFeature.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.knight.openwebbeans.feature;
+
+import com.oracle.svm.core.annotate.AutomaticFeature;
+import com.oracle.svm.core.jdk.LocalizationFeature;
+import com.oracle.svm.core.jdk.Resources;
+import com.oracle.svm.core.option.HostedOptionKey;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.nativeimage.ImageSingletons;
+import org.graalvm.nativeimage.hosted.Feature;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Iterator;
+import java.util.stream.Stream;
+
+@AutomaticFeature
+public class OpenWebBeansFeature implements Feature {
+    public static final class Options {
+        @Option(help = "OpenWebBeans properties.", type = OptionType.User)
+        static final HostedOptionKey<String> OpenWebBeansProperties = new HostedOptionKey<>(null);
+    }
+
+    // org.graalvm.compiler.options.processor is not on central
+    public static class OpenWebBeansOptions implements OptionDescriptors {
+        @Override
+        public OptionDescriptor get(final String value) {
+            switch (value) {
+                case "OpenWebBeansProperties":
+                    return OptionDescriptor.create(
+                            value, OptionType.User, String.class,
+                            "OpenWebBeans properties.",
+                            Options.class, value,
+                            Options.OpenWebBeansProperties);
+                default:
+                    return null;
+            }
+        }
+
+        @Override
+        public Iterator<OptionDescriptor> iterator() {
+            return Stream.of("OpenWebBeansProperties").map(this::get).iterator();
+        }
+    }
+
+    @Override
+    public void beforeAnalysis(final BeforeAnalysisAccess access) {
+        if (Options.OpenWebBeansProperties.hasBeenSet()) {
+            register(Options.OpenWebBeansProperties.getValue(), "META-INF/openwebbeans/openwebbeans.properties");
+        }
+        ImageSingletons.lookup(LocalizationFeature.class).addBundleToCache("openwebbeans/Messages");
+    }
+
+    private void register(final String path, final String resource) {
+        try (final InputStream stream = Files.newInputStream(Paths.get(path))) {
+            Resources.registerResource(resource, stream);
+        } catch (final IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
diff --git a/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/replacement/AbstractMetaDataDiscovery.java b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/replacement/AbstractMetaDataDiscovery.java
new file mode 100644
index 0000000..c4a08fd
--- /dev/null
+++ b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/replacement/AbstractMetaDataDiscovery.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.knight.openwebbeans.replacement;
+
+import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.annotate.TargetClass;
+
+@TargetClass(org.apache.webbeans.corespi.scanner.AbstractMetaDataDiscovery.class)
+public final class AbstractMetaDataDiscovery {
+    @Substitute
+    protected void registerBeanArchives(final ClassLoader loader) {
+        // no-op: we don't discover we just take the generated/configured scanning
+    }
+}
diff --git a/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/replacement/OWBInitializer.java b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/replacement/OWBInitializer.java
new file mode 100644
index 0000000..159652c
--- /dev/null
+++ b/knights/openwebbeans-knight/src/main/java/org/apache/geronimo/arthur/knight/openwebbeans/replacement/OWBInitializer.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.knight.openwebbeans.replacement;
+
+import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.annotate.TargetClass;
+import org.apache.openwebbeans.se.PreScannedCDISeScannerService;
+import org.apache.webbeans.spi.ScannerService;
+
+@TargetClass(org.apache.openwebbeans.se.OWBInitializer.class)
+public final class OWBInitializer {
+    @Substitute
+    protected ScannerService getScannerService() {
+        final PreScannedCDISeScannerService scannerService = new PreScannedCDISeScannerService();
+        scannerService.loader(Thread.currentThread().getContextClassLoader());
+        return scannerService;
+    }
+}
diff --git a/knights/openwebbeans-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension b/knights/openwebbeans-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension
new file mode 100644
index 0000000..24e264e
--- /dev/null
+++ b/knights/openwebbeans-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension
@@ -0,0 +1 @@
+org.apache.geronimo.arthur.knight.openwebbeans.OpenWebBeansExtension
diff --git a/knights/openwebbeans-knight/src/main/resources/META-INF/services/org.graalvm.compiler.options.OptionDescriptors b/knights/openwebbeans-knight/src/main/resources/META-INF/services/org.graalvm.compiler.options.OptionDescriptors
new file mode 100644
index 0000000..71ed3d1
--- /dev/null
+++ b/knights/openwebbeans-knight/src/main/resources/META-INF/services/org.graalvm.compiler.options.OptionDescriptors
@@ -0,0 +1 @@
+org.apache.geronimo.arthur.knight.openwebbeans.feature.OpenWebBeansFeature$OpenWebBeansOptions