You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2021/07/08 10:06:24 UTC

[camel-quarkus] branch main updated: Leverage catalog metadata to discover unremovable types

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/main by this push:
     new 11c3f0a  Leverage catalog metadata to discover unremovable types
11c3f0a is described below

commit 11c3f0ac5a9f0b246a6c172c1edb7d39d0fced18
Author: James Netherton <ja...@gmail.com>
AuthorDate: Tue Jul 6 08:28:37 2021 +0100

    Leverage catalog metadata to discover unremovable types
    
    Fixes #2822
---
 .../deployment/CamelUnremovableBeansProcessor.java |  94 +++++++++++++
 .../deployment/catalog/BuildTimeCamelCatalog.java  |  86 ++++++++++++
 .../catalog/BuildTimeJsonSchemaResolver.java       |  83 ++++++++++++
 .../core/deployment/catalog/SchemaResource.java    | 110 ++++++++++++++++
 .../spi/BuildTimeCamelCatalogBuildItem.java        |  33 +++++
 .../core/runtime/CamelBeansUnremovableTest.java    | 145 +++++++++++++++++++++
 .../src/test/resources/custom-component.json       | 122 +++++++++++++++++
 .../src/test/resources/custom-dataformat.json      |  53 ++++++++
 .../src/test/resources/custom-language.json        |  53 ++++++++
 .../deployment/GoogleBigqueryProcessor.java        |   7 -
 .../queue/it/AzureStorageQueueResource.java        |   4 -
 .../component/influxdb/it/InfluxdbResource.java    |   2 -
 12 files changed, 779 insertions(+), 13 deletions(-)

diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelUnremovableBeansProcessor.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelUnremovableBeansProcessor.java
new file mode 100644
index 0000000..385a404
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelUnremovableBeansProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * 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.camel.quarkus.core.deployment;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import org.apache.camel.quarkus.core.deployment.catalog.BuildTimeCamelCatalog;
+import org.apache.camel.quarkus.core.deployment.catalog.BuildTimeJsonSchemaResolver;
+import org.apache.camel.quarkus.core.deployment.catalog.SchemaResource;
+import org.apache.camel.quarkus.core.deployment.spi.BuildTimeCamelCatalogBuildItem;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.spi.annotations.Dataformat;
+import org.apache.camel.spi.annotations.Language;
+import org.apache.camel.tooling.model.BaseOptionModel;
+import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CamelUnremovableBeansProcessor {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CamelProcessor.class);
+
+    private static final DotName[] CATALOG_SCHEMA_TYPES = {
+            DotName.createSimple(Component.class.getName()),
+            DotName.createSimple(Dataformat.class.getName()),
+            DotName.createSimple(Language.class.getName())
+    };
+
+    @BuildStep
+    BuildTimeCamelCatalogBuildItem buildTimeCamelCatalog(CombinedIndexBuildItem combinedIndex) {
+        Set<SchemaResource> resources = new HashSet<>();
+        IndexView index = combinedIndex.getIndex();
+
+        List<AnnotationInstance> annotations = Stream.of(CATALOG_SCHEMA_TYPES)
+                .map(index::getAnnotations)
+                .flatMap(Collection::stream)
+                .collect(Collectors.toList());
+
+        for (AnnotationInstance instance : annotations) {
+            SchemaResource resource = new SchemaResource();
+            resource.setName(instance.value().asString());
+            resource.setType(instance.name().withoutPackagePrefix().toLowerCase());
+            resource.setClassName(instance.target().asClass().name());
+            resources.add(resource);
+        }
+
+        BuildTimeJsonSchemaResolver resolver = new BuildTimeJsonSchemaResolver(resources);
+        BuildTimeCamelCatalog catalog = new BuildTimeCamelCatalog(resolver);
+        return new BuildTimeCamelCatalogBuildItem(catalog);
+    }
+
+    @BuildStep
+    UnremovableBeanBuildItem unremovableCamelBeans(BuildTimeCamelCatalogBuildItem camelCatalogBuildItem) {
+        BuildTimeCamelCatalog catalog = camelCatalogBuildItem.getCatalog();
+        Set<DotName> unremovableClasses = catalog.getAllOptions()
+                .stream()
+                .filter(option -> option.getType().equals("object"))
+                .filter(option -> !option.getJavaType().startsWith("java.lang"))
+                .map(BaseOptionModel::getJavaType)
+                .map(DotName::createSimple)
+                .collect(Collectors.toSet());
+
+        if (LOGGER.isDebugEnabled()) {
+            unremovableClasses.stream().forEach(
+                    unremovableClass -> LOGGER.debug("Registering camel unremovable bean class: {}", unremovableClass));
+        }
+
+        return UnremovableBeanBuildItem.beanTypes(unremovableClasses);
+    }
+}
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/BuildTimeCamelCatalog.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/BuildTimeCamelCatalog.java
new file mode 100644
index 0000000..4d33e71
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/BuildTimeCamelCatalog.java
@@ -0,0 +1,86 @@
+/*
+ * 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.camel.quarkus.core.deployment.catalog;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.camel.catalog.impl.AbstractCamelCatalog;
+import org.apache.camel.tooling.model.BaseOptionModel;
+import org.apache.camel.tooling.model.ComponentModel;
+
+public class BuildTimeCamelCatalog extends AbstractCamelCatalog {
+
+    public BuildTimeCamelCatalog(BuildTimeJsonSchemaResolver resolver) {
+        setJSonSchemaResolver(resolver);
+    }
+
+    public BuildTimeJsonSchemaResolver getJSonSchemaResolver() {
+        return (BuildTimeJsonSchemaResolver) super.getJSonSchemaResolver();
+    }
+
+    /**
+     * Gets a list of all component, endpoint, dataformat & language options for the components that are on the classpath
+     * 
+     * @return List of {@link BaseOptionModel} instances
+     */
+    public List<BaseOptionModel> getAllOptions() {
+        List<BaseOptionModel> options = new ArrayList<>();
+        BuildTimeJsonSchemaResolver resolver = getJSonSchemaResolver();
+        Set<SchemaResource> schemaResources = resolver.getSchemaResources();
+
+        // Component options
+        List<ComponentModel> componentModels = schemaResources
+                .stream()
+                .map(SchemaResource::getName)
+                .map(this::componentModel)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        // For components we need to combine the component options with the endpoint options
+        componentModels.stream()
+                .flatMap(componentModel -> componentModel.getComponentOptions().stream())
+                .forEach(options::add);
+
+        componentModels.stream()
+                .flatMap(componentModel -> componentModel.getEndpointOptions().stream())
+                .forEach(options::add);
+
+        // DataFormat options
+        schemaResources
+                .stream()
+                .map(SchemaResource::getName)
+                .map(this::dataFormatModel)
+                .filter(Objects::nonNull)
+                .flatMap(dataFormatModel -> dataFormatModel.getOptions().stream())
+                .forEach(options::add);
+
+        // Language options
+        schemaResources
+                .stream()
+                .map(SchemaResource::getName)
+                .map(this::languageModel)
+                .filter(Objects::nonNull)
+                .flatMap(languageModel -> languageModel.getOptions().stream())
+                .forEach(options::add);
+
+        return options;
+    }
+}
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/BuildTimeJsonSchemaResolver.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/BuildTimeJsonSchemaResolver.java
new file mode 100644
index 0000000..a1d69f5
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/BuildTimeJsonSchemaResolver.java
@@ -0,0 +1,83 @@
+/*
+ * 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.camel.quarkus.core.deployment.catalog;
+
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.camel.catalog.JSonSchemaResolver;
+
+public class BuildTimeJsonSchemaResolver implements JSonSchemaResolver {
+
+    private final Set<SchemaResource> schemaResources;
+
+    public BuildTimeJsonSchemaResolver(Set<SchemaResource> schemaResources) {
+        this.schemaResources = schemaResources;
+    }
+
+    @Override
+    public void setClassLoader(ClassLoader classLoader) {
+        throw new UnsupportedOperationException("Setting an alternative ClassLoader is not supported");
+    }
+
+    @Override
+    public String getComponentJSonSchema(String name) {
+        return resolveJsonSchema("component", name);
+    }
+
+    @Override
+    public String getDataFormatJSonSchema(String name) {
+        return resolveJsonSchema("dataformat", name);
+    }
+
+    @Override
+    public String getLanguageJSonSchema(String name) {
+        return resolveJsonSchema("language", name);
+    }
+
+    @Override
+    public String getOtherJSonSchema(String name) {
+        throw new UnsupportedOperationException("Other JSON schema resolution is not supported");
+    }
+
+    @Override
+    public String getModelJSonSchema(String name) {
+        throw new UnsupportedOperationException("Model JSON schema resolution is not supported");
+    }
+
+    @Override
+    public String getMainJsonSchema() {
+        throw new UnsupportedOperationException("Main JSON schema resolution is not supported");
+    }
+
+    public Set<SchemaResource> getSchemaResources() {
+        return schemaResources;
+    }
+
+    private String resolveJsonSchema(String type, String name) {
+        Optional<SchemaResource> schemaResource = schemaResources.stream()
+                .filter(si -> si.getType().equals(type))
+                .filter(si -> si.getName().equals(name))
+                .findFirst();
+
+        if (schemaResource.isPresent()) {
+            return schemaResource.get().load();
+        }
+
+        return null;
+    }
+}
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/SchemaResource.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/SchemaResource.java
new file mode 100644
index 0000000..05f6755
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/catalog/SchemaResource.java
@@ -0,0 +1,110 @@
+/*
+ * 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.camel.quarkus.core.deployment.catalog;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+
+import org.apache.camel.util.IOHelper;
+import org.jboss.jandex.DotName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SchemaResource {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SchemaResource.class);
+
+    private String type;
+    private String name;
+    private DotName className;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public DotName getClassName() {
+        return className;
+    }
+
+    public void setClassName(DotName className) {
+        this.className = className;
+    }
+
+    public String getLocation() {
+        String packageName = className.prefix().toString();
+        return packageName.replace('.', '/') + "/" + name + ".json";
+    }
+
+    public String load() {
+        InputStream resource = Thread.currentThread().getContextClassLoader().getResourceAsStream(getLocation());
+        if (resource != null) {
+            try {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("Resolved JSON schema resource: {}", getLocation());
+                }
+
+                return IOHelper.loadText(resource);
+            } catch (IOException e) {
+                if (LOGGER.isErrorEnabled()) {
+                    LOGGER.error("Unable to load JSON schema resource: {}", getLocation(), e);
+                }
+            } finally {
+                IOHelper.close(resource);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        SchemaResource that = (SchemaResource) o;
+        return Objects.equals(type, that.type)
+                && Objects.equals(name, that.name)
+                && Objects.equals(className, that.className);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type, name, className);
+    }
+
+    @Override
+    public String toString() {
+        return "SchemaResource{" + "type='" + type + '\'' + ", name='" + name + '\'' + ", packageName='" + className + '\''
+                + '}';
+    }
+}
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/BuildTimeCamelCatalogBuildItem.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/BuildTimeCamelCatalogBuildItem.java
new file mode 100644
index 0000000..b871e27
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/BuildTimeCamelCatalogBuildItem.java
@@ -0,0 +1,33 @@
+/*
+ * 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.camel.quarkus.core.deployment.spi;
+
+import io.quarkus.builder.item.SimpleBuildItem;
+import org.apache.camel.quarkus.core.deployment.catalog.BuildTimeCamelCatalog;
+
+public final class BuildTimeCamelCatalogBuildItem extends SimpleBuildItem {
+
+    private final BuildTimeCamelCatalog catalog;
+
+    public BuildTimeCamelCatalogBuildItem(BuildTimeCamelCatalog catalog) {
+        this.catalog = catalog;
+    }
+
+    public BuildTimeCamelCatalog getCatalog() {
+        return catalog;
+    }
+}
diff --git a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelBeansUnremovableTest.java b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelBeansUnremovableTest.java
new file mode 100644
index 0000000..ebf1645
--- /dev/null
+++ b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelBeansUnremovableTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.camel.quarkus.core.runtime;
+
+import java.util.Set;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.spi.annotations.Dataformat;
+import org.apache.camel.spi.annotations.Language;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class CamelBeansUnremovableTest {
+
+    static final String RESSOURCE_PATH = "org/apache/camel/quarkus/core/runtime/"
+            + CamelBeansUnremovableTest.class.getSimpleName();
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+                    .addAsResource("custom-component.json", RESSOURCE_PATH + "/custom-component.json")
+                    .addAsResource("custom-dataformat.json", RESSOURCE_PATH + "/custom-dataformat.json")
+                    .addAsResource("custom-language.json", RESSOURCE_PATH + "/custom-language.json"));
+
+    @Inject
+    CamelContext context;
+
+    @Test
+    public void testComponentBeansUnremovable() {
+        Registry registry = context.getRegistry();
+
+        Set<UnremovableComponentBean> unremovableComponentBeans = registry.findByType(UnremovableComponentBean.class);
+        Assertions.assertEquals(1, unremovableComponentBeans.size());
+
+        Set<UnremovableEndpointBean> unremovableEndpointBeans = registry.findByType(UnremovableEndpointBean.class);
+        Assertions.assertEquals(1, unremovableEndpointBeans.size());
+    }
+
+    @Test
+    public void testDataFormatBeansUnremovable() {
+        Registry registry = context.getRegistry();
+        Set<UnremovableDataFormatBean> unremovableDataFormatBeans = registry.findByType(UnremovableDataFormatBean.class);
+        Assertions.assertEquals(1, unremovableDataFormatBeans.size());
+    }
+
+    @Test
+    public void testLanguageBeansUnremovable() {
+        Registry registry = context.getRegistry();
+        Set<UnremovableLanguageBean> unremovableLanguageBeans = registry.findByType(UnremovableLanguageBean.class);
+        Assertions.assertEquals(1, unremovableLanguageBeans.size());
+    }
+
+    @Test
+    public void testNonUnremovableBeansRemoved() {
+        Registry registry = context.getRegistry();
+        Set<Exception> nonUnremovableBeans = registry.findByType(Exception.class);
+        Assertions.assertTrue(nonUnremovableBeans.isEmpty());
+    }
+
+    static final class UnremovableComponentBean {
+    }
+
+    static final class UnremovableEndpointBean {
+    }
+
+    static final class UnremovableDataFormatBean {
+    }
+
+    static final class UnremovableLanguageBean {
+    }
+
+    @ApplicationScoped
+    static final class BeanProducers {
+
+        @Singleton
+        @Produces
+        public UnremovableComponentBean unremovableComponentBean() {
+            return new UnremovableComponentBean();
+        }
+
+        @Singleton
+        @Produces
+        public UnremovableEndpointBean unremovableEndpointBean() {
+            return new UnremovableEndpointBean();
+        }
+
+        @Singleton
+        @Produces
+        public UnremovableDataFormatBean unremovableDataFormatBean() {
+            return new UnremovableDataFormatBean();
+        }
+
+        @Singleton
+        @Produces
+        public UnremovableLanguageBean unremovableLanguageBean() {
+            return new UnremovableLanguageBean();
+        }
+
+        @Singleton
+        @Produces
+        public Exception removableBean() {
+            return new Exception("java.lang types should not be auto added as unremovable");
+        }
+    }
+
+    // See component metadata in src/test/resources/custom-component.json
+    @Component("custom-component")
+    static final class CustomComponent {
+    }
+
+    // See dataformat metadata in src/test/resources/custom-dataformat.json
+    @Dataformat("custom-dataformat")
+    static final class CustomDataFormat {
+    }
+
+    // See language metadata in src/test/resources/custom-language.json
+    @Language("custom-language")
+    static final class CustomLanguage {
+    }
+}
diff --git a/extensions-core/core/deployment/src/test/resources/custom-component.json b/extensions-core/core/deployment/src/test/resources/custom-component.json
new file mode 100644
index 0000000..fbd05f1
--- /dev/null
+++ b/extensions-core/core/deployment/src/test/resources/custom-component.json
@@ -0,0 +1,122 @@
+{
+  "component": {
+    "kind": "component",
+    "name": "custom-component",
+    "title": "Custom Component",
+    "description": "Fake component to test AutoWired bean types are unremovable.",
+    "deprecated": false,
+    "firstVersion": "0.0.0",
+    "label": "testing",
+    "javaType": "org.apache.camel.quarkus.core.runtime.CamelBeansUnremovableTest$CustomComponent",
+    "supportLevel": "Stable",
+    "groupId": "org.apache.camel.quarkus",
+    "artifactId": "camel-quarkus-custom-component",
+    "version": "0.0.0",
+    "scheme": "custom-component",
+    "extendsScheme": "",
+    "syntax": "custom-component:fake",
+    "async": false,
+    "api": false,
+    "consumerOnly": false,
+    "producerOnly": true,
+    "lenientProperties": false
+  },
+  "componentProperties": {
+    "autowiredEnabled": {
+      "kind": "property",
+      "displayName": "Autowired Enabled",
+      "group": "advanced",
+      "label": "advanced",
+      "required": false,
+      "type": "boolean",
+      "javaType": "boolean",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "defaultValue": true,
+      "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc."
+    },
+    "unremovableComponentProperty": {
+      "kind": "property",
+      "displayName": "",
+      "group": "advanced",
+      "label": "advanced",
+      "required": false,
+      "type": "object",
+      "javaType": "org.apache.camel.quarkus.core.runtime.CamelBeansUnremovableTest$UnremovableComponentBean",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "defaultValue": true,
+      "description": ""
+    },
+    "removableComponentPrimitiveProperty": {
+      "kind": "property",
+      "displayName": "",
+      "group": "advanced",
+      "label": "advanced",
+      "required": false,
+      "type": "integer",
+      "javaType": "long",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "defaultValue": true,
+      "description": ""
+    },
+    "removableComponentJavaDotLangProperty": {
+      "kind": "property",
+      "displayName": "",
+      "group": "advanced",
+      "label": "advanced",
+      "required": false,
+      "type": "object",
+      "javaType": "java.lang.Exception",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "defaultValue": true,
+      "description": ""
+    }
+  },
+  "properties": {
+    "unremovableEndpointProperty": {
+      "kind": "parameter",
+      "displayName": "",
+      "group": "producer",
+      "label": "",
+      "required": false,
+      "type": "object",
+      "javaType": "org.apache.camel.quarkus.core.runtime.CamelBeansUnremovableTest$UnremovableEndpointBean",
+      "deprecated": false,
+      "deprecationNote": "",
+      "autowired": true,
+      "secret": false,
+      "description": ""
+    },
+    "removableEndpointPrimitiveProperty": {
+      "kind": "parameter",
+      "displayName": "",
+      "group": "producer",
+      "label": "",
+      "required": false,
+      "type": "boolean",
+      "javaType": "boolean",
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    },
+    "removableEndpointJavaDotLangProperty": {
+      "kind": "parameter",
+      "displayName": "",
+      "group": "producer",
+      "label": "",
+      "required": false,
+      "type": "object",
+      "javaType": "java.lang.Exception",
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    }
+  }
+}
diff --git a/extensions-core/core/deployment/src/test/resources/custom-dataformat.json b/extensions-core/core/deployment/src/test/resources/custom-dataformat.json
new file mode 100644
index 0000000..842ee57
--- /dev/null
+++ b/extensions-core/core/deployment/src/test/resources/custom-dataformat.json
@@ -0,0 +1,53 @@
+{
+  "dataformat": {
+    "kind": "dataformat",
+    "name": "custom-dataformat",
+    "title": "Custom DataFormat",
+    "description": "",
+    "deprecated": false,
+    "firstVersion": "0.0.0",
+    "label": "dataformat",
+    "javaType": "org.apache.camel.quarkus.core.runtime.CamelBeansUnremovableTest$CustomDataFormat",
+    "supportLevel": "Stable",
+    "groupId": "org.apache.camel.quarkus",
+    "artifactId": "camel-quarkus-custom-dataformat",
+    "version": "0.0.0",
+    "modelName": "",
+    "modelJavaType": ""
+  },
+  "properties": {
+    "unremovableDataFormatProperty": {
+      "kind": "attribute",
+      "displayName": "",
+      "required": false,
+      "type": "object",
+      "javaType": "org.apache.camel.quarkus.core.runtime.CamelBeansUnremovableTest$UnremovableDataFormatBean",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    },
+    "removableDataFormatPrimitiveProperty": {
+      "kind": "attribute",
+      "displayName": "",
+      "required": false,
+      "type": "boolean",
+      "javaType": "boolean",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    },
+    "removableDataFormatJavaDotLangProperty": {
+      "kind": "attribute",
+      "displayName": "",
+      "required": false,
+      "type": "object",
+      "javaType": "java.lang.Exception",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/extensions-core/core/deployment/src/test/resources/custom-language.json b/extensions-core/core/deployment/src/test/resources/custom-language.json
new file mode 100644
index 0000000..3f14e5b
--- /dev/null
+++ b/extensions-core/core/deployment/src/test/resources/custom-language.json
@@ -0,0 +1,53 @@
+{
+  "language": {
+    "kind": "language",
+    "name": "custom-language",
+    "title": "Custom Language",
+    "description": "",
+    "deprecated": false,
+    "firstVersion": "0.0.0",
+    "label": "language,script",
+    "javaType": "org.apache.camel.language.groovy.GroovyLanguage",
+    "supportLevel": "Stable",
+    "groupId": "org.apache.camel.quarkus",
+    "artifactId": "camel-quarkus-custom-language",
+    "version": "0.0.0",
+    "modelName": "",
+    "modelJavaType": ""
+  },
+  "properties": {
+    "unremovableLanguageProperty": {
+      "kind": "attribute",
+      "displayName": "",
+      "required": false,
+      "type": "object",
+      "javaType": "org.apache.camel.quarkus.core.runtime.CamelBeansUnremovableTest$UnremovableLanguageBean",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    },
+    "removableLanguagePrimitiveProperty": {
+      "kind": "attribute",
+      "displayName": "",
+      "required": false,
+      "type": "boolean",
+      "javaType": "boolean",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    },
+    "removableLanguageJavaDotLangProperty": {
+      "kind": "attribute",
+      "displayName": "",
+      "required": false,
+      "type": "object",
+      "javaType": "java.lang.Exception",
+      "deprecated": false,
+      "autowired": false,
+      "secret": false,
+      "description": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/extensions/google-bigquery/deployment/src/main/java/org/apache/camel/quarkus/component/google/bigquery/deployment/GoogleBigqueryProcessor.java b/extensions/google-bigquery/deployment/src/main/java/org/apache/camel/quarkus/component/google/bigquery/deployment/GoogleBigqueryProcessor.java
index 98bfdb5..91bedd1 100644
--- a/extensions/google-bigquery/deployment/src/main/java/org/apache/camel/quarkus/component/google/bigquery/deployment/GoogleBigqueryProcessor.java
+++ b/extensions/google-bigquery/deployment/src/main/java/org/apache/camel/quarkus/component/google/bigquery/deployment/GoogleBigqueryProcessor.java
@@ -17,10 +17,8 @@
 package org.apache.camel.quarkus.component.google.bigquery.deployment;
 
 import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
-import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
 import io.quarkus.deployment.annotations.BuildStep;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
-import org.apache.camel.component.google.bigquery.GoogleBigQueryConnectionFactory;
 import org.apache.camel.quarkus.component.google.bigquery.GoogleBigQueryConnectionFactoryProducer;
 
 class GoogleBigqueryProcessor {
@@ -32,11 +30,6 @@ class GoogleBigqueryProcessor {
     }
 
     @BuildStep
-    UnremovableBeanBuildItem unremovableBeans() {
-        return UnremovableBeanBuildItem.beanTypes(GoogleBigQueryConnectionFactory.class);
-    }
-
-    @BuildStep
     public AdditionalBeanBuildItem connectionFactoryProducerBean() {
         return new AdditionalBeanBuildItem(GoogleBigQueryConnectionFactoryProducer.class);
     }
diff --git a/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java b/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java
index a930df4..cb32979 100644
--- a/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java
+++ b/integration-test-groups/azure/azure-storage-queue/src/main/java/org/apache/camel/quarkus/component/azure/storage/queue/it/AzureStorageQueueResource.java
@@ -23,7 +23,6 @@ import java.util.stream.Collectors;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
-import javax.inject.Named;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -40,7 +39,6 @@ import com.azure.storage.common.StorageSharedKeyCredential;
 import com.azure.storage.queue.QueueServiceClient;
 import com.azure.storage.queue.QueueServiceClientBuilder;
 import com.azure.storage.queue.models.QueueMessageItem;
-import io.quarkus.arc.Unremovable;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.component.azure.storage.queue.QueueOperationDefinition;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -64,8 +62,6 @@ public class AzureStorageQueueResource {
     String azureQueueServiceUrl;
 
     @javax.enterprise.inject.Produces
-    @Named("azureQueueServiceClient")
-    @Unremovable
     public QueueServiceClient createQueueClient() throws Exception {
         final StorageSharedKeyCredential credentials = new StorageSharedKeyCredential(azureStorageAccountName,
                 azureStorageAccountKey);
diff --git a/integration-tests/influxdb/src/main/java/org/apache/camel/quarkus/component/influxdb/it/InfluxdbResource.java b/integration-tests/influxdb/src/main/java/org/apache/camel/quarkus/component/influxdb/it/InfluxdbResource.java
index 02fea17..e71dee2 100644
--- a/integration-tests/influxdb/src/main/java/org/apache/camel/quarkus/component/influxdb/it/InfluxdbResource.java
+++ b/integration-tests/influxdb/src/main/java/org/apache/camel/quarkus/component/influxdb/it/InfluxdbResource.java
@@ -29,7 +29,6 @@ import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
-import io.quarkus.arc.Unremovable;
 import org.apache.camel.FluentProducerTemplate;
 import org.apache.camel.component.influxdb.InfluxDbConstants;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -53,7 +52,6 @@ public class InfluxdbResource {
     @ConfigProperty(name = INFLUXDB_CONNECTION_PROPERTY)
     String connectionUrl;
 
-    @Unremovable
     @Singleton
     @javax.enterprise.inject.Produces
     InfluxDB createInfluxDbConnection() {