New CDI based EE injection manager incubating implementation. (#4822)

* New CDI based EE injection manager incubating implementation.

Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/incubator/cdi-inject-weld/pom.xml b/incubator/cdi-inject-weld/pom.xml
new file mode 100644
index 0000000..44b60b7
--- /dev/null
+++ b/incubator/cdi-inject-weld/pom.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.glassfish.jersey.incubator</groupId>
+        <artifactId>project</artifactId>
+        <version>2.35-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>jersey-cdi-inject-weld</artifactId>
+    <packaging>jar</packaging>
+    <name>jersey-inject-cdi-weld</name>
+
+    <description>CDI InjectionManager implementation</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <version>${servlet4.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-grizzly2-http</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>jakarta.enterprise</groupId>
+            <artifactId>jakarta.enterprise.cdi-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.weld.se</groupId>
+            <artifactId>weld-se-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.el</groupId>
+            <artifactId>jakarta.el-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+
+        <plugins>
+            <plugin>
+                <groupId>com.sun.istack</groupId>
+                <artifactId>istack-commons-maven-plugin</artifactId>
+                <inherited>true</inherited>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <inherited>true</inherited>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <inherited>true</inherited>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.glassfish.jersey.inject.weld.managed.*;version=${project.version}
+                        </Export-Package>
+                        <Import-Package>
+                            sun.misc.*;resolution:=optional,
+                            ${jakarta.annotation.osgi.version},
+                            *
+                        </Import-Package>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>default-jar</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java
new file mode 100644
index 0000000..d1fbafa
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/BeanHelper.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.Path;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.data.BindingBeanPair;
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableSupplierInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.injector.CachedConstructorAnalyzer;
+import org.glassfish.jersey.inject.weld.internal.injector.InjectionUtils;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyConstructorInjectionPoint;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyTwofoldInstantiator;
+import org.glassfish.jersey.inject.weld.internal.injector.WrappingJerseyInjectionTarget;
+import org.glassfish.jersey.internal.inject.ClassBinding;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+import org.glassfish.jersey.internal.inject.PerThread;
+import org.glassfish.jersey.internal.inject.SupplierClassBinding;
+
+import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedConstructor;
+import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
+import org.jboss.weld.annotated.enhanced.jlr.ConstructorSignatureImpl;
+import org.jboss.weld.annotated.enhanced.jlr.EnhancedAnnotatedTypeImpl;
+import org.jboss.weld.annotated.slim.SlimAnnotatedType;
+import org.jboss.weld.bean.builtin.BeanManagerProxy;
+import org.jboss.weld.injection.ConstructorInjectionPoint;
+import org.jboss.weld.injection.producer.AbstractInstantiator;
+import org.jboss.weld.injection.producer.BasicInjectionTarget;
+import org.jboss.weld.injection.producer.BeanInjectionTarget;
+import org.jboss.weld.injection.producer.InjectionTargetService;
+import org.jboss.weld.injection.producer.Instantiator;
+import org.jboss.weld.injection.producer.NonProducibleInjectionTarget;
+import org.jboss.weld.manager.BeanManagerImpl;
+import org.jboss.weld.resources.ClassTransformer;
+
+/**
+ * Helper class to register a {@link Bean} into CDI {@link BeanManager}.
+ */
+public abstract class BeanHelper {
+
+    /**
+     * Forbids the creation of {@link BeanHelper} instance.
+     */
+    private BeanHelper() {
+    }
+
+    /**
+     * Registers an instance as {@link JerseyBean} into {@link BeanManager}.
+     *
+     * @param binding   object containing {@link javax.enterprise.inject.spi.BeanAttributes} information.
+     * @param abd       {@link AfterBeanDiscovery} event.
+     * @param resolvers all registered injection resolvers.
+     * @param <T>       type of the instance which is registered.
+     */
+    public static <T> void registerBean(RuntimeType runtimeType, InitializableInstanceBinding<T> binding, AfterBeanDiscovery abd,
+                                        List<InjectionResolver> resolvers, BeanManager beanManager) {
+        InitializableInstanceBean<T> bean = new InitializableInstanceBean<>(runtimeType, binding);
+        /*
+         * Wrap into custom injection target that is able to inject the additional @Inject, @Context, @*Param fields into
+         * the given service.
+         */
+        InjectionTarget<T> injectionTarget = new WrappingJerseyInjectionTarget<>(bean, resolvers);
+        bean.setInjectionTarget(injectionTarget);
+        abd.addBean(bean);
+    }
+
+    /**
+     * Registers a class as {@link JerseyBean} into {@link BeanManager}.
+     *
+     * @param binding     object containing {@link javax.enterprise.inject.spi.BeanAttributes} information.
+     * @param abd         {@link AfterBeanDiscovery} event.
+     * @param resolvers   all registered injection resolvers.
+     * @param beanManager currently used bean manager.
+     * @param <T>         type of the class which is registered.
+     */
+    public static <T> BindingBeanPair registerBean(RuntimeType runtimeType, ClassBinding<T> binding, AfterBeanDiscovery abd,
+                                                   Collection<InjectionResolver> resolvers, BeanManager beanManager) {
+        AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(binding.getService());
+        InjectionTarget<T> injectionTarget = beanManager.createInjectionTarget(annotatedType);
+
+        ClassBean<T> bean = new ClassBean<>(runtimeType, binding);
+        bean.setInjectionTarget(getJerseyInjectionTarget(binding.getService(), injectionTarget, bean, resolvers));
+        abd.addBean(bean);
+
+        return new BindingBeanPair(binding, bean);
+    }
+
+    /**
+     * Registers an instance supplier and its provided value as {@link JerseyBean}s into {@link BeanManager}.
+     *
+     * @param binding object containing {@link javax.enterprise.inject.spi.BeanAttributes} information.
+     * @param abd     {@link AfterBeanDiscovery} event.
+     * @param <T>     type of the instance which is registered.
+     */
+    public static <T> void registerSupplier(RuntimeType runtimeType, InitializableSupplierInstanceBinding<T> binding,
+                                            AfterBeanDiscovery abd, BeanManager beanManager) {
+        /*
+         * CDI does not provide sufficient support for ThreadScoped Supplier
+         */
+        if (binding.getScope() == PerThread.class) {
+            BeanManagerImpl manager;
+            if (beanManager instanceof BeanManagerProxy) {
+                manager = ((BeanManagerProxy) beanManager).unwrap();
+            } else {
+                manager = (BeanManagerImpl) beanManager;
+            }
+            abd.addBean(new InitializableSupplierThreadScopeBean(runtimeType, binding, manager));
+        } else {
+            abd.addBean(new InitializableSupplierInstanceBean<>(runtimeType, binding));
+            abd.addBean(new InitializableSupplierInstanceBeanBridge<>(runtimeType, binding));
+        }
+    }
+
+    /**
+     * Registers a class supplier and its provided value as {@link JerseyBean}s into {@link BeanManager}.
+     *
+     * @param binding     object containing {@link javax.enterprise.inject.spi.BeanAttributes} information.
+     * @param abd         {@link AfterBeanDiscovery} event.
+     * @param resolvers   all registered injection resolvers.
+     * @param beanManager currently used bean manager.
+     * @param <T>         type of the class which is registered.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> BindingBeanPair registerSupplier(RuntimeType runtimeType, SupplierClassBinding<T> binding,
+            AfterBeanDiscovery abd, Collection<InjectionResolver> resolvers, BeanManager beanManager) {
+
+        Class<Supplier<T>> supplierClass = (Class<Supplier<T>>) binding.getSupplierClass();
+        AnnotatedType<Supplier<T>> annotatedType = beanManager.createAnnotatedType(supplierClass);
+        InjectionTarget<Supplier<T>> injectionTarget = beanManager.createInjectionTarget(annotatedType);
+
+        SupplierClassBean<T> supplierBean = new SupplierClassBean<>(runtimeType, binding);
+        InjectionTarget<Supplier<T>> jit = getJerseyInjectionTarget(supplierClass, injectionTarget, supplierBean, resolvers);
+        supplierBean.setInjectionTarget(jit);
+
+        final SupplierBeanBridge supplierBeanBridge = new SupplierBeanBridge(runtimeType, binding, beanManager);
+
+        abd.addBean(supplierBean);
+        abd.addBean(supplierBeanBridge);
+
+        return new BindingBeanPair(binding, supplierBean, supplierBeanBridge);
+    }
+
+    /**
+     * Update ClassBinding Bean by {@link ConstructorInjectionPoint} for the client side beans.
+     * @param binding The ClassBinding used to create a client side ConstructorInjectionPoint.
+     * @param pair {@link BindingBeanPair} that contains the original server side Bean.
+     * @param resolvers Resolvers handling Jersey specific injection annotations.
+     * @param beanManager The {@link BeanManager}.
+     */
+    public static void updateBean(ClassBinding binding,
+            BindingBeanPair pair, Collection<InjectionResolver> resolvers, BeanManager beanManager) {
+
+        final JerseyBean bean = pair.getBeans().get(0);
+        final ConstructorInjectionPoint cip = createConstructorInjectionPoint(binding, bean, resolvers, beanManager);
+
+        if (ClassBean.class.isInstance(bean)
+                && JerseyInjectionTarget.class.isInstance(((ClassBean) bean).getInjectionTarget())) {
+            final JerseyTwofoldInstantiator instantiator =
+                    ((JerseyInjectionTarget) ((ClassBean) bean).getInjectionTarget()).getTwofoldInstantiator();
+            instantiator.setOptionalConstructorInjectionPoint(cip);
+        }
+    }
+
+    /**
+     * Update SupplierClassBinding Bean by {@link ConstructorInjectionPoint} for the client side beans.
+     * @param binding The SupplierClassBinding used to create a client side ConstructorInjectionPoint.
+     * @param pair {@link BindingBeanPair} that contains the original server side Bean.
+     * @param resolvers Resolvers handling Jersey specific injection annotations.
+     * @param beanManager The {@link BeanManager}.
+     */
+    public static void updateSupplierBean(SupplierClassBinding binding,
+            BindingBeanPair pair, Collection<InjectionResolver> resolvers, BeanManager beanManager) {
+
+        final JerseyBean bean = pair.getBeans().get(0);
+        final ConstructorInjectionPoint cip = createConstructorInjectionPoint(binding, bean, resolvers, beanManager);
+
+        if (SupplierClassBean.class.isInstance(bean)
+                && JerseyInjectionTarget.class.isInstance(((SupplierClassBean) bean).getInjectionTarget())) {
+            final JerseyTwofoldInstantiator instantiator =
+                    ((JerseyInjectionTarget) ((SupplierClassBean) bean).getInjectionTarget()).getTwofoldInstantiator();
+            instantiator.setOptionalConstructorInjectionPoint(cip);
+        }
+    }
+
+    private static <T> ConstructorInjectionPoint<T> createConstructorInjectionPoint(
+            SupplierClassBinding<T> binding, Bean<T> bean, Collection<InjectionResolver> resolvers, BeanManager beanManager) {
+
+        final Class<Supplier<T>> bindingClass = (Class<Supplier<T>>) binding.getSupplierClass();
+        final AnnotatedType<Supplier<T>> annotatedType = beanManager.createAnnotatedType(bindingClass);
+        final InjectionTarget<Supplier<T>> injectionTarget = beanManager.createInjectionTarget(annotatedType);
+
+        final CachedConstructorAnalyzer<Supplier<T>> analyzer =
+                new CachedConstructorAnalyzer<>(bindingClass, InjectionUtils.getInjectAnnotations(resolvers));
+
+        if (analyzer.hasCompatibleConstructor()) {
+            EnhancedAnnotatedConstructor<T> constructor = createEnhancedAnnotatedType((BasicInjectionTarget) injectionTarget)
+                    .getDeclaredEnhancedConstructor(new ConstructorSignatureImpl(analyzer.getConstructor()));
+
+            JerseyConstructorInjectionPoint<T> constructorInjectionPoint = new JerseyConstructorInjectionPoint<T>(
+                    constructor, bean, ((BasicInjectionTarget) injectionTarget).getBeanManager(), resolvers);
+            return constructorInjectionPoint;
+        }
+        return null;
+    }
+
+    private static <T> ConstructorInjectionPoint<T> createConstructorInjectionPoint(
+            ClassBinding<T> binding, Bean<T> bean, Collection<InjectionResolver> resolvers, BeanManager beanManager) {
+
+        final Class<T> bindingClass = binding.getImplementationType();
+        final AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(bindingClass);
+        final InjectionTarget<T> injectionTarget = beanManager.createInjectionTarget(annotatedType);
+
+        final CachedConstructorAnalyzer<T> analyzer =
+                new CachedConstructorAnalyzer<>(bindingClass, InjectionUtils.getInjectAnnotations(resolvers));
+
+        if (analyzer.hasCompatibleConstructor()) {
+            EnhancedAnnotatedConstructor<T> constructor = createEnhancedAnnotatedType((BasicInjectionTarget) injectionTarget)
+                    .getDeclaredEnhancedConstructor(new ConstructorSignatureImpl(analyzer.getConstructor()));
+
+            JerseyConstructorInjectionPoint<T> constructorInjectionPoint = new JerseyConstructorInjectionPoint<T>(
+                    constructor, bean, ((BasicInjectionTarget) injectionTarget).getBeanManager(), resolvers);
+            return constructorInjectionPoint;
+        }
+        return null;
+    }
+
+    private static <T> InjectionTarget<T> getJerseyInjectionTarget(Class<T> clazz, InjectionTarget<T> injectionTarget,
+            Bean<T> bean, Collection<InjectionResolver> resolvers) {
+        BasicInjectionTarget<T> it = (BasicInjectionTarget<T>) injectionTarget;
+
+        /*
+         * Looks at whether the DefaultInstantiator resolving a valid constructor does not met this case:
+         * - No constructor with @Inject annotation is defined
+         * - NoArgs constructor is defined
+         * - Instantiator ignores JAX-RS valid constructor with multiple params
+         */
+        boolean noArgConstructor = isNoArgConstructorCase(it, clazz);
+
+        JerseyInjectionTarget<T> jit;
+        /*
+         * CDI is able to find a constructor that means that the class contains only one constructor of this type:
+         * - default constructor
+         * - non-argument constructor
+         * - multi-param constructor annotated by @Inject annotation and able to inject all parameters.
+         */
+        if (!noArgConstructor && injectionTarget instanceof BeanInjectionTarget) {
+            jit = new JerseyInjectionTarget<>(it, bean, clazz, resolvers);
+
+        /*
+         * CDI failed during the looking for a proper constructor because of these reasons:
+         * - multi-param constructor not annotated by @Inject annotation
+         * - multiple constructors annotated by @Inject annotation
+         * - is not able to satisfied single constructor annotated by @Inject annotation
+         *
+         * Therefore produced NonProducibleInjectionTarget cannot create and instance, we try to find the proper constructor
+         * using JAX-RS rules:
+         * - largest constructor with all annotated parameters
+         *
+         * If JAX-RS valid constructor is not find - InjectionException is thrown
+         */
+        } else if (noArgConstructor || injectionTarget instanceof NonProducibleInjectionTarget) {
+            CachedConstructorAnalyzer<T> analyzer =
+                    new CachedConstructorAnalyzer<>(clazz, InjectionUtils.getInjectAnnotations(resolvers));
+
+            /*
+             * Contains the analyzed class any constructor that can be injected by Jersey?
+             */
+            if (analyzer.hasCompatibleConstructor()) {
+                EnhancedAnnotatedConstructor<T> constructor = createEnhancedAnnotatedType(it)
+                        .getDeclaredEnhancedConstructor(new ConstructorSignatureImpl(analyzer.getConstructor()));
+
+                JerseyConstructorInjectionPoint<T> constructorInjectionPoint =
+                        new JerseyConstructorInjectionPoint<>(constructor, bean, it.getBeanManager(), resolvers);
+
+                Instantiator<T> instantiator = new JerseyInstantiator<>(constructorInjectionPoint);
+                jit = new JerseyInjectionTarget<>(createEnhancedAnnotatedType(it), it, bean, clazz, resolvers, instantiator);
+
+            /*
+             * Instance of this class cannot be created neither CDI nor Jersey therefore mark it as non-producible.
+             */
+            } else {
+                return new WrappingJerseyInjectionTarget<>(it, bean, resolvers);
+            }
+        } else {
+            throw new RuntimeException("Unknown InjectionTarget for the class: " + clazz.getTypeName());
+        }
+
+        InjectionTargetService injectionTargetService = it.getBeanManager().getServices().get(InjectionTargetService.class);
+        injectionTargetService.addInjectionTargetToBeInitialized(jit.getEnhancedAnnotatedType(), jit);
+        return jit;
+    }
+
+    public static <T> EnhancedAnnotatedType<T> createEnhancedAnnotatedType(BasicInjectionTarget<T> it) {
+        return EnhancedAnnotatedTypeImpl.of(
+                (SlimAnnotatedType<T>) it.getAnnotatedType(), ClassTransformer.instance(it.getBeanManager()));
+    }
+
+    /**
+     * Looks at whether the DefaultInstantiator resolving a valid constructor does not met this case:
+     * - No constructor with @Inject annotation is defined
+     * - NoArgs constructor is defined
+     * - Instantiator ignores JAX-RS valid constructor with multiple params
+     *
+     * @param it    injection target containing instantiator with resolved constructor.
+     * @param clazz class which analyzed constructor belongs to.
+     * @param <T>   type of the analyzed class.
+     * @return {@code true} if no-arg constructor was selected while multi-params constructor exists.
+     */
+    private static <T> boolean isNoArgConstructorCase(BasicInjectionTarget<T> it, Class<T> clazz) {
+        if (!(it instanceof NonProducibleInjectionTarget)) {
+            Instantiator<T> instantiator = it.getInstantiator();
+            Constructor<T> constructor = instantiator.getConstructor();
+            return constructor.getParameterCount() == 0 && clazz.getConstructors().length > 1;
+        }
+
+        return false;
+    }
+
+    /**
+     * Wrapper class to provide Jersey implementation of {@link Instantiator} interface.
+     *
+     * @param <T> type which is created by instantiator.
+     */
+    private static class JerseyInstantiator<T> extends AbstractInstantiator<T> {
+
+        private final ConstructorInjectionPoint<T> injectionPoint;
+
+        private JerseyInstantiator(ConstructorInjectionPoint<T> injectionPoint) {
+            this.injectionPoint = injectionPoint;
+        }
+
+        @Override
+        public ConstructorInjectionPoint<T> getConstructorInjectionPoint() {
+            return injectionPoint;
+        }
+
+        @Override
+        public Constructor<T> getConstructor() {
+            return injectionPoint.getAnnotated().getJavaMember();
+        }
+
+        @Override
+        public String toString() {
+            return "JerseyInstantiator [constructor=" + injectionPoint.getMember() + "]";
+        }
+
+        @Override
+        public boolean hasInterceptorSupport() {
+            return false;
+        }
+
+        @Override
+        public boolean hasDecoratorSupport() {
+            return false;
+        }
+    }
+
+    public static boolean isResourceClass(Class<?> clazz) {
+        if (isJaxrsResource(clazz)) {
+            return true;
+        }
+
+        for (Class<?> iface : clazz.getInterfaces()) {
+            if (isJaxrsResource(iface)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static boolean isJaxrsResource(Class<?> clazz) {
+        if (clazz.isAnnotationPresent(Path.class)) {
+            return true;
+        }
+
+        for (Method method : clazz.getMethods()) {
+            if (method.isAnnotationPresent(Path.class)) {
+                return true;
+            }
+
+            for (Annotation annotation : method.getAnnotations()) {
+                if (annotation.annotationType().isAnnotationPresent(HttpMethod.class)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/ClassBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/ClassBean.java
new file mode 100644
index 0000000..6c3d6b8
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/ClassBean.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Set;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.internal.inject.ClassBinding;
+
+/**
+ * Creates an implementation of {@link javax.enterprise.inject.spi.Bean} interface using Jersey's {@link ClassBinding}. Binding
+ * provides the information about the bean also called {@link javax.enterprise.inject.spi.BeanAttributes} information and
+ * {@link JerseyInjectionTarget} provides the contextual part of the bean because implements
+ * {@link javax.enterprise.context.spi.Contextual} with Jersey injection extension (is able to inject into JAX-RS/Jersey specified
+ * annotation).
+ * <p>
+ * Inject example:
+ * <pre>
+ * AbstractBinder {
+ *     &#64;Override
+ *     protected void configure() {
+ *         bind(MyBean.class)
+ *              .to(MyBean.class)
+ *              .in(Singleton.class)&#59;
+ *     }
+ * }
+ * </pre>
+ * Register example:
+ * <pre>
+ *  &#64;Path("/")
+ *  public class MyResource {
+ *    &#64;Inject
+ *    private MyBean myBean&#59;
+ *  }
+ * </pre>
+ *
+ * @author Petr Bouda
+ */
+class ClassBean<T> extends JerseyBean<T> {
+
+    private final ClassBinding<T> binding;
+    private InjectionTarget<T> injectionTarget;
+
+    /**
+     * Creates a new Jersey-specific {@link javax.enterprise.inject.spi.Bean} instance.
+     * @param runtimeType {@link RuntimeType} type information of the bean source.
+     * @param binding the binding information.
+     */
+    ClassBean(RuntimeType runtimeType, ClassBinding<T> binding) {
+        super(runtimeType, binding);
+        this.binding = binding;
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        /*
+         * Resource class without the Scope annotation should registered as a RequestScoped.
+         */
+        if (binding.getScope() == null && BeanHelper.isResourceClass(binding.getService())) {
+            return RequestScoped.class;
+        }
+
+        return binding.getScope() == null ? Dependent.class : transformScope(binding.getScope());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T create(CreationalContext<T> context) {
+        T instance = injectionTarget.produce(context);
+        injectionTarget.inject(instance, context);
+        injectionTarget.postConstruct(instance);
+        return instance;
+    }
+
+    @Override
+    public void destroy(T instance, CreationalContext<T> context) {
+        injectionTarget.preDestroy(instance);
+        injectionTarget.dispose(instance);
+        context.release();
+    }
+
+    @Override
+    public Set<Type> getTypes() {
+        Set<Type> contracts = super.getTypes();
+        contracts.addAll(Arrays.asList(binding.getService().getInterfaces()));
+        return contracts;
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        return binding.getService();
+    }
+
+    @Override
+    public Set<InjectionPoint> getInjectionPoints() {
+        return injectionTarget.getInjectionPoints();
+    }
+
+    /**
+     * Lazy set of an injection target because to create fully functional injection target needs already created bean.
+     *
+     * @param injectionTarget {@link javax.enterprise.context.spi.Contextual} information belonging to this bean.
+     */
+    void setInjectionTarget(InjectionTarget<T> injectionTarget) {
+        this.injectionTarget = injectionTarget;
+    }
+
+    @Override
+    public String toString() {
+        return "ClassBean{" + getBeanClass() + "(" + getRutimeType() + ")}";
+    }
+
+    public InjectionTarget<T> getInjectionTarget() {
+        return injectionTarget;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableInstanceBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableInstanceBean.java
new file mode 100644
index 0000000..f319a4f
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableInstanceBean.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyClientCreationalContext;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Instance bean to be created in the pre-initialization phase and initialized after Jersey is bootstrap.
+ * @param <T> the class of the bean instance.
+ */
+public class InitializableInstanceBean<T> extends JerseyBean<T> {
+
+    private InjectionTarget<T> injectionTarget;
+
+    /**
+     * Creates a new Jersey-specific {@link javax.enterprise.inject.spi.Bean} instance.
+     *
+     * @param binding {@link javax.enterprise.inject.spi.BeanAttributes} part of the bean.
+     */
+    InitializableInstanceBean(RuntimeType runtimeType, InitializableInstanceBinding<T> binding) {
+        super(runtimeType, binding);
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return getBinding().getScope() == null ? Dependent.class : transformScope(getBinding().getScope());
+    }
+
+    @Override
+    public T create(CreationalContext<T> context) {
+        InitializableInstanceBinding<T> realBinding = (InitializableInstanceBinding<T>) getBinding();
+        if (JerseyClientCreationalContext.class.isInstance(context)) {
+            realBinding = ((JerseyClientCreationalContext) context).getInjectionManager().getInjectionManagerBinding(realBinding);
+        }
+        T service = realBinding.getService();
+        this.injectionTarget.inject(service, context);
+        return service;
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        final InitializableInstanceBinding<T> binding = (InitializableInstanceBinding<T>) getBinding();
+        return binding.isInit() ? binding.getImplementationType() : Object.class;
+    }
+
+    /**
+     * Lazy set of an injection target because to create fully functional injection target needs already created bean.
+     *
+     * @param injectionTarget {@link javax.enterprise.context.spi.Contextual} information belonging to this bean.
+     */
+    void setInjectionTarget(InjectionTarget<T> injectionTarget) {
+        this.injectionTarget = injectionTarget;
+    }
+
+    @Override
+    public String toString() {
+        return "InitializableInstanceBean{" + getBeanClass() + "}";
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierInstanceBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierInstanceBean.java
new file mode 100644
index 0000000..cbaaf0c
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierInstanceBean.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableSupplierInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyClientCreationalContext;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.inject.weld.internal.type.ParameterizedTypeImpl;
+import org.glassfish.jersey.internal.inject.DisposableSupplier;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * Creates an implementation of {@link javax.enterprise.inject.spi.Bean} interface using Jersey's {@link SupplierInstanceBinding}.
+ * Binding provides the information about the bean also called {@link javax.enterprise.inject.spi.BeanAttributes} information.
+ * The {@code Bean} does not use {@link JerseyInjectionTarget} because serves already
+ * created supplier instance, therefore the create operation just return provided instance without any other contextual operation
+ * (produce, inject, destroy). Client has to manage the instance alone.
+ * <p>
+ * Inject example:
+ * <pre>
+ * AbstractBinder {
+ *     &#64;Override
+ *     protected void configure() {
+ *         bindFactory(new MyBeanFactory())
+ *              .to(MyBean.class)
+ *              .in(Singleton.class)&#59;
+ *     }
+ * }
+ * </pre>
+ * Register example:
+ * <pre>
+ *  &#64;Path("/")
+ *  public class MyResource {
+ *    &#64;Inject
+ *    private Supplier&lt;MyBean&gt; myBean&#59;
+ *  }
+ * </pre>
+ *
+ * @author Petr Bouda
+ */
+class InitializableSupplierInstanceBean<T> extends JerseyBean<Supplier<T>> {
+
+    private final Set<Type> contracts = new HashSet<>();
+    private final Supplier<T> supplier;
+
+    /**
+     * Creates a new Jersey-specific {@link javax.enterprise.inject.spi.Bean} instance.
+     *
+     * @param binding {@link javax.enterprise.inject.spi.BeanAttributes} part of the bean.
+     */
+    InitializableSupplierInstanceBean(RuntimeType runtimeType, InitializableSupplierInstanceBinding<T> binding) {
+        super(runtimeType, binding);
+        this.supplier = binding.getSupplier();
+
+        for (Type contract: binding.getContracts()) {
+            this.contracts.add(new ParameterizedTypeImpl(Supplier.class, contract));
+            if (DisposableSupplier.class.isAssignableFrom(binding.getSupplier().getClass())) {
+                this.contracts.add(new ParameterizedTypeImpl(DisposableSupplier.class, contract));
+            }
+        }
+    }
+
+    @Override
+    public Set<Type> getTypes() {
+        return contracts;
+    }
+
+    @Override
+    public Set<Annotation> getQualifiers() {
+        return DEFAULT_QUALIFIERS;
+    }
+
+    @Override
+    public Supplier<T> create(CreationalContext<Supplier<T>> context) {
+        if (JerseyClientCreationalContext.class.isInstance(context)) {
+            final InitializableSupplierInstanceBinding<T> binding = (InitializableSupplierInstanceBinding<T>) getBinding();
+            final JerseyClientCreationalContext jerseyContext = (JerseyClientCreationalContext) context;
+            return jerseyContext.getInjectionManager().getInjectionManagerBinding(binding).getSupplier();
+        } else {
+            return supplier;
+        }
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        final InitializableSupplierInstanceBinding binding = (InitializableSupplierInstanceBinding) getBinding();
+        return binding.isInit() ? binding.getOriginalSupplier().getClass() : Object.class;
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return getBinding().getScope() == null ? Dependent.class : transformScope(getBinding().getScope());
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierInstanceBeanBridge.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierInstanceBeanBridge.java
new file mode 100644
index 0000000..c86d44f
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierInstanceBeanBridge.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableSupplierInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.internal.inject.DisposableSupplier;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+
+import java.lang.annotation.Annotation;
+import java.util.function.Supplier;
+
+/**
+ * Creates an implementation of {@link javax.enterprise.inject.spi.Bean} interface using Jersey's {@link SupplierInstanceBinding}.
+ * Binding provides the information about the bean also called {@link javax.enterprise.inject.spi.BeanAttributes} information.
+ * The {@code Bean} does not use {@link JerseyInjectionTarget} because serves already
+ * created instances, therefore the create operation just return provided instance without any other contextual operation
+ * (produce, inject, destroy). Client has to manage the instance alone.
+ * <p>
+ * This implementation works as bridge between {@link Supplier} and its provided value. This solves the case when the concrete
+ * type of supplier value is fetched from {@link org.glassfish.jersey.internal.inject.InjectionManager} then this
+ * {@link javax.enterprise.inject.spi.Bean} implementation just invokes {@link Supplier#get} method on underlying/registered
+ * supplier.
+ * <p>
+ * Inject example:
+ * <pre>
+ * AbstractBinder {
+ *     &#64;Override
+ *     protected void configure() {
+ *         bindFactory(new MyBeanFactory())
+ *              .to(MyBean.class)
+ *              .in(Singleton.class)&#59;
+ *     }
+ * }
+ * </pre>
+ * Register example:
+ * <pre>
+ *  &#64;Path("/")
+ *  public class MyResource {
+ *    &#64;Inject
+ *    private MyBean myBean&#59;
+ *  }
+ * </pre>
+ *
+ * @author Petr Bouda
+ */
+class InitializableSupplierInstanceBeanBridge<T> extends JerseyBean<Object> {
+
+    private final Supplier<T> supplier;
+    private final Class<? extends Annotation> scope;
+
+    /**
+     * Creates a new Jersey-specific {@link javax.enterprise.inject.spi.Bean} instance.
+     *
+     * @param binding {@link javax.enterprise.inject.spi.BeanAttributes} part of the bean.
+     */
+    @SuppressWarnings("unchecked")
+    InitializableSupplierInstanceBeanBridge(RuntimeType runtimeType, InitializableSupplierInstanceBinding binding) {
+        super(runtimeType, binding);
+
+        InitializableSupplierInstanceBinding<T> casted = (InitializableSupplierInstanceBinding<T>) binding;
+        this.supplier = casted.getSupplier();
+        this.scope = casted.getScope();
+    }
+
+    @Override
+    public Object create(CreationalContext creationalContext) {
+        return supplier.get();
+    }
+
+    @Override
+    public void destroy(Object instance, CreationalContext<Object> context) {
+        if (DisposableSupplier.class.isAssignableFrom(supplier.getClass())) {
+            ((DisposableSupplier<Object>) supplier).dispose(instance);
+        }
+    }
+
+    /**
+     * {@link InitializableSupplierInstanceBeanBridge} needs have the same scope as a keeping value.
+     *
+     * @return scope of the supplier bean.
+     */
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return scope == null ? Dependent.class : transformScope(scope);
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierThreadScopeBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierThreadScopeBean.java
new file mode 100644
index 0000000..5f144e0
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/InitializableSupplierThreadScopeBean.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.PassivationCapable;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableSupplierInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+import org.jboss.weld.bean.StringBeanIdentifier;
+import org.jboss.weld.bean.proxy.BeanInstance;
+import org.jboss.weld.bean.proxy.ContextBeanInstance;
+import org.jboss.weld.bean.proxy.ProxyFactory;
+import org.jboss.weld.manager.BeanManagerImpl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.WeakHashMap;
+import java.util.function.Supplier;
+
+/**
+ * Creates an implementation of {@link Bean} interface using Jersey's {@link SupplierInstanceBinding}.
+ * Binding provides the information about the bean also called {@link javax.enterprise.inject.spi.BeanAttributes} information.
+ * The {@code Bean} does not use {@link JerseyInjectionTarget} because serves already
+ * created proxy, therefore the create operation just return provided instance without any other contextual operation
+ * (produce, inject, destroy).
+ * <p>
+ * This bean is special and is used only for service registered as a {@link org.glassfish.jersey.internal.inject.PerThread} and
+ * works through the proxy which serves the correct instance per the given thread.
+ * <p>
+ * Register example:
+ * <pre>
+ * AbstractBinder {
+ *     &#64;Override
+ *     protected void configure() {
+ *         bindFactory(new MyFactoryInjectionProvider())
+ *              .to(MyBean.class)
+ *              .in(PerThread.class);
+ *     }
+ * }
+ * </pre>
+ * Inject example:
+ * <pre>
+ * &#64;Path("/")
+ * public class MyResource {
+ *   &#64;Inject
+ *   private MyBean myBean&#59;
+ * }
+ * </pre>
+ */
+public class InitializableSupplierThreadScopeBean extends JerseyBean<Object> {
+
+    private final ThreadScopeBeanInstance<Object> beanInstance;
+    private final InitializableSupplierInstanceBinding binding;
+    private final Object proxy;
+
+    /**
+     * Creates a new Jersey-specific {@link Bean} instance.
+     *
+     * @param binding {@link javax.enterprise.inject.spi.BeanAttributes} part of the bean.
+     */
+    @SuppressWarnings("unchecked")
+    InitializableSupplierThreadScopeBean(RuntimeType runtimeType,
+                                         InitializableSupplierInstanceBinding binding,
+                                         BeanManagerImpl manager) {
+        super(runtimeType, binding);
+        this.binding = binding;
+        this.beanInstance = new ThreadScopeBeanInstance<>(binding.getSupplier(), this, manager.getContextId());
+        this.proxy = createClientProxy(beanInstance, manager.getContextId());
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return Dependent.class;
+    }
+
+    @Override
+    public Object create(CreationalContext<Object> ctx) {
+        return proxy;
+    }
+
+    @Override
+    public void destroy(Object instance, CreationalContext<Object> creationalContext) {
+        this.beanInstance.dispose();
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        return (Class<?>) this.binding.getContracts().iterator().next();
+    }
+
+    private <T> T createClientProxy(BeanInstance beanInstance, String contextId) {
+        ProxyFactory<T> factory = new ProxyFactory<>(contextId, getBeanClass(), getTypes(), this);
+        return factory.create(beanInstance);
+    }
+
+    private static class ThreadScopeBeanInstance<T> extends ContextBeanInstance<T> {
+
+        private final WeakHashMap<Thread, Object> instances = new WeakHashMap<>();
+
+        private final Supplier<T> supplier;
+
+        /**
+         * Creates a new invocation handler with supplier which provides a current injected value in proper scope.
+         *
+         * @param supplier provider of the value.
+         */
+        private ThreadScopeBeanInstance(Supplier<T> supplier, Bean<T> bean, String contextId) {
+            super(bean, new StringBeanIdentifier(((PassivationCapable) bean).getId()), contextId);
+            this.supplier = supplier;
+        }
+
+        @Override
+        public Object invoke(Object obj, Method method, Object... arguments) throws Throwable {
+            Object instance = instances.computeIfAbsent(Thread.currentThread(), thread -> supplier.get());
+            return super.invoke(instance, method, arguments);
+        }
+
+        public void dispose() {
+            this.instances.clear();
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/JerseyBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/JerseyBean.java
new file mode 100644
index 0000000..99cee8b
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/JerseyBean.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.annotation.Priority;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.PassivationCapable;
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Singleton;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.PerLookup;
+import org.glassfish.jersey.internal.inject.PerThread;
+
+import org.jboss.weld.environment.se.contexts.ThreadScoped;
+
+/**
+ * Jersey-specific abstract class which implements {@link Bean} interface. Class particularly contains default implementations
+ * of {@link Bean} interface.
+ *
+ * @author Petr Bouda
+ */
+public abstract class JerseyBean<T> implements Bean<T>, PassivationCapable {
+
+    static final Set<Annotation> DEFAULT_QUALIFIERS;
+
+    static {
+        DEFAULT_QUALIFIERS = new HashSet<>();
+        DEFAULT_QUALIFIERS.add(new AnnotationLiteral<Default>() {});
+        DEFAULT_QUALIFIERS.add(new AnnotationLiteral<Any>() {});
+    }
+
+    public Binding<T, ?> getBinding() {
+        return binding;
+    }
+
+    private final Binding<T, ?> binding;
+    private final RuntimeType runtimeType;
+
+    /**
+     * JerseyBean constructor with {@link Binding} which represents {@link javax.enterprise.context.spi.Contextual} part of the
+     * bean.
+     *
+     * @param runtimeType
+     * @param binding information about the bean.
+     */
+    JerseyBean(RuntimeType runtimeType, Binding<T, ?> binding) {
+        this.binding = binding;
+        this.runtimeType = runtimeType == null ? RuntimeType.SERVER : runtimeType;
+    }
+
+    /**
+     * Transforms Jersey scopes/annotations to HK2 equivalents.
+     *
+     * @param scope Jersey scope/annotation.
+     * @return HK2 equivalent scope/annotation.
+     */
+    protected static Class<? extends Annotation> transformScope(Class<? extends Annotation> scope) {
+        if (scope == PerLookup.class) {
+            return Dependent.class;
+        } else if (scope == PerThread.class) {
+            return ThreadScoped.class;
+        } else if (scope == org.glassfish.jersey.process.internal.RequestScoped.class) {
+            return RequestScoped.class;
+        }
+        return scope;
+    }
+
+    @Override
+    public Set<Type> getTypes() {
+        Set<Type> contracts = new HashSet<>();
+        contracts.addAll(binding.getContracts());
+
+        // Merge aliases with the main bean
+        if (!binding.getAliases().isEmpty()) {
+            binding.getAliases().forEach(alias -> contracts.add(alias.getContract()));
+        }
+        contracts.add(Object.class);
+        return contracts;
+    }
+
+    @Override
+    public Set<Annotation> getQualifiers() {
+        Set<Annotation> qualifiers = new HashSet<>();
+        qualifiers.addAll(DEFAULT_QUALIFIERS);
+        if (binding.getQualifiers() != null) {
+            qualifiers.addAll(binding.getQualifiers());
+        }
+
+        // Merge aliases with the main bean
+        if (!binding.getAliases().isEmpty()) {
+            binding.getAliases().forEach(alias -> qualifiers.addAll(alias.getQualifiers()));
+        }
+        return qualifiers;
+    }
+
+    @Override
+    public String getName() {
+        return binding.getName();
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return Singleton.class;
+    }
+
+    @Override
+    public Set<Class<? extends Annotation>> getStereotypes() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public boolean isAlternative() {
+        return false;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return false;
+    }
+
+    @Override
+    public void destroy(T instance, CreationalContext<T> creationalContext) {
+    }
+
+    @Override
+    public Set<InjectionPoint> getInjectionPoints() {
+        return Collections.emptySet();
+    }
+
+    public int getRank() {
+        if (binding.getRank() != null) {
+            return binding.getRank();
+        }
+
+        Class<T> type = binding.getImplementationType();
+        if (type != null) {
+            Priority priority = type.getAnnotation(Priority.class);
+            if (priority != null) {
+                return priority.value();
+            }
+        }
+
+        return 1;
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        return Object.class;
+    }
+
+    @Override
+    public String getId() {
+        // Object for Lambda
+        return (getBeanClass().equals(Object.class) ? getContractsAsString() : getBeanClass().getTypeName())
+                + "#jersey" + runtimeType;
+    }
+
+    public RuntimeType getRutimeType() {
+        return runtimeType;
+    }
+
+    public String getContractsAsString() {
+        return Arrays.toString(binding.getContracts().toArray());
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierBeanBridge.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierBeanBridge.java
new file mode 100644
index 0000000..0a3c247
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierBeanBridge.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.inject.weld.managed.CdiInjectionManagerFactory;
+import org.glassfish.jersey.inject.weld.internal.type.ParameterizedTypeImpl;
+import org.glassfish.jersey.internal.inject.DisposableSupplier;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.SupplierClassBinding;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+
+/**
+ * Creates an implementation of {@link javax.enterprise.inject.spi.Bean} interface using Jersey's {@link SupplierInstanceBinding}.
+ * Binding provides the information about the bean also called {@link javax.enterprise.inject.spi.BeanAttributes} information.
+ * The {@code Bean} does not use {@link JerseyInjectionTarget} because serves already
+ * the instances created by underlying {@link Supplier} injected target on which the call is delegated.
+ * <p>
+ * This implementation works as bridge between {@link Supplier} and its provided value. This solves the case when the concrete
+ * type of supplier value is fetched from {@link org.glassfish.jersey.internal.inject.InjectionManager} then this
+ * {@link javax.enterprise.inject.spi.Bean} implementation just invokes {@link Supplier#get} method on underlying/registered
+ * supplier.
+ * <p>
+ * Inject example:
+ * <pre>
+ * AbstractBinder {
+ *     &#64;Override
+ *     protected void configure() {
+ *         bindFactory(MyBeanFactory.class)
+ *              .to(MyBean.class)
+ *              .in(Singleton.class)&#59;
+ *     }
+ * }
+ * </pre>
+ * Register example:
+ * <pre>
+ *  &#64;Path("/")
+ *  public class MyResource {
+ *    &#64;Inject
+ *    private MyBean myBean&#59;
+ *  }
+ * </pre>
+ *
+ * @author Petr Bouda
+ */
+class SupplierBeanBridge extends JerseyBean<Object> {
+
+    private final BeanManager beanManager;
+    private ParameterizedType type;
+    private boolean disposable;
+    private SupplierClassBinding binding;
+
+    // This bridge can create multiple instances using the method 'provide' therefore must map created suppliers because of
+    // 'dispose' invocation later on.
+    // TODO: Key as a WeakReference - prevent objects in scope which never dispose the objects such as PerLookup.
+    private final Map<Object, DisposableSupplier<Object>> disposableSuppliers = new IdentityHashMap<>();
+
+    /**
+     * Creates a new Jersey-specific {@link javax.enterprise.inject.spi.Bean} instance.
+     *
+     * @param binding {@link javax.enterprise.inject.spi.BeanAttributes} part of the bean.
+     */
+    @SuppressWarnings("unchecked")
+    SupplierBeanBridge(RuntimeType runtimeType, SupplierClassBinding binding, BeanManager beanManager) {
+        super(runtimeType, binding);
+
+        // Register wrapper for factory functionality, wrapper automatically call service locator which is able to retrieve
+        // the service in the proper context and scope. Bridge is registered for all contracts but is able to lookup from
+        // service locator only using the first contract.
+        Type contract = null;
+        if (binding.getContracts().iterator().hasNext()) {
+            contract = (Type) binding.getContracts().iterator().next();
+        }
+
+        this.binding = binding;
+        this.beanManager = beanManager;
+        this.disposable = DisposableSupplier.class.isAssignableFrom(binding.getSupplierClass());
+        this.type = new ParameterizedTypeImpl(Supplier.class, contract);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Object create(CreationalContext creationalContext) {
+        if (type != null) {
+            InjectionManager injectionManager = CdiInjectionManagerFactory.getInjectionManager(creationalContext);
+            Supplier<?> supplier = injectionManager.getInstance(type);
+
+            //Supplier<?> supplier = getSupplier(beanManager, type);
+            Object instance = supplier.get();
+            if (disposable) {
+                disposableSuppliers.put(instance, (DisposableSupplier) supplier);
+            }
+            return instance;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void destroy(Object instance, CreationalContext context) {
+        if (disposable) {
+            DisposableSupplier disposableSupplier = disposableSuppliers.get(instance);
+            disposableSupplier.dispose(instance);
+            disposableSuppliers.remove(instance);
+        }
+    }
+
+    private static Supplier<?> getSupplier(BeanManager beanManager, ParameterizedType supplierType) {
+        Set<Bean<?>> beans = beanManager.getBeans(supplierType);
+        if (beans.isEmpty()) {
+            return null;
+        }
+
+        Bean<?> bean = beans.iterator().next();
+        CreationalContext<?> ctx = beanManager.createCreationalContext(bean);
+        return (Supplier<?>) beanManager.getReference(bean, supplierType, ctx);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Class<? extends Annotation> getScope() {
+        return binding.getScope() == null ? Dependent.class : transformScope(binding.getScope());
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        return this.binding.getContracts().isEmpty()
+                ? super.getBeanClass()
+                : (Class<?>) this.binding.getContracts().iterator().next();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierClassBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierClassBean.java
new file mode 100644
index 0000000..5ae244d
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/bean/SupplierClassBean.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.bean;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.inject.weld.internal.type.ParameterizedTypeImpl;
+import org.glassfish.jersey.internal.inject.DisposableSupplier;
+import org.glassfish.jersey.internal.inject.SupplierClassBinding;
+
+/**
+ * Creates an implementation of {@link javax.enterprise.inject.spi.Bean} interface using Jersey's {@link SupplierClassBinding}.
+ * Binding provides the information about the bean also called {@link javax.enterprise.inject.spi.BeanAttributes} information and
+ * {@link JerseyInjectionTarget} provides the contextual part of the bean because implements
+ * {@link javax.enterprise.context.spi.Contextual} with Jersey injection extension (is able to inject into JAX-RS/Jersey specified
+ * annotation).
+ * <p>
+ * Bean's implementation provides possibility to register {@link Supplier} and {@link DisposableSupplier}.
+ * <p>
+ * Inject example:
+ * <pre>
+ * AbstractBinder {
+ *     &#64;Override
+ *     protected void configure() {
+ *         bindFactory(MyBeanSupplier.class)
+ *              .to(MyBean.class)
+ *              .in(Singleton.class)&#59;
+ *     }
+ * }
+ * </pre>
+ * Register example:
+ * <pre>
+ *  &#64;Path("/")
+ *  public class MyResource {
+ *    &#64;Inject
+ *    private Supplier&lt;MyBean&gt; myBean&#59;
+ *  }
+ * </pre>
+ *
+ * @author Petr Bouda
+ */
+class SupplierClassBean<T> extends JerseyBean<Supplier<T>> {
+
+    private final Set<Type> contracts = new HashSet<>();
+    private final Class<? extends Supplier<T>> supplierClass;
+    private final Class<? extends Annotation> supplierScope;
+    private InjectionTarget<Supplier<T>> injectionTarget;
+
+    /**
+     * Creates a new Jersey-specific {@link javax.enterprise.inject.spi.Bean} instance.
+     *
+     * @param binding {@link javax.enterprise.inject.spi.BeanAttributes} part of the bean.
+     */
+    SupplierClassBean(RuntimeType runtimeType, SupplierClassBinding<T> binding) {
+        super(runtimeType, binding);
+        this.supplierClass = binding.getSupplierClass();
+        this.supplierScope = binding.getSupplierScope();
+
+        for (Type contract : binding.getContracts()) {
+            this.contracts.add(new ParameterizedTypeImpl(Supplier.class, contract));
+            if (DisposableSupplier.class.isAssignableFrom(supplierClass)) {
+                this.contracts.add(new ParameterizedTypeImpl(DisposableSupplier.class, contract));
+            }
+        }
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return supplierScope == null ? Dependent.class : transformScope(supplierScope);
+    }
+
+    @Override
+    public Set<Type> getTypes() {
+        return contracts;
+    }
+
+    @Override
+    public Supplier<T> create(CreationalContext<Supplier<T>> context) {
+        Supplier<T> instance = injectionTarget.produce(context);
+        injectionTarget.inject(instance, context);
+        injectionTarget.postConstruct(instance);
+        return instance;
+    }
+
+    @Override
+    public void destroy(Supplier<T> instance, CreationalContext<Supplier<T>> context) {
+        injectionTarget.preDestroy(instance);
+        injectionTarget.dispose(instance);
+        context.release();
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        return supplierClass;
+    }
+
+    /**
+     * Lazy set of an injection target because to create fully functional injection target needs already created bean.
+     *
+     * @param injectionTarget {@link javax.enterprise.context.spi.Contextual} information belonging to this bean.
+     */
+    void setInjectionTarget(InjectionTarget<Supplier<T>> injectionTarget) {
+        this.injectionTarget = injectionTarget;
+    }
+
+    public InjectionTarget<Supplier<T>> getInjectionTarget() {
+        return injectionTarget;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/data/BindingBeanPair.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/data/BindingBeanPair.java
new file mode 100644
index 0000000..1d0b2c9
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/data/BindingBeanPair.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+package org.glassfish.jersey.inject.weld.internal.data;
+
+import org.glassfish.jersey.inject.weld.internal.bean.JerseyBean;
+import org.glassfish.jersey.internal.inject.Binding;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Pair of a binding and corresponding Jersey beans.
+ */
+public class BindingBeanPair {
+    private final Binding binding;
+    private final List<JerseyBean> beans = new LinkedList<JerseyBean>();
+
+    public BindingBeanPair(Binding binding, JerseyBean... beans) {
+        this.binding = binding;
+        if (beans != null) {
+            for (JerseyBean bean : beans) {
+                this.beans.add(bean);
+            }
+        }
+    }
+
+    public Binding getBinding() {
+        return binding;
+    }
+
+    public List<JerseyBean> getBeans() {
+        return beans;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/InitializableInstanceBinding.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/InitializableInstanceBinding.java
new file mode 100644
index 0000000..61b4a2c
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/InitializableInstanceBinding.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.inject;
+
+import org.glassfish.jersey.internal.inject.AliasBinding;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.Bindings;
+import org.glassfish.jersey.internal.inject.InstanceBinding;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Injection binding description of a bean bound directly as a specific instance to be created in a pre-initialization phase
+ * and initialized in runtime.
+ *
+ * @param <T> Type of the service described by this injection binding.
+ */
+public class InitializableInstanceBinding<T> extends MatchableBinding<T, InitializableInstanceBinding<T>> implements Cloneable {
+
+    protected T service;
+    private AtomicBoolean isInit = new AtomicBoolean(false);
+    private Class<T> implementationType;
+
+    /**
+     * Creates a service as an instance.
+     *
+     * @param service service's instance.
+     */
+    protected InitializableInstanceBinding(T service) {
+        this(service, null);
+    }
+
+    /**
+     * Creates a service as an instance.
+     *
+     * @param service      service's instance.
+     * @param contractType service's contractType.
+     */
+    private InitializableInstanceBinding(T service, Type contractType) {
+        this.service = service;
+        this.implementationType = service == null ? null : (Class<T>) service.getClass();
+        if (contractType != null) {
+            this.to(contractType);
+        }
+    }
+
+    /**
+     * Gets service' class.
+     *
+     * @return service's class.
+     */
+    public T getService() {
+        if (!isInit.get()) {
+            String types = Arrays.toString(getContracts().toArray());
+            throw new IllegalStateException("Not initialized " + service + "(" + types + ")");
+        }
+        return service;
+    }
+
+    /**
+     * Gets service's type.
+     *
+     * @return service's type.
+     */
+    public Class<T> getImplementationType() {
+        return implementationType;
+    }
+
+    public void init(T service) {
+        if (!isInit.getAndSet(true)) {
+            this.service = service;
+            implementationType = (Class<T>) service.getClass();
+        } else if (this.service != service) {
+            throw new IllegalStateException("Multiple initialized for " + service.getClass());
+        }
+    }
+
+    public boolean isInit() {
+        return isInit.get();
+    }
+
+    public Matching<InitializableInstanceBinding<T>> matches(Binding other) {
+        return super.matches(other);
+    }
+
+    @Override
+    public InitializableInstanceBinding<T> clone() {
+        throw new RuntimeException(new CloneNotSupportedException());
+    }
+
+    public static <T> InitializableInstanceBinding<T> from(InstanceBinding<T> instanceBinding) {
+        return new InitializableWrappingInstanceBinding(instanceBinding);
+    }
+
+    @Override
+    protected MatchLevel bestMatchLevel() {
+        return MatchLevel.IMPLEMENTATION;
+    }
+
+    private static class InitializableWrappingInstanceBinding<T> extends InitializableInstanceBinding<T> {
+        private final InstanceBinding<T> wrapped;
+        public InitializableWrappingInstanceBinding(InstanceBinding<T> binding) {
+            super(binding.getService());
+            wrapped = binding;
+        }
+
+        private InitializableWrappingInstanceBinding(InitializableWrappingInstanceBinding<T> binding) {
+            super(binding.service);
+            wrapped = binding.wrapped;
+        }
+
+        @Override
+        public Class<T> getImplementationType() {
+            return super.getImplementationType();
+        }
+
+        @Override
+        public T getService() {
+            return super.getService();
+        }
+
+        @Override
+        public Class<? extends Annotation> getScope() {
+            return wrapped.getScope();
+        }
+
+        @Override
+        public Set<Type> getContracts() {
+            return wrapped.getContracts();
+        }
+
+        @Override
+        public Integer getRank() {
+            return wrapped.getRank();
+        }
+
+        @Override
+        public Set<AliasBinding> getAliases() {
+            return wrapped.getAliases();
+        }
+
+        @Override
+        public Set<Annotation> getQualifiers() {
+            return wrapped.getQualifiers();
+        }
+
+        @Override
+        public String getAnalyzer() {
+            return wrapped.getAnalyzer();
+        }
+
+        @Override
+        public String getName() {
+            return wrapped.getName();
+        }
+
+        @Override
+        public String toString() {
+            return "InitializableWrappingInstanceBinding(" + wrapped.getService().getClass() + ")";
+        }
+
+        @Override
+        public InitializableWrappingInstanceBinding clone() {
+            return new InitializableWrappingInstanceBinding(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/InitializableSupplierInstanceBinding.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/InitializableSupplierInstanceBinding.java
new file mode 100644
index 0000000..d99bf59
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/InitializableSupplierInstanceBinding.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.inject;
+
+import org.glassfish.jersey.internal.inject.AliasBinding;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.DisposableSupplier;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
+
+/**
+ * Supplier instance binding to be created in the pre-initialization phase and initialized in runtime.
+ * @param <T> Type of the supplied service described by this injection binding.
+ */
+public class InitializableSupplierInstanceBinding<T>
+        extends MatchableBinding<Supplier<T>, InitializableSupplierInstanceBinding<T>>
+        implements Cloneable {
+
+    private final InitializableSupplier<T> supplier;
+
+    /**
+     * Creates a supplier as an instance.
+     *
+     * @param supplier service's instance.
+     */
+    public InitializableSupplierInstanceBinding(Supplier<T> supplier) {
+        this.supplier = DisposableSupplier.class.isInstance(supplier)
+                ? new InitializableDisposableSupplier<T>((DisposableSupplier<T>) supplier)
+                : new InitializableSupplier<T>(supplier);
+        if ("EmptyReferenceFactory".equals(supplier.getClass().getSimpleName())) {
+            this.supplier.init(supplier);
+            this.supplier.isReferencingFactory = true;
+        }
+        if ("InitializedReferenceFactory".equals(supplier.getClass().getSimpleName())) {
+            this.supplier.init(supplier);
+            this.supplier.isReferencingFactory = true;
+        }
+        T t = supplier.get();
+    }
+
+    public void init(Supplier<T> supplier) {
+        this.supplier.init(supplier);
+    }
+
+    public boolean isInit() {
+        return supplier.init.get();
+    }
+
+    /**
+     * Gets supplier's instance.
+     *
+     * @return supplier's instance.
+     */
+    public Supplier<T> getSupplier() {
+        return supplier;
+    }
+
+    public Supplier<T> getOriginalSupplier() {
+        if (supplier.originalSupplier == null) {
+            throw new IllegalStateException("Supplier must not be null");
+        }
+        return supplier.originalSupplier;
+    }
+
+    public static <T> InitializableSupplierInstanceBinding<T> from(SupplierInstanceBinding<T> binding) {
+        return new InitializableSupplierWrappingInstanceBinding(binding);
+    }
+
+    @Override
+    public InitializableSupplierInstanceBinding clone() {
+        throw new RuntimeException(new CloneNotSupportedException());
+    }
+
+    public Matching matches(SupplierInstanceBinding<T> other) {
+        return matches(this.getOriginalSupplier().getClass(), other.getSupplier().getClass(), other);
+    }
+
+    public Matching matches(InitializableSupplierInstanceBinding<T> other) {
+        return matches(this.getOriginalSupplier().getClass(), other.getSupplier().getClass(), other);
+    }
+
+    private Matching<InitializableSupplierInstanceBinding<T>> matches(
+            Class<?> originalSupplierClass, Class<?> otherSupplierClass, Binding other) {
+        final boolean matchesService = originalSupplierClass.equals(otherSupplierClass);
+        final Matching matching = matchesContracts(other);
+        if (matching.matchLevel == MatchLevel.FULL_CONTRACT && matchesService) {
+            matching.matchLevel = MatchLevel.SUPPLIER;
+        }
+        return matching;
+    }
+
+    @Override
+    protected MatchLevel bestMatchLevel() {
+        return MatchLevel.SUPPLIER;
+    }
+
+    private static class InitializableDisposableSupplier<T> extends InitializableSupplier<T> implements DisposableSupplier<T> {
+        private InitializableDisposableSupplier(DisposableSupplier<T> originalSupplier) {
+            super(originalSupplier);
+        }
+
+        @Override
+        public void dispose(T instance) {
+            ((DisposableSupplier) supplier).dispose(instance);
+        }
+    }
+
+    private static class InitializableSupplier<T> implements Supplier<T> {
+
+        private AtomicBoolean init = new AtomicBoolean(false);
+        protected Supplier<T> supplier;
+        protected final Supplier<T> originalSupplier;
+        private boolean isReferencingFactory = false;
+
+        private InitializableSupplier(Supplier<T> originalSupplier) {
+            this.originalSupplier = originalSupplier;
+        }
+
+        private void init(Supplier<T> supply) {
+            if (!init.getAndSet(true)) {
+                this.supplier = supply;
+            } else if (!isReferencingFactory && supplier != supply) {
+                throw new IllegalStateException("Multiple initialized for " + originalSupplier.getClass());
+            }
+        }
+
+        @Override
+        public T get() {
+            if (!init.get()) {
+                throw new IllegalStateException("Not initialized" + originalSupplier.getClass());
+            }
+            return supplier.get();
+        }
+
+        public boolean isInit() {
+            return init.get();
+        }
+    }
+
+    private static class InitializableSupplierWrappingInstanceBinding<T> extends InitializableSupplierInstanceBinding<T> {
+        private final SupplierInstanceBinding wrapped;
+        public InitializableSupplierWrappingInstanceBinding(SupplierInstanceBinding binding) {
+            super(binding.getSupplier());
+            wrapped = binding;
+        }
+
+        private InitializableSupplierWrappingInstanceBinding(InitializableSupplierWrappingInstanceBinding binding) {
+            super(binding.getOriginalSupplier());
+            wrapped = binding.wrapped;
+        }
+
+        @Override
+        public Class getImplementationType() {
+            return super.getImplementationType();
+        }
+
+        @Override
+        public Supplier getSupplier() {
+            return super.getSupplier();
+        }
+
+        @Override
+        public Class<? extends Annotation> getScope() {
+            return wrapped.getScope();
+        }
+
+        @Override
+        public Set<Type> getContracts() {
+            return wrapped.getContracts();
+        }
+
+        @Override
+        public Integer getRank() {
+            return wrapped.getRank();
+        }
+
+        @Override
+        public Set<AliasBinding> getAliases() {
+            return wrapped.getAliases();
+        }
+
+        @Override
+        public Set<Annotation> getQualifiers() {
+            return wrapped.getQualifiers();
+        }
+
+        @Override
+        public String getAnalyzer() {
+            return wrapped.getAnalyzer();
+        }
+
+        @Override
+        public String getName() {
+            return wrapped.getName();
+        }
+
+        @Override
+        public InitializableSupplierWrappingInstanceBinding clone() {
+            return new InitializableSupplierWrappingInstanceBinding(this);
+        }
+
+        @Override
+        public String toString() {
+            return "InitializableSupplierWrappingInstanceBinding(" +  wrapped.getSupplier() + ")";
+        }
+    }
+
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/MatchableBinding.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/MatchableBinding.java
new file mode 100644
index 0000000..e6cd0bd
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/inject/MatchableBinding.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.inject;
+
+import org.glassfish.jersey.internal.inject.Binding;
+
+import java.lang.reflect.Type;
+import java.util.Set;
+
+/**
+ * A Binding to be able to be compared and matched in the runtime to be properly initialized.
+ *
+ * @param <T> Type of the bean described by this injection binding.
+ * @param <D> Concrete injection binding implementation type.
+ */
+public abstract class MatchableBinding<T, D extends MatchableBinding> extends Binding<T, D> {
+
+    protected abstract MatchLevel bestMatchLevel();
+
+    protected Matching<D> matches(Binding<?, ?> other) {
+        final Matching<D> matching = matchesContracts(other);
+        if (matching.matchLevel == MatchLevel.FULL_CONTRACT) {
+            if (getImplementationType().equals(other.getImplementationType())) {
+                matching.matchLevel = MatchLevel.IMPLEMENTATION;
+            }
+        }
+        return matching;
+    }
+
+    /**
+     * Return a Matching object that represents comparison between contracts of this binding and a given binding.
+     * The result contains a reference to this binding.
+     * @param other
+     * @return
+     */
+    public Matching<D> matchesContracts(Binding<?, ?> other) {
+        boolean atLeastOneMatch = false;
+        boolean allMatch = true;
+        final Set<Type> firstContracts = getContracts();
+        final Set<Type> secondContracts = other.getContracts();
+        final Set<Type> biggerContracts = firstContracts.size() < secondContracts.size() ? secondContracts : firstContracts;
+        final Set<Type> smallerContracts = firstContracts.size() < secondContracts.size() ? firstContracts : secondContracts;
+
+        for (Type thisType : biggerContracts) {
+            boolean aMatch = false;
+            for (Type otherType : smallerContracts) {
+                if (thisType.equals(otherType)) {
+                    aMatch = true;
+                    atLeastOneMatch = true;
+                    break;
+                }
+            }
+            if (!aMatch) {
+                allMatch = false;
+            }
+        }
+        final MatchLevel matchLevel = atLeastOneMatch
+                ? (allMatch ? MatchLevel.FULL_CONTRACT : MatchLevel.PARTIAL_CONTRACT)
+                : MatchLevel.NONE;
+        final Matching<D> matching = new Matching<>((D) this, matchLevel);
+        return matching;
+    }
+
+    /**
+     * Matching object that represents the level of a match between two bindings. Contains a reference to a MatchableBinding
+     * whose instance was used to create the Matching object.
+     * @param <D> Concrete injection binding implementation type.
+     */
+    public static class Matching<D extends MatchableBinding> implements Comparable<Matching> {
+        private D binding;
+        protected MatchLevel matchLevel;
+
+        public static <D extends MatchableBinding> Matching<D> noneMatching() {
+            return new Matching<D>(null, MatchLevel.NONE);
+        }
+
+        protected Matching(D binding, MatchLevel matchLevel) {
+            this.binding = binding;
+            this.matchLevel = matchLevel;
+        }
+
+        @Override
+        public int compareTo(Matching other) {
+            return other.matchLevel.level - this.matchLevel.level;
+        }
+
+        public Matching better(Matching other) {
+            return compareTo(other) <= 0 ? this : other;
+        }
+
+        public boolean isBest() {
+            return matches() && matchLevel == binding.bestMatchLevel();
+        }
+
+        public boolean matches() {
+            return matchLevel.level > MatchLevel.NONE.level;
+        }
+
+        public D getBinding() {
+            return binding;
+        }
+    }
+
+    /**
+     * Internal granularity of a Matching.
+     */
+    protected static enum MatchLevel {
+        NONE(0),
+        PARTIAL_CONTRACT(1),
+        FULL_CONTRACT(2),
+        IMPLEMENTATION(3),
+        SUPPLIER(4);
+
+        private final int level;
+
+        MatchLevel(int level) {
+            this.level = level;
+        }
+    }
+}
+
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/AbstractInjectionTarget.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/AbstractInjectionTarget.java
new file mode 100644
index 0000000..9b79ffa
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/AbstractInjectionTarget.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+
+/**
+ * Abstract class which implements all methods from {@link InjectionTarget} by invoking the same methods on the delegate object.
+ * Useful super class to extend and override only the needed method.
+ *
+ * @param <T> type of the injection target.
+ * @author Petr Bouda
+ */
+abstract class AbstractInjectionTarget<T> implements InjectionTarget<T> {
+
+    /**
+     * Object on which all calls will be delegated.
+     *
+     * @return injection target.
+     */
+    abstract InjectionTarget<T> delegate();
+
+    @Override
+    public void inject(final T instance, final CreationalContext<T> ctx) {
+        delegate().inject(instance, ctx);
+    }
+
+    @Override
+    public void postConstruct(final T instance) {
+        delegate().postConstruct(instance);
+    }
+
+    @Override
+    public void preDestroy(final T instance) {
+        delegate().preDestroy(instance);
+    }
+
+    @Override
+    public T produce(final CreationalContext<T> ctx) {
+        return delegate().produce(ctx);
+    }
+
+    @Override
+    public void dispose(final T instance) {
+        delegate().dispose(instance);
+    }
+
+    @Override
+    public Set<InjectionPoint> getInjectionPoints() {
+        return delegate().getInjectionPoints();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzer.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzer.java
new file mode 100644
index 0000000..2042642
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzer.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.logging.Logger;
+
+import javax.enterprise.inject.InjectionException;
+import javax.inject.Inject;
+
+import org.glassfish.jersey.internal.LocalizationMessages;
+import org.glassfish.jersey.internal.util.collection.LazyValue;
+import org.glassfish.jersey.internal.util.collection.Value;
+import org.glassfish.jersey.internal.util.collection.Values;
+
+/**
+ * Processes a provided class and selects the valid constructor with the largest number of parameters. Constructor is cached
+ * for a later retrieve.
+ */
+public class CachedConstructorAnalyzer<T> {
+
+    private static final Logger LOGGER = Logger.getLogger(CachedConstructorAnalyzer.class.getName());
+
+    private final LazyValue<Constructor<T>> constructor;
+    private final Collection<Class<? extends Annotation>> resolverAnnotations;
+
+    /**
+     * Creates a new constructor analyzer which accepts the class that is analyzed.
+     *
+     * @param clazz       analyzed class.
+     * @param annotations all annotations used for an injecting.
+     */
+    public CachedConstructorAnalyzer(Class<T> clazz, Collection<Class<? extends Annotation>> annotations) {
+        this.resolverAnnotations = annotations;
+        this.constructor = Values.lazy((Value<Constructor<T>>) () -> getConstructorInternal(clazz));
+    }
+
+    public Constructor<T> getConstructor() {
+        return constructor.get();
+    }
+
+    public boolean hasCompatibleConstructor() {
+        try {
+            return constructor.get() != null;
+        } catch (InjectionException ex) {
+            // Compatible constructor was not found.
+            return false;
+        }
+    }
+
+    /**
+     * Select the proper constructor of the given {@code clazz}.
+     *
+     * @return compatible and largest constructor.
+     */
+    @SuppressWarnings("unchecked")
+    private Constructor<T> getConstructorInternal(Class<T> clazz) {
+        if (clazz.isLocalClass()) {
+            throw new InjectionException(
+                    LocalizationMessages.INJECTION_ERROR_LOCAL_CLASS_NOT_SUPPORTED(clazz.getName()));
+        }
+        if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
+            throw new InjectionException(
+                    LocalizationMessages.INJECTION_ERROR_NONSTATIC_MEMBER_CLASS_NOT_SUPPORTED(clazz.getName()));
+        }
+
+        // At this point, we simply need to find the constructor with the largest number of parameters
+        Constructor<?>[] constructors = AccessController.doPrivileged(
+                (PrivilegedAction<Constructor<?>[]>) clazz::getDeclaredConstructors);
+        Constructor<?> selected = null;
+        int selectedSize = 0;
+        int maxParams = -1;
+
+        for (Constructor<?> constructor : constructors) {
+            Class<?>[] params = constructor.getParameterTypes();
+            if (params.length >= maxParams && isCompatible(constructor)) {
+                if (params.length > maxParams) {
+                    maxParams = params.length;
+                    selectedSize = 0;
+                }
+
+                selected = constructor;
+                selectedSize++;
+            }
+        }
+
+        if (selectedSize == 0) {
+            throw new InjectionException(LocalizationMessages.INJECTION_ERROR_SUITABLE_CONSTRUCTOR_NOT_FOUND(clazz.getName()));
+        }
+
+        if (selectedSize > 1) {
+            // Found {0} constructors with {1} parameters in {2} class. Selecting the first found constructor: {3}
+            LOGGER.warning(LocalizationMessages.MULTIPLE_MATCHING_CONSTRUCTORS_FOUND(
+                    selectedSize, maxParams, clazz.getName(), selected.toGenericString()));
+        }
+
+        return (Constructor<T>) selected;
+    }
+
+    /**
+     * Checks whether the constructor is valid for injection that means that all parameters has an injection annotation.
+     *
+     * @param constructor constructor to inject.
+     * @return True if element contains at least one inject annotation.
+     */
+    @SuppressWarnings("MagicConstant")
+    private boolean isCompatible(Constructor<?> constructor) {
+        if (constructor.getAnnotation(Inject.class) != null) {
+            // JSR-330 applicable
+            return true;
+        }
+
+        int paramSize = constructor.getParameterTypes().length;
+        if (paramSize != 0 && resolverAnnotations.isEmpty()) {
+            return false;
+        }
+
+        if (!Modifier.isPublic(constructor.getModifiers())) {
+            // return true for a default constructor, return false otherwise.
+            return paramSize == 0
+                    && (constructor.getDeclaringClass().getModifiers()
+                                & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)) == constructor.getModifiers();
+        }
+
+        for (Annotation[] paramAnnotations : constructor.getParameterAnnotations()) {
+            boolean found = false;
+            for (Annotation paramAnnotation : paramAnnotations) {
+                if (resolverAnnotations.contains(paramAnnotation.annotationType())) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/Collector.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/Collector.java
new file mode 100644
index 0000000..97077b2
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/Collector.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+
+/**
+ * This class collects errors, and can then also produce a MultiException from those errors if necessary.
+ *
+ * @author John Wells (john.wells at oracle.com)
+ */
+class Collector {
+
+    private LinkedHashSet<Throwable> throwables;
+
+    /**
+     * Merges {@link MultiException} with all {@code throwables} registered in it.
+     *
+     * @param me {@code MultiException} to merge.
+     */
+    public void addMultiException(MultiException me) {
+        if (me == null) {
+            return;
+        }
+        if (throwables == null) {
+            throwables = new LinkedHashSet<>();
+        }
+
+        throwables.addAll(me.getErrors());
+    }
+
+    /**
+     * Adds a throwable to the list of throwables in this collector.
+     *
+     * @param th The throwable to add to the list.
+     */
+    public void addThrowable(Throwable th) {
+        if (th == null) {
+            return;
+        }
+        if (throwables == null) {
+            throwables = new LinkedHashSet<>();
+        }
+
+        if (th instanceof MultiException) {
+            throwables.addAll(((MultiException) th).getErrors());
+        } else {
+            throwables.add(th);
+        }
+    }
+
+    /**
+     * This method will throw if the list of throwables associated with this collector is not empty.
+     *
+     * @throws MultiException An exception with all the throwables found in this collector.
+     */
+    public void throwIfErrors() throws MultiException {
+        if (throwables == null || throwables.isEmpty()) {
+            return;
+        }
+
+        throw new MultiException(new LinkedList<>(throwables));
+    }
+
+    /**
+     * Returns true if this collector has errors.
+     *
+     * @return true if the collector has errors.
+     */
+    public boolean hasErrors() {
+        return ((throwables != null) && (!throwables.isEmpty()));
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/ContextInjectionResolverImpl.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/ContextInjectionResolverImpl.java
new file mode 100644
index 0000000..b494906
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/ContextInjectionResolverImpl.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.reflect.Type;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.GenericType;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.Bindings;
+import org.glassfish.jersey.internal.inject.ContextInjectionResolver;
+import org.glassfish.jersey.internal.inject.Injectee;
+import org.glassfish.jersey.internal.inject.InjecteeImpl;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+import org.glassfish.jersey.internal.util.ReflectionHelper;
+import org.glassfish.jersey.internal.util.collection.Cache;
+
+/**
+ * Injection resolver for {@link Context @Context} injection annotation.
+ *
+ * @author Petr Bouda
+ */
+public class ContextInjectionResolverImpl implements InjectionResolver<Context>, ContextInjectionResolver {
+
+    private Supplier<BeanManager> beanManager;
+
+    /**
+     * Creates a new {@link ContextInjectionResolver} with {@link BeanManager} to fetch Bean descriptors.
+     *
+     * @param beanManager current bean manager.
+     */
+    ContextInjectionResolverImpl(Supplier<BeanManager> beanManager) {
+        this.beanManager = beanManager;
+    }
+
+    private final Cache<Type, Bean<?>> descriptorCache = new Cache<>(key -> {
+        Set<Bean<?>> beans = beanManager.get().getBeans(key);
+        if (beans.isEmpty()) {
+            return null;
+        }
+        return beans.iterator().next();
+    });
+
+    @Override
+    public Object resolve(Injectee injectee) {
+        Injectee newInjectee = injectee;
+        if (injectee.isFactory()) {
+            newInjectee = getFactoryInjectee(injectee, ReflectionHelper.getTypeArgument(injectee.getRequiredType(), 0));
+        }
+
+        Bean<?> bean = descriptorCache.apply(newInjectee.getRequiredType());
+
+        if (bean != null) {
+            CreationalContext ctx = beanManager.get().createCreationalContext(bean);
+            Object result = bean.create(ctx);
+
+            if (injectee.isFactory()) {
+                return (Supplier<Object>) () -> result;
+            } else {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean isConstructorParameterIndicator() {
+        return true;
+    }
+
+    @Override
+    public boolean isMethodParameterIndicator() {
+        return false;
+    }
+
+    @Override
+    public Class<Context> getAnnotation() {
+        return Context.class;
+    }
+
+    /**
+     * Context injection resolver binder.
+     */
+    public static final class Binder extends AbstractBinder {
+
+        private Supplier<BeanManager> beanManager;
+
+        public Binder(Supplier<BeanManager> beanManager) {
+            this.beanManager = beanManager;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        protected void configure() {
+            ContextInjectionResolverImpl resolver = new ContextInjectionResolverImpl(beanManager);
+
+            /*
+             * Binding for CDI, without this binding JerseyInjectionTarget wouldn't know about the ContextInjectionTarget and
+             * injection into fields would be disabled.
+             */
+            bind(resolver)
+                    .to(new GenericType<InjectionResolver<Context>>() {})
+                    .to(ContextInjectionResolver.class);
+
+            /*
+             * Binding for Jersey, without this binding Jersey wouldn't put together ContextInjectionResolver and
+             * DelegatedInjectionValueParamProvider and therefore injection into resource method would be disabled.
+             */
+            bind(Bindings.service(resolver))
+                    .to(new GenericType<InjectionResolver<Context>>() {})
+                    .to(ContextInjectionResolver.class);
+        }
+    }
+
+    private Injectee getFactoryInjectee(Injectee injectee, Type requiredType) {
+        return new RequiredTypeOverridingInjectee(injectee, requiredType);
+    }
+
+    private static class RequiredTypeOverridingInjectee extends InjecteeImpl {
+        private RequiredTypeOverridingInjectee(Injectee injectee, Type requiredType) {
+            setFactory(injectee.isFactory());
+            setInjecteeClass(injectee.getInjecteeClass());
+            setInjecteeDescriptor(injectee.getInjecteeDescriptor());
+            setOptional(injectee.isOptional());
+            setParent(injectee.getParent());
+            setPosition(injectee.getPosition());
+            setRequiredQualifiers(injectee.getRequiredQualifiers());
+            setRequiredType(requiredType);
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/InjectionUtils.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/InjectionUtils.java
new file mode 100644
index 0000000..946db4d
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/InjectionUtils.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import javax.enterprise.inject.spi.Bean;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+import org.glassfish.jersey.internal.inject.Injectee;
+import org.glassfish.jersey.internal.inject.InjecteeImpl;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+import org.glassfish.jersey.internal.util.Pretty;
+import org.glassfish.jersey.internal.util.collection.ImmutableCollectors;
+
+/**
+ * Utility class for processing of an injection.
+ *
+ * @author Petr Bouda
+ */
+public final class InjectionUtils {
+
+    /**
+     * Forbids the creation of {@link InjectionUtils} instance.
+     */
+    private InjectionUtils() {
+    }
+
+    /**
+     * Just injects the thing, doesn't try to do anything else
+     *
+     * @param injectMe      the object to inject into.
+     * @param bean          information about the injected instance.
+     * @param resolvers     all injection resolvers registered in the application.
+     * @param proxyResolver object which is able to create a proxy.
+     * @param <T>           type of the injected instance.
+     */
+    static <T> void justInject(T injectMe, Bean<T> bean, Map<Field, InjectionResolver> resolvers,
+            JerseyProxyResolver proxyResolver) {
+        if (injectMe == null) {
+            throw new IllegalArgumentException();
+        }
+
+        for (Map.Entry<Field, InjectionResolver> entry : resolvers.entrySet()) {
+            Field field = entry.getKey();
+            InjectionResolver resolver = entry.getValue();
+            Injectee injectee = InjectionUtils.getFieldInjectee(bean, field);
+
+            Object resolvedValue;
+            if (injectee.isProvider()) {
+                resolvedValue = (Provider<Object>) () -> resolver.resolve(injectee);
+            } else if (proxyResolver.isProxiable(injectee)) {
+                resolvedValue = proxyResolver.proxy(injectee, resolver);
+            } else {
+                resolvedValue = resolver.resolve(injectee);
+            }
+
+            try {
+                ReflectionUtils.setField(field, injectMe, resolvedValue);
+            } catch (MultiException me) {
+                throw me;
+            } catch (Throwable th) {
+                throw new MultiException(th);
+            }
+        }
+    }
+
+    /**
+     * Returns the injectee for a field.
+     *
+     * @param bean bean in which the field is placed.
+     * @param field      the field to analyze.
+     * @return the list (in order) of parameters to the constructor.
+     */
+    private static Injectee getFieldInjectee(Bean<?> bean, Field field) {
+        Set<Annotation> annotations = Arrays.stream(field.getAnnotations())
+                .collect(ImmutableCollectors.toImmutableSet());
+
+        Type adjustedType = ReflectionUtils.resolveField(bean.getBeanClass(), field);
+
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setParentClassScope(bean.getScope());
+
+        if (isProvider(adjustedType)) {
+            ParameterizedType paramType = (ParameterizedType) adjustedType;
+            injectee.setRequiredType(paramType.getActualTypeArguments()[0]);
+            injectee.setProvider(true);
+        } else {
+            injectee.setRequiredType(adjustedType);
+        }
+
+        injectee.setParent(field);
+        injectee.setRequiredQualifiers(getFieldAdjustedQualifierAnnotations(field, annotations));
+        return injectee;
+    }
+
+    public static boolean isProvider(Type type) {
+        if (type instanceof ParameterizedType) {
+            ParameterizedType paramType = (ParameterizedType) type;
+            return Provider.class.isAssignableFrom((Class<?>) paramType.getRawType());
+        }
+
+        return false;
+    }
+
+    private static Set<Annotation> getFieldAdjustedQualifierAnnotations(Field field, Set<Annotation> qualifiers) {
+        Named n = field.getAnnotation(Named.class);
+        if (n == null || !"".equals(n.value())) {
+            return qualifiers;
+        }
+
+        HashSet<Annotation> retVal = new HashSet<>();
+        for (Annotation qualifier : qualifiers) {
+            if (qualifier.annotationType().equals(Named.class)) {
+                retVal.add(new NamedImpl(field.getName()));
+            } else {
+                retVal.add(qualifier);
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Gets the fields from the given class and analyzer. Checks service output.
+     *
+     * @param clazz             the non-null impl class.
+     * @param injectAnnotations all annotations which can be used to inject a value.
+     * @param errors            for gathering errors.  @return a non-null set (even in error cases, check the collector).
+     */
+    static Set<Field> getFields(Class<?> clazz, Set<? extends Class<?>> injectAnnotations, Collector errors) {
+        Set<Field> retVal;
+
+        try {
+            retVal = getFieldsInternal(clazz, injectAnnotations, errors);
+        } catch (MultiException me) {
+            errors.addMultiException(me);
+            return Collections.emptySet();
+        } catch (Throwable th) {
+            errors.addThrowable(th);
+            return Collections.emptySet();
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Will find all the initialize fields in the class.
+     *
+     * @param clazz             the class to search for fields
+     * @param injectAnnotations all annotations which can be used to inject a value.
+     * @param errors            the error collector
+     * @return A non-null but possibly empty set of initializer fields
+     */
+    private static Set<Field> getFieldsInternal(Class<?> clazz, Set<? extends Class<?>> injectAnnotations, Collector errors) {
+        Set<Field> retVal = new LinkedHashSet<>();
+
+        for (Field field : ReflectionUtils.getAllFields(clazz)) {
+            if (!hasInjectAnnotation(field, injectAnnotations)) {
+                // Not an initializer field
+                continue;
+            }
+
+            if (!isProperField(field)) {
+                errors.addThrowable(new IllegalArgumentException("The field " + Pretty.field(field)
+                        + " may not be static, final or have an Annotation type"));
+                continue;
+            }
+
+            retVal.add(field);
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Checks whether an annotated element has any annotation that was used for the injection.
+     *
+     * @param annotated         the annotated element.
+     * @param injectAnnotations all annotations which can be used to inject a value.
+     * @return True if element contains at least one inject annotation.
+     */
+    private static boolean hasInjectAnnotation(AnnotatedElement annotated, Set<? extends Class<?>> injectAnnotations) {
+        for (Annotation annotation : annotated.getAnnotations()) {
+            if (injectAnnotations.contains(annotation.annotationType())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static boolean isProperField(Field field) {
+        if (isStatic(field) || isFinal(field)) {
+            return false;
+        }
+
+        Class<?> type = field.getType();
+        return !type.isAnnotation();
+    }
+
+    /**
+     * Returns true if the underlying member is static.
+     *
+     * @param member The non-null member to test.
+     * @return true if the member is static.
+     */
+    private static boolean isStatic(Member member) {
+        int modifiers = member.getModifiers();
+        return ((modifiers & Modifier.STATIC) != 0);
+    }
+
+    /**
+     * Returns true if the underlying member is abstract.
+     *
+     * @param member The non-null member to test.
+     * @return true if the member is abstract.
+     */
+    private static boolean isFinal(Member member) {
+        int modifiers = member.getModifiers();
+        return ((modifiers & Modifier.FINAL) != 0);
+    }
+
+    /**
+     * Returns all annotations that can be managed using registered and provided {@link InjectionResolver injection resolvers}.
+     *
+     * @param resolvers all registered resolvers.
+     * @return all possible injection annotations.
+     */
+    @SuppressWarnings("unchecked")
+    public static Collection<Class<? extends Annotation>> getInjectAnnotations(Collection<InjectionResolver> resolvers) {
+        List<Class<? extends Annotation>> annotations = new ArrayList<>();
+        for (InjectionResolver resolver : resolvers) {
+            annotations.add(resolver.getAnnotation());
+        }
+        return annotations;
+    }
+
+    /**
+     * Assigns {@link InjectionResolver} to every {@link AnnotatedElement} provided as a method parameter. Injection resolver
+     * will be used for fetching the proper value during the injection processing.
+     *
+     * @param annotatedElements all annotated elements from the class which this injector belongs to.
+     * @param resolvers         all registered injection resolvers.
+     * @param <A>               type of the annotated elements.
+     * @return immutable map of all fields along with injection resolvers using that can be injected.
+     */
+    static <A extends AnnotatedElement> Map<A, InjectionResolver> mapElementToResolver(Set<A> annotatedElements,
+            Map<? extends Class<?>, InjectionResolver> resolvers) {
+
+        Map<A, InjectionResolver> mappedElements = new HashMap<>();
+        for (A element : annotatedElements) {
+            mappedElements.put(element, findResolver(resolvers, element));
+        }
+        return mappedElements;
+    }
+
+    static InjectionResolver findResolver(Map<? extends Class<?>, InjectionResolver> resolvers, AnnotatedElement element) {
+        for (Annotation annotation : element.getAnnotations()) {
+            InjectionResolver injectionResolver = resolvers.get(annotation.annotationType());
+            if (injectionResolver != null) {
+                return injectionResolver;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates a map from resolvers where the annotation that is handled by resolver is a key and resolver itself is value.
+     *
+     * @param resolvers collection of resolvers.
+     * @return map resolver annotation to resolver.
+     */
+    static Map<? extends Class<?>, InjectionResolver> mapAnnotationToResolver(Collection<InjectionResolver> resolvers) {
+        return resolvers.stream().collect(Collectors.toMap(InjectionResolver::getAnnotation, Function.identity()));
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyClientCreationalContext.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyClientCreationalContext.java
new file mode 100644
index 0000000..529b94f
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyClientCreationalContext.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+
+import org.glassfish.jersey.inject.weld.internal.managed.CdiClientInjectionManager;
+import org.jboss.weld.construction.api.AroundConstructCallback;
+import org.jboss.weld.context.api.ContextualInstance;
+import org.jboss.weld.contexts.CreationalContextImpl;
+import org.jboss.weld.injection.spi.ResourceReference;
+import org.jboss.weld.interceptor.proxy.InterceptionContext;
+
+import java.util.List;
+
+/**
+ * Jersey implementation of CreationalContext holding an instance of the client InjectionManager.
+ * Should be used on the client side only. Wraps the original context.
+ * @param <T> the class of the creational context.
+ */
+public class JerseyClientCreationalContext<T> extends CreationalContextImpl<T> {
+
+    private final CreationalContextImpl<T> wrapped;
+    private CdiClientInjectionManager injectionManager = null;
+
+    public JerseyClientCreationalContext(CreationalContextImpl<T> wrapped) {
+        super(wrapped.getContextual());
+        this.wrapped = wrapped;
+    }
+
+    @Override
+    public <S> CreationalContextImpl<S> getCreationalContext(Contextual<S> contextual) {
+        return new JerseyClientCreationalContext<>(wrapped.getCreationalContext(contextual))
+                .setInjectionManager(injectionManager);
+    }
+
+    public <S> CreationalContextImpl<S> getProducerReceiverCreationalContext(Contextual<S> contextual) {
+        return new JerseyClientCreationalContext<>(wrapped.getProducerReceiverCreationalContext(contextual))
+                .setInjectionManager(injectionManager);
+    }
+
+    public <S> S getIncompleteInstance(Contextual<S> bean) {
+        return wrapped.getIncompleteInstance(bean);
+    }
+
+    public boolean containsIncompleteInstance(Contextual<?> bean) {
+        return wrapped.containsIncompleteInstance(bean);
+    }
+
+    public void addDependentInstance(ContextualInstance<?> contextualInstance) {
+        wrapped.addDependentInstance(contextualInstance);
+    }
+
+    public void release() {
+        wrapped.release();
+    }
+
+    public void release(Contextual<T> contextual, T instance) {
+        wrapped.release(contextual, instance);
+    }
+
+    /**
+     * @return the parent {@link CreationalContext} or null if there isn't any parent.
+     */
+    public CreationalContextImpl<?> getParentCreationalContext() {
+        return wrapped.getParentCreationalContext();
+    }
+
+    /**
+     * Returns an unmodifiable list of dependent instances.
+     */
+    public List<ContextualInstance<?>> getDependentInstances() {
+        return wrapped.getDependentInstances();
+    }
+
+    /**
+     * Register a {@link ResourceReference} as a dependency. {@link ResourceReference#release()} will be called on every {@link ResourceReference} once this
+     * {@link CreationalContext} instance is released.
+     */
+    public void addDependentResourceReference(ResourceReference<?> resourceReference) {
+        wrapped.addDependentResourceReference(resourceReference);
+    }
+
+    /**
+     * Destroys dependent instance
+     *
+     * @param instance
+     * @return true if the instance was destroyed, false otherwise
+     */
+    public boolean destroyDependentInstance(T instance) {
+        return wrapped.destroyDependentInstance(instance);
+    }
+
+    /**
+     * @return the {@link Contextual} for which this {@link CreationalContext} is created.
+     */
+    public Contextual<T> getContextual() {
+        return wrapped.getContextual();
+    }
+
+    public List<AroundConstructCallback<T>> getAroundConstructCallbacks() {
+        return wrapped.getAroundConstructCallbacks();
+    }
+
+    @Override
+    public void setConstructorInterceptionSuppressed(boolean value) {
+        wrapped.setConstructorInterceptionSuppressed(value);
+    }
+
+    @Override
+    public boolean isConstructorInterceptionSuppressed() {
+        return wrapped.isConstructorInterceptionSuppressed();
+    }
+
+    @Override
+    public void registerAroundConstructCallback(AroundConstructCallback<T> callback) {
+        wrapped.registerAroundConstructCallback(callback);
+    }
+
+    /**
+     *
+     * @return the interception context used for Weld-managed AroundConstruct interceptors or <code>null</code> if no such interceptors were applied
+     */
+    public InterceptionContext getAroundConstructInterceptionContext() {
+        return wrapped.getAroundConstructInterceptionContext();
+    }
+
+    public void setAroundConstructInterceptionContext(InterceptionContext aroundConstructInterceptionContext) {
+        wrapped.setAroundConstructInterceptionContext(aroundConstructInterceptionContext);
+    }
+
+    public JerseyClientCreationalContext setInjectionManager(CdiClientInjectionManager injectionManager) {
+        this.injectionManager = injectionManager;
+        return this;
+    }
+
+    public CdiClientInjectionManager getInjectionManager() {
+        return injectionManager;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyConstructorInjectionPoint.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyConstructorInjectionPoint.java
new file mode 100644
index 0000000..d2677ac
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyConstructorInjectionPoint.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Parameter;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.inject.Provider;
+
+import org.glassfish.jersey.internal.inject.Injectee;
+import org.glassfish.jersey.internal.inject.InjecteeImpl;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+
+import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedConstructor;
+import org.jboss.weld.injection.ConstructorInjectionPoint;
+import org.jboss.weld.injection.InjectionPointFactory;
+import org.jboss.weld.injection.ParameterInjectionPoint;
+import org.jboss.weld.manager.BeanManagerImpl;
+
+/**
+ * Class that creates a new instance using the provided constructor, selects and injects the values.
+ *
+ * @author Petr Bouda
+ */
+public class JerseyConstructorInjectionPoint<T> extends ConstructorInjectionPoint<T> {
+
+    private final JerseyProxyResolver proxyResolver = new JerseyProxyResolver();
+
+    private List<Supplier<Object>> cachedSuppliers;
+
+    private Object[] cachedProxies;
+
+    /**
+     * Creates a new constructor injection point suitable for Jersey components.
+     *
+     * @param constructor resolved constructor that can be injected using Jersey.
+     * @param bean        bean descriptor dedicated to the parent class.
+     * @param manager     current bean manager.
+     * @param resolvers   all registered resolvers.
+     */
+    public JerseyConstructorInjectionPoint(EnhancedAnnotatedConstructor<T> constructor, Bean<T> bean, BeanManagerImpl manager,
+            Collection<InjectionResolver> resolvers) {
+        super(constructor, null, constructor.getJavaClass(), InjectionPointFactory.instance(), manager);
+
+        List<InjecteeToSupplier> valueSuppliers =
+                createValueSuppliers(constructor.getJavaMember(), getParameterInjectionPoints(), resolvers);
+
+        /*
+         * Caches either created proxies if the component class is not RequestScoped or caches the supplier that just create
+         * values every component creates.
+         */
+        if (proxyResolver.isProxiable(bean.getScope())) {
+            this.cachedProxies = generateProxies(valueSuppliers);
+        } else {
+            this.cachedSuppliers = valueSuppliers.stream()
+                    .map(is -> is.supplier)
+                    .collect(Collectors.toList());
+        }
+    }
+
+    /**
+     * Helper method for getting the current parameter values from a list of annotated parameters.
+     *
+     * @param manager The Bean manager
+     * @return The object array of looked up values
+     */
+    public Object[] getParameterValues(BeanManagerImpl manager, CreationalContext<?> ctx, CreationalContext<?> ctxTransient) {
+        if (cachedProxies == null) {
+            return generateValues(cachedSuppliers);
+        } else {
+            return cachedProxies;
+        }
+    }
+
+    private Object[] generateValues(List<Supplier<Object>> suppliers) {
+        Object[] parameterValues = new Object[getParameterInjectionPoints().size()];
+        for (int i = 0; i < parameterValues.length; i++) {
+            parameterValues[i] = suppliers.get(i).get();
+        }
+        return parameterValues;
+    }
+
+    private Object[] generateProxies(List<InjecteeToSupplier> suppliers) {
+        Object[] proxies = new Object[suppliers.size()];
+        for (int i = 0; i < proxies.length; i++) {
+            InjecteeToSupplier injecteeToSupplier = suppliers.get(i);
+            if (injecteeToSupplier.injectee.isProvider()) {
+                proxies[i] = new Provider<Object>() {
+                    @Override
+                    public Object get() {
+                        return injecteeToSupplier.supplier.get();
+                    }
+                };
+            } else {
+                proxies[i] = proxyResolver.noCachedProxy(injecteeToSupplier.injectee, injecteeToSupplier.supplier);
+            }
+        }
+        return proxies;
+    }
+
+    /**
+     * Maps the parameters of the selected constructor to the injection resolver.
+     *
+     * @param params    all parameters of a constructor.
+     * @param resolvers registered injection resolvers.
+     * @return map of the parameter to injection resolver.
+     */
+    private List<InjecteeToSupplier> createValueSuppliers(Constructor<T> constructor,
+            List<ParameterInjectionPoint<?, T>> params, Collection<InjectionResolver> resolvers) {
+
+        List<InjecteeToSupplier> suppliers = new ArrayList<>();
+        Map<? extends Class<?>, InjectionResolver> injectAnnotations = InjectionUtils.mapAnnotationToResolver(resolvers);
+        for (int i = 0; i < params.size(); i++) {
+            Parameter parameter = params.get(i).getAnnotated().getJavaParameter();
+            InjectionResolver resolver = InjectionUtils.findResolver(injectAnnotations, parameter);
+            Injectee injectee = parameterToInjectee(constructor, parameter, i);
+//            if (!Class.class.isInstance(injectee.getRequiredType()) || ((Class) injectee.getRequiredType()).isInterface()) {
+                suppliers.add(new InjecteeToSupplier(injectee, () -> resolver.resolve(injectee)));
+//            }
+        }
+
+        return suppliers;
+    }
+
+    private Injectee parameterToInjectee(Constructor<T> constructor, Parameter parameter, int position) {
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setParent(constructor);
+        if (parameter.getParameterizedType() instanceof ParameterizedType
+                && InjectionUtils.isProvider(parameter.getParameterizedType())) {
+            ParameterizedType paramType = (ParameterizedType) parameter.getParameterizedType();
+            injectee.setRequiredType(paramType.getActualTypeArguments()[0]);
+            injectee.setProvider(true);
+        } else {
+            injectee.setRequiredType(parameter.getType());
+        }
+        injectee.setPosition(position);
+        return injectee;
+    }
+
+    /**
+     * Holder for Injectee and Supplier types. Internal class.
+     */
+    private static class InjecteeToSupplier {
+
+        private final Injectee injectee;
+        private final Supplier<Object> supplier;
+
+        private InjecteeToSupplier(Injectee injectee, Supplier<Object> supplier) {
+            this.injectee = injectee;
+            this.supplier = supplier;
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyInjectionTarget.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyInjectionTarget.java
new file mode 100644
index 0000000..e5702c0
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyInjectionTarget.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.List;
+
+import javax.enterprise.context.Dependent;
+import javax.ws.rs.WebApplicationException;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.InjectionException;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.Decorator;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.inject.spi.Interceptor;
+
+import org.glassfish.jersey.inject.weld.internal.bean.BeanHelper;
+import org.glassfish.jersey.inject.weld.internal.bean.JerseyBean;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+import org.glassfish.jersey.internal.util.collection.LazyValue;
+import org.glassfish.jersey.internal.util.collection.Value;
+import org.glassfish.jersey.internal.util.collection.Values;
+
+import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedConstructor;
+import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedMethod;
+import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
+import org.jboss.weld.bean.CustomDecoratorWrapper;
+import org.jboss.weld.bean.DecoratorImpl;
+import org.jboss.weld.bean.proxy.ProxyInstantiator;
+import org.jboss.weld.injection.producer.AbstractInstantiator;
+import org.jboss.weld.injection.producer.BasicInjectionTarget;
+import org.jboss.weld.injection.producer.ConstructorInterceptionInstantiator;
+import org.jboss.weld.injection.producer.DefaultInstantiator;
+import org.jboss.weld.injection.producer.Instantiator;
+import org.jboss.weld.injection.producer.InterceptionModelInitializer;
+import org.jboss.weld.injection.producer.InterceptorApplyingInstantiator;
+import org.jboss.weld.injection.producer.SubclassDecoratorApplyingInstantiator;
+import org.jboss.weld.injection.producer.SubclassedComponentInstantiator;
+import org.jboss.weld.interceptor.spi.model.InterceptionModel;
+import org.jboss.weld.logging.BeanLogger;
+import org.jboss.weld.resources.ClassTransformer;
+import org.jboss.weld.util.reflection.Formats;
+
+/**
+ * Wrapper for {@link InjectionTarget} that implements the functionality of injecting using JAX-RS annotations into provided
+ * instances. {@code Delegate} is a original {@code InjectionTarget} which is able to inject other fields/parameters which
+ * are managed by CDI.
+ * <p>
+ * Implementation is also able create with custom {@code jerseyConstructor} if it is provided. This functionality allows override
+ * default instantiator and use the Jersey-specific one.
+ */
+public class JerseyInjectionTarget<T> extends BasicInjectionTarget<T> {
+
+    private final Bean<T> bean;
+    private final Class<T> clazz;
+    private final LazyValue<JerseyInstanceInjector<T>> injector;
+    private final EnhancedAnnotatedType<T> enhancedAnnotatedType;
+    private Collection<InjectionResolver> resolvers;
+    private BasicInjectionTarget delegate; // for managed beans the initializeAfterBeanDiscovery is called for it
+    private final Instantiator<T> instantiator;
+
+    /**
+     * Creates a new injection target which is able to delegate an injection to {@code delegate injection target} and inject
+     * the fields that are Jersey-specific. The resolvers must be set later on. CDI will select its own constructor.
+     *
+     * @param delegate CDI specific injection target.
+     * @param clazz    class that will be scanned and injected.
+     */
+    public JerseyInjectionTarget(BasicInjectionTarget<T> delegate, Class<T> clazz) {
+        this(delegate, delegate.getBean(), clazz, null);
+    }
+
+    /**
+     * Creates a new injection target which is able to delegate an injection to {@code delegate injection target} and inject
+     * the fields that are Jersey-specific. CDI will select its own constructor.
+     *
+     * @param delegate  CDI specific injection target.
+     * @param bean      bean which this injection target belongs to.
+     * @param clazz     class that will be scanned and injected.
+     * @param resolvers all resolvers that can provide a valued for Jersey-specific injection.
+     */
+    public JerseyInjectionTarget(BasicInjectionTarget<T> delegate, Bean<T> bean, Class<T> clazz,
+            Collection<InjectionResolver> resolvers) {
+        this(BeanHelper.createEnhancedAnnotatedType(delegate), delegate, bean, clazz, resolvers, delegate.getInstantiator());
+        this.delegate = delegate;
+        setInstantiator(this.instantiator);
+    }
+
+    /**
+     * Creates a new injection target which is able to delegate an injection to {@code delegate injection target} and inject
+     * the fields that are Jersey-specific. This method accepts custom instantiator, if the instantiator is {@code null}
+     * default one is created.
+     *
+     * @param annotatedType resolved type of the registered bean.
+     * @param delegate      CDI specific injection target.
+     * @param bean          bean which this injection target belongs to.
+     * @param clazz         class that will be scanned and injected.
+     * @param resolvers     all resolvers that can provide a valued for Jersey-specific injection.
+     * @param instantiator  default instantiator.
+     */
+    public JerseyInjectionTarget(EnhancedAnnotatedType<T> annotatedType, BasicInjectionTarget<T> delegate, Bean<T> bean,
+            Class<T> clazz, Collection<InjectionResolver> resolvers, Instantiator<T> instantiator) {
+        super(annotatedType,
+                bean,
+                delegate.getBeanManager(),
+                delegate.getInjector(),
+                delegate.getLifecycleCallbackInvoker(),
+                JerseyBean.class.isInstance(bean)
+                        ? new JerseyTwofoldInstantiator<T>((AbstractInstantiator<T>) instantiator)
+                        : instantiator);
+
+        this.bean = bean;
+        this.enhancedAnnotatedType = annotatedType;
+        this.clazz = clazz;
+        this.resolvers = resolvers;
+        this.injector = Values.lazy((Value<JerseyInstanceInjector<T>>) () -> new JerseyInstanceInjector<>(bean, this.resolvers));
+        this.delegate = null;
+        this.instantiator = getInstantiator();
+        setInstantiator(this.instantiator);
+    }
+
+    @Override
+    protected void checkDelegateInjectionPoints() {
+        if (getAnnotatedType().getAnnotation(javax.decorator.Decorator.class) == null) {
+            super.checkDelegateInjectionPoints();
+        }
+    }
+
+    @Override
+    public void inject(T instance, CreationalContext<T> ctx) {
+        /*
+         * If an instance contains any fields which be injected by Jersey then Jersey attempts to inject them using annotations
+         * retrieves from registered InjectionResolvers.
+         */
+        try {
+            injector.get().inject(instance);
+        } catch (WebApplicationException wae) {
+            throw wae;
+        } catch (Throwable cause) {
+            throw new InjectionException(
+                    "Exception occurred during Jersey/JAX-RS annotations processing in the class: " + clazz, cause);
+        }
+
+        /*
+         * The rest of the fields (annotated by @Inject) are injected using CDI.
+         */
+        super.inject(instance, ctx);
+    }
+
+    /**
+     * Copied method from the parent class because of a custom type of {@link Instantiator} is used in this implementation.
+     *
+     * @param annotatedType processed class.
+     */
+    @Override
+    public void initializeAfterBeanDiscovery(EnhancedAnnotatedType<T> annotatedType) {
+        initializeInterceptionModel(annotatedType);
+
+        InterceptionModel interceptionModel = null;
+        if (isInterceptionCandidate()) {
+            interceptionModel = beanManager.getInterceptorModelRegistry().get(getType());
+        }
+        boolean hasNonConstructorInterceptors = interceptionModel != null
+                && (interceptionModel.hasExternalNonConstructorInterceptors()
+                            || interceptionModel.hasTargetClassInterceptors());
+
+        List<Decorator<?>> decorators = null;
+        if (getBean() != null && isInterceptionCandidate()) {
+            decorators = beanManager.resolveDecorators(getBean().getTypes(), getBean().getQualifiers());
+        }
+        boolean hasDecorators = decorators != null && !decorators.isEmpty();
+        if (hasDecorators) {
+            checkDecoratedMethods(annotatedType, decorators);
+        }
+
+        if (hasNonConstructorInterceptors || hasDecorators) {
+            if (!(getInstantiator() instanceof DefaultInstantiator<?>)) {
+                throw new IllegalStateException("Unexpected instantiator " + getInstantiator());
+            }
+
+            /*
+             * Casting changed from DefaultInstantiator to a more abstract one because of using our custom JerseyInstantiator.
+             */
+            AbstractInstantiator<T> delegate = (AbstractInstantiator<T>) getInstantiator();
+            setInstantiator(
+                    SubclassedComponentInstantiator.forInterceptedDecoratedBean(annotatedType, getBean(), delegate, beanManager));
+
+            if (hasDecorators) {
+                setInstantiator(new SubclassDecoratorApplyingInstantiator<>(
+                        getBeanManager().getContextId(), getInstantiator(), getBean(), decorators));
+            }
+
+            if (hasNonConstructorInterceptors) {
+                setInstantiator(new InterceptorApplyingInstantiator<>(
+                        getInstantiator(), interceptionModel, getType()));
+            }
+        }
+
+        if (isInterceptionCandidate()) {
+            setupConstructorInterceptionInstantiator(interceptionModel);
+        }
+    }
+
+    private void setupConstructorInterceptionInstantiator(InterceptionModel interceptionModel) {
+        if (interceptionModel != null && interceptionModel.hasExternalConstructorInterceptors()) {
+            setInstantiator(new ConstructorInterceptionInstantiator<>(getInstantiator(), interceptionModel, getType()));
+        }
+    }
+
+    private void checkNoArgsConstructor(EnhancedAnnotatedType<T> type) {
+        if (!beanManager.getServices().get(ProxyInstantiator.class).isUsingConstructor()) {
+            return;
+        }
+        EnhancedAnnotatedConstructor<T> constructor = type.getNoArgsEnhancedConstructor();
+        if (constructor == null) {
+            throw BeanLogger.LOG.decoratedHasNoNoargsConstructor(this);
+        } else if (constructor.isPrivate()) {
+            throw BeanLogger.LOG
+                    .decoratedNoargsConstructorIsPrivate(this, Formats.formatAsStackTraceElement(constructor.getJavaMember()));
+        }
+    }
+
+    private void checkDecoratedMethods(EnhancedAnnotatedType<T> type, List<Decorator<?>> decorators) {
+        if (type.isFinal()) {
+            throw BeanLogger.LOG.finalBeanClassWithDecoratorsNotAllowed(this);
+        }
+        checkNoArgsConstructor(type);
+        for (Decorator<?> decorator : decorators) {
+            EnhancedAnnotatedType<?> decoratorClass;
+            if (decorator instanceof DecoratorImpl<?>) {
+                DecoratorImpl<?> decoratorBean = (DecoratorImpl<?>) decorator;
+                decoratorClass = decoratorBean.getBeanManager().getServices().get(ClassTransformer.class)
+                        .getEnhancedAnnotatedType(decoratorBean.getAnnotated());
+            } else if (decorator instanceof CustomDecoratorWrapper<?>) {
+                decoratorClass = ((CustomDecoratorWrapper<?>) decorator).getEnhancedAnnotated();
+            } else {
+                throw BeanLogger.LOG.nonContainerDecorator(decorator);
+            }
+
+            for (EnhancedAnnotatedMethod<?, ?> decoratorMethod : decoratorClass.getEnhancedMethods()) {
+                EnhancedAnnotatedMethod<?, ?> method = type.getEnhancedMethod(decoratorMethod.getSignature());
+                if (method != null && !method.isStatic() && !method.isPrivate() && method.isFinal()) {
+                    throw BeanLogger.LOG.finalBeanClassWithInterceptorsNotAllowed(this);
+                }
+            }
+        }
+    }
+
+    private void initializeInterceptionModel(EnhancedAnnotatedType<T> annotatedType) {
+        AbstractInstantiator<T> instantiator = (AbstractInstantiator<T>) getInstantiator();
+        if (instantiator.getConstructorInjectionPoint() == null) {
+            return; // this is a non-producible InjectionTarget (only created to inject existing instances)
+        }
+        if (isInterceptionCandidate() && !beanManager.getInterceptorModelRegistry().containsKey(getType())) {
+            buildInterceptionModel(annotatedType, instantiator);
+        }
+    }
+
+    private void buildInterceptionModel(EnhancedAnnotatedType<T> annotatedType, AbstractInstantiator<T> instantiator) {
+        new InterceptionModelInitializer<>(beanManager, annotatedType, annotatedType.getDeclaredEnhancedConstructor(
+                instantiator.getConstructorInjectionPoint().getSignature()), getBean()).init();
+    }
+
+    private boolean isInterceptor() {
+        return (getBean() instanceof Interceptor<?>) || getType().isAnnotationPresent(javax.interceptor.Interceptor.class);
+    }
+
+    private boolean isDecorator() {
+        return (getBean() instanceof Decorator<?>) || getType().isAnnotationPresent(javax.decorator.Decorator.class);
+    }
+
+    private boolean isInterceptionCandidate() {
+        return !isInterceptor() && !isDecorator() && !Modifier.isAbstract(getType().getJavaClass().getModifiers());
+    }
+
+    @Override
+    public T produce(CreationalContext<T> ctx) {
+        T instance;
+        if (delegate != null) {
+            instance = (T) delegate.produce(ctx);
+        } else {
+            instance = super.produce(ctx);
+            if (bean != null && !bean.getScope().equals(Dependent.class) && !getInstantiator().hasDecoratorSupport()) {
+                // This should be safe, but needs verification PLM
+                // Without this, the chaining of decorators will fail as the
+                // incomplete instance will be resolved
+                ctx.push(instance);
+            }
+        }
+        return instance;
+    }
+
+    public Instantiator<T> getInstantiator() {
+        return delegate != null ? delegate.getInstantiator() : super.getInstantiator();
+    }
+
+    public void setInstantiator(Instantiator<T> instantiator) {
+        if (this.delegate != null) {
+            delegate.setInstantiator(instantiator);
+        } else {
+            super.setInstantiator(instantiator);
+        }
+    }
+
+    @Override
+    public Bean<T> getBean() {
+        return this.bean;
+    }
+
+    /**
+     * In some cases Injection Resolvers cannot be provided during th creation of the object therefore must be set later on.
+     *
+     * @param resolvers all registered injection resolvers.
+     */
+    public void setInjectionResolvers(Collection<InjectionResolver> resolvers) {
+        this.resolvers = resolvers;
+    }
+
+    public EnhancedAnnotatedType<T> getEnhancedAnnotatedType() {
+        return enhancedAnnotatedType;
+    }
+
+    public JerseyTwofoldInstantiator<T> getTwofoldInstantiator() {
+        return (JerseyTwofoldInstantiator<T>) instantiator;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyInstanceInjector.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyInstanceInjector.java
new file mode 100644
index 0000000..07cf0d3
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyInstanceInjector.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.enterprise.inject.spi.Bean;
+
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+
+/**
+ * Class that accepts all registered {@link InjectionResolver} and inject all possible values annotated by JAX-RS annotations
+ * into provided instance in {@link #inject(Object)}.
+ *
+ * @author Petr Bouda
+ */
+class JerseyInstanceInjector<T> {
+
+    private final Bean<T> bean;
+    private final Map<Field, InjectionResolver> cachedFields;
+
+    private final JerseyProxyResolver proxyResolver = new JerseyProxyResolver();
+
+    /**
+     * Constructor that creates a new class injector for the given class.
+     *
+     * @param bean      information about the injected class.
+     * @param resolvers all resolvers which are registered in the application.
+     */
+    JerseyInstanceInjector(Bean<T> bean, Collection<InjectionResolver> resolvers) {
+        this.bean = bean;
+        this.cachedFields = analyzeFields(bean.getBeanClass(), resolvers);
+    }
+
+    /**
+     * Takes an instance an inject the annotated field which were analyzed during the injector construction in method
+     * {@link #analyzeFields(Class, Collection)}.
+     *
+     * @param injectMe an instance into which the values will be injected.
+     */
+    void inject(T injectMe) {
+        InjectionUtils.justInject(injectMe, bean, cachedFields, proxyResolver);
+    }
+
+    /**
+     * Takes a class and returns all fields along with {@link InjectionResolver} which will be used for injection during injection
+     * process.
+     *
+     * @param clazz     class to be analyzed.
+     * @param resolvers all registered injection resolvers.
+     * @return immutable map of all fields along with injection resolvers using that can be injected.
+     */
+    private Map<Field, InjectionResolver> analyzeFields(Class<?> clazz, Collection<InjectionResolver> resolvers) {
+        Map<? extends Class<?>, InjectionResolver> injectAnnotations = InjectionUtils.mapAnnotationToResolver(resolvers);
+
+        Collector collector = new Collector();
+        Set<Field> fields = InjectionUtils.getFields(clazz, injectAnnotations.keySet(), collector);
+        collector.throwIfErrors();
+        return InjectionUtils.mapElementToResolver(fields, injectAnnotations);
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolver.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolver.java
new file mode 100644
index 0000000..20c282c
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolver.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+import javax.ws.rs.core.Application;
+
+import javax.enterprise.context.RequestScoped;
+
+import org.glassfish.jersey.internal.inject.Injectee;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+
+/**
+ * Class working with JAX-RS/Jersey types injected using {@link javax.ws.rs.core.Context} annotation and all other types which
+ * can be injected using using other {@code *Param} annotations.
+ * <p>
+ * Processed JAX-RS interfaces:
+ *
+ * @author Petr Bouda
+ * @see javax.ws.rs.core.UriInfo
+ * @see javax.ws.rs.core.Request
+ * @see javax.ws.rs.core.HttpHeaders
+ * @see javax.ws.rs.core.SecurityContext
+ * @see javax.ws.rs.core.Configuration
+ * @see javax.ws.rs.core.Application not proxiable because is registered as a singleton.
+ * @see javax.ws.rs.ext.Providers
+ */
+class JerseyProxyResolver {
+
+    /**
+     * Contains already created proxies for the given type.
+     * e.g. if the proxy has been already created for {@code UriInfo} don't create a new one and reuse the existing one.
+     */
+    private final ConcurrentHashMap<AnnotatedElement, Object> cachedProxies = new ConcurrentHashMap<>();
+
+    /**
+     * Classes in which is not needed to use a proxy because they are singletons.
+     */
+    private static final List<Class<?>> IGNORED_CLASSES = Collections.singletonList(Application.class);
+
+    /**
+     * Returns {@code true} if one of the proxiable annotations is present on the clazz into which values are injected.
+     * <p>
+     * In these cases the value is not proxiable:
+     * <ul>
+     * <li>Class without the annotation</li>
+     * <li>Class annotated by {@link javax.enterprise.context.RequestScoped}</li>
+     * <li>Class annotated by {@link org.glassfish.jersey.process.internal.RequestScoped}</li>
+     * <ul/>
+     *
+     * @param injectee information about the injection point.
+     * @return {@code true} if contains one proxiable annotation at least.
+     */
+    public boolean isProxiable(Injectee injectee) {
+        return !ignoredClass(injectee.getRequiredType()) && isProxiable(injectee.getParentClassScope());
+    }
+
+    /**
+     * Returns {@code true} if one of the proxiable annotations is present on the clazz.
+     * <p>
+     * In these cases the value is not proxiable:
+     * <ul>
+     * <li>Class without the annotation</li>
+     * <li>Class annotated by {@link javax.enterprise.context.RequestScoped}</li>
+     * <li>Class annotated by {@link org.glassfish.jersey.process.internal.RequestScoped}</li>
+     * <ul/>
+     *
+     * @param scopeAnnotation annotation belonging to the scope of the class.
+     * @return {@code true} if contains one proxiable annotation at least.
+     */
+    public boolean isProxiable(Class<? extends Annotation> scopeAnnotation) {
+        return ignoreProxy().stream().noneMatch(ignoredAnnotation -> ignoredAnnotation == scopeAnnotation);
+    }
+
+    /**
+     * Returns a proxy (newly created or cached) which is able to call {@link InjectionResolver} with the given {@link Injectee}
+     * to get the value in proper scope.
+     *
+     * @param injectee information about the injection point.
+     * @param resolver dedicated resolver which find the value.
+     * @return created proxy which resolve the value in the proper scope.
+     */
+    public Object proxy(Injectee injectee, InjectionResolver resolver) {
+        return cachedProxies.computeIfAbsent(injectee.getParent(), type -> createProxy(injectee, resolver));
+    }
+
+    /**
+     * Returns a proxy (newly created or cached) which is able to call the given {@link Supplier}. This method does not cache
+     * a result.
+     *
+     * @param injectee information about the injection point.
+     * @param supplier supplier called using the proxy.
+     * @return created proxy which resolve the value in the proper scope.
+     */
+    public Object noCachedProxy(Injectee injectee, Supplier<Object> supplier) {
+        return createProxy(getClass(injectee.getRequiredType()), supplier);
+    }
+
+    private Object createProxy(Injectee injectee, InjectionResolver resolver) {
+        return createProxy(getClass(injectee.getRequiredType()), () -> resolver.resolve(injectee));
+    }
+
+    private Object createProxy(Class<?> requiredClass, Supplier<Object> supplier) {
+        return Proxy.newProxyInstance(
+                requiredClass.getClassLoader(),
+                new Class<?>[] {requiredClass},
+                new JerseyInvocationHandler(supplier));
+    }
+
+    private Class<?> getClass(Type type) {
+        if (type instanceof ParameterizedType) {
+            ParameterizedType paramType = (ParameterizedType) type;
+            return (Class<?>) paramType.getRawType();
+        }
+
+        return (Class<?>) type;
+    }
+
+    /**
+     * Returns all annotations for which proxy will be created.
+     *
+     * @return all proxyable annotations.
+     */
+    private Collection<Class<? extends Annotation>> ignoreProxy() {
+        return Arrays.asList(RequestScoped.class, org.glassfish.jersey.process.internal.RequestScoped.class);
+    }
+
+    /**
+     * Classes in which is not needed to use a proxy because they are singletons.
+     *
+     * @return classes omitted during proxying.
+     */
+    private boolean ignoredClass(Type type) {
+        Class<?> clazz;
+        if (type instanceof ParameterizedType) {
+            ParameterizedType paramType = (ParameterizedType) type;
+            clazz = (Class<?>) paramType.getRawType();
+        } else {
+            clazz = (Class<?>) type;
+        }
+
+        return IGNORED_CLASSES.contains(clazz);
+    }
+
+    /**
+     * {@link InvocationHandler} to intercept a calling using a proxy by providing a value of the given injected type in a proper
+     * scope.
+     */
+    private static class JerseyInvocationHandler implements InvocationHandler {
+
+        private final Supplier<Object> supplier;
+
+        /**
+         * Creates a new invocation handler with supplier which provides a current injected value in proper scope.
+         *
+         * @param supplier provider of the value.
+         */
+        private JerseyInvocationHandler(Supplier<Object> supplier) {
+            this.supplier = supplier;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            Object target = supplier.get();
+            return method.invoke(target, args);
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyTwofoldInstantiator.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyTwofoldInstantiator.java
new file mode 100644
index 0000000..e9f6309
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyTwofoldInstantiator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import javax.enterprise.context.spi.CreationalContext;
+import org.jboss.weld.injection.ConstructorInjectionPoint;
+import org.jboss.weld.injection.producer.AbstractInstantiator;
+import org.jboss.weld.manager.BeanManagerImpl;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * An implementation of an instantiator capable of instantiating different instance for the client and server side.
+ * @param <T> the class of the instantiator.
+ */
+public class JerseyTwofoldInstantiator<T> extends AbstractInstantiator<T> {
+
+    private final AbstractInstantiator<T> primaryInstantiator;
+    private ConstructorInjectionPoint<T> optionalConstructorInjectionPoint = null;
+
+    JerseyTwofoldInstantiator(AbstractInstantiator<T> serverInstantiator) {
+        this.primaryInstantiator = serverInstantiator;
+    }
+
+    @Override
+    public ConstructorInjectionPoint<T> getConstructorInjectionPoint() {
+        return primaryInstantiator.getConstructorInjectionPoint();
+    }
+
+    @Override
+    public boolean hasInterceptorSupport() {
+        return primaryInstantiator.hasDecoratorSupport();
+    }
+
+    @Override
+    public boolean hasDecoratorSupport() {
+        return primaryInstantiator.hasDecoratorSupport();
+    }
+
+    @Override
+    public Constructor<T> getConstructor() {
+        return primaryInstantiator.getConstructor();
+    }
+
+    @Override
+    public T newInstance(CreationalContext<T> ctx, BeanManagerImpl manager) {
+        final ConstructorInjectionPoint<T> cip =
+                optionalConstructorInjectionPoint == null || !JerseyClientCreationalContext.class.isInstance(ctx)
+                ? primaryInstantiator.getConstructorInjectionPoint()
+                : optionalConstructorInjectionPoint;
+        return cip.newInstance(manager, ctx);
+    }
+
+    /**
+     * Set the optional constuctor injection point for the client side instantiation.
+     * @param optionalConstructorInjectionPoint The optional constructor injection point.
+     */
+    public void setOptionalConstructorInjectionPoint(ConstructorInjectionPoint<T> optionalConstructorInjectionPoint) {
+        this.optionalConstructorInjectionPoint = optionalConstructorInjectionPoint;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/MultiException.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/MultiException.java
new file mode 100644
index 0000000..2c7e31a
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/MultiException.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This exception can contain multiple other exceptions.
+ * However, it will also have the causal chain of the
+ * first exception added to the list of exceptions.
+ *
+ * @author John Wells (john.wells at oracle.com)
+ */
+public class MultiException extends RuntimeException {
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 2112432697858621044L;
+    private final Object lock = new byte[0]; // byte[0] is an arbitrary type that is Serializable
+    private final List<Throwable> throwables = new LinkedList<>();
+    private boolean reportToErrorService = true;
+
+    /**
+     * Creates an empty MultiException.
+     */
+    public MultiException() {
+    }
+
+    /**
+     * This list must have at least one element in it.
+     * The first element of the list will become the
+     * cause of this exception, and its message will become
+     * the message of this exception.
+     *
+     * @param ths A non-null, non-empty list of exceptions.
+     */
+    public MultiException(List<Throwable> ths) {
+        super(ths.get(0).getMessage(), ths.get(0));
+
+        for (Throwable th : ths) {
+            if (th instanceof MultiException) {
+                MultiException me = (MultiException) th;
+
+                throwables.addAll(me.throwables);
+            } else {
+                throwables.add(th);
+            }
+        }
+    }
+
+    /**
+     * This allows for construction of a MultiException
+     * with one element in its list.
+     *
+     * @param th May not be null.
+     */
+    public MultiException(Throwable th, boolean reportToErrorService) {
+        super(th.getMessage(), th);
+
+        if (th instanceof MultiException) {
+            MultiException me = (MultiException) th;
+
+            throwables.addAll(me.throwables);
+        } else {
+            throwables.add(th);
+        }
+
+        this.reportToErrorService = reportToErrorService;
+    }
+
+    /**
+     * This allows for construction of a MultiException
+     * with one element in its list.
+     *
+     * @param th May not be null.
+     */
+    public MultiException(Throwable th) {
+        this(th, true);
+    }
+
+    /**
+     * Gets all the errors associated with this MultiException.
+     *
+     * @return All the errors associated with this MultiException. Will
+     * not return null, but may return an empty object.
+     */
+    public List<Throwable> getErrors() {
+        synchronized (lock) {
+            return new LinkedList<>(throwables);
+        }
+    }
+
+    /**
+     * Adds an error to an existing exception.
+     *
+     * @param error The exception to add.
+     */
+    public void addError(Throwable error) {
+        synchronized (lock) {
+            throwables.add(error);
+        }
+    }
+
+    /**
+     * Gets the message associated with this exception.
+     */
+    public String getMessage() {
+        List<Throwable> listCopy = getErrors();
+        StringBuffer sb = new StringBuffer("A MultiException has " + listCopy.size() + " exceptions.  They are:\n");
+
+        int lcv = 1;
+        for (Throwable th : listCopy) {
+            sb.append(lcv++ + ". " + th.getClass().getName() + ((th.getMessage() != null) ? ": " + th.getMessage() : "") + "\n");
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Prints the stack trace of this exception to the given PrintStream.
+     */
+    public void printStackTrace(PrintStream s) {
+        List<Throwable> listCopy = getErrors();
+
+        if (listCopy.size() <= 0) {
+            super.printStackTrace(s);
+            return;
+        }
+
+        int lcv = 1;
+        for (Throwable th : listCopy) {
+            s.println("MultiException stack " + lcv++ + " of " + listCopy.size());
+            th.printStackTrace(s);
+        }
+    }
+
+    /**
+     * Prints the stack trace of this exception to the given PrintWriter.
+     */
+    public void printStackTrace(PrintWriter s) {
+        List<Throwable> listCopy = getErrors();
+
+        if (listCopy.size() <= 0) {
+            super.printStackTrace(s);
+            return;
+        }
+
+        int lcv = 1;
+        for (Throwable th : listCopy) {
+            s.println("MultiException stack " + lcv++ + " of " + listCopy.size());
+            th.printStackTrace(s);
+        }
+    }
+
+    /**
+     * Returns true if this exception should be reported
+     * to the error service when thrown during a creation
+     * or deletion of a service.
+     *
+     * @return true if this exception should be reported to
+     * the error service when creating or deleting a service.
+     */
+    public boolean getReportToErrorService() {
+        return reportToErrorService;
+    }
+
+    /**
+     * Sets if this exception should be reported
+     * to the error service when thrown during a creation
+     * or deletion of a service.
+     *
+     * @param report true if this exception should be reported to
+     *               the error service when creating or deleting a service.
+     */
+    public void setReportToErrorService(boolean report) {
+        reportToErrorService = report;
+    }
+
+    @Override
+    public String toString() {
+        return getMessage();
+    }
+
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/NamedImpl.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/NamedImpl.java
new file mode 100644
index 0000000..6a7d5fb
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/NamedImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import javax.inject.Named;
+
+import org.glassfish.jersey.internal.inject.AnnotationLiteral;
+
+/**
+ * This is an implementation of the {@link Named} annotation.
+ *
+ * @author John Wells (john.wells at oracle.com)
+ */
+class NamedImpl extends AnnotationLiteral<Named> implements Named {
+
+    /**
+     * For serialization
+     */
+    private static final long serialVersionUID = 9110325112008963155L;
+
+    private final String name;
+
+    /**
+     * Creates a {@link Named} annotation with the given name.
+     *
+     * @param name The non-null name to give the annotation.
+     */
+    NamedImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String value() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return "@Named(" + name + ")";
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/ReflectionUtils.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/ReflectionUtils.java
new file mode 100644
index 0000000..e47a998
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/ReflectionUtils.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.glassfish.jersey.inject.weld.internal.type.GenericArrayTypeImpl;
+import org.glassfish.jersey.inject.weld.internal.type.ParameterizedTypeImpl;
+import org.glassfish.jersey.internal.util.collection.ImmutableCollectors;
+
+/**
+ * Utility class for getting the information from class using Reflection API.
+ *
+ * @author John Wells (john.wells at oracle.com)
+ * @author Petr Bouda
+ */
+class ReflectionUtils {
+
+    private static final Logger LOGGER = Logger.getLogger(ReflectionUtils.class.getName());
+
+    static Set<Field> getAllFields(Class<?> clazz) {
+        if (clazz == null || Object.class.equals(clazz)) {
+            return Collections.emptySet();
+        }
+        if (clazz.isInterface()) {
+            return Collections.emptySet();
+        }
+
+        Set<Field> retVal = new LinkedHashSet<>();
+        retVal.addAll(getDeclaredField(clazz));
+        retVal.addAll(getAllFields(clazz.getSuperclass()));
+        return retVal;
+    }
+
+    /**
+     * Gets the EXACT set of fields on this class only. No subclasses. So this set should be considered RAW and has not taken into
+     * account any subclasses.
+     *
+     * @param clazz The class to examine.
+     * @return all declared fields.
+     */
+    private static Set<Field> getDeclaredField(final Class<?> clazz) {
+        return Arrays.stream(secureGetDeclaredFields(clazz)).collect(ImmutableCollectors.toImmutableLinkedSet());
+    }
+
+    private static Field[] secureGetDeclaredFields(final Class<?> clazz) {
+        return AccessController.doPrivileged((PrivilegedAction<Field[]>) clazz::getDeclaredFields);
+    }
+
+    /**
+     * Resolves the generic type of a field given the actual class being instantiated
+     *
+     * @param topclass The instantiation class.  Must not be null
+     * @param field    The non-null field whose type to resolve
+     * @return The resolved field type by way of its subclasses.  Will not return
+     * null, but may return the original fields generic type
+     */
+    static Type resolveField(Class<?> topclass, Field field) {
+        return resolveMember(topclass, field.getGenericType(), field.getDeclaringClass());
+    }
+
+    /**
+     * Resolves the generic type of a type and declaring class given the actual class being instantiated
+     *
+     * @param topclass       The instantiation class.  Must not be null
+     * @param lookingForType The type to resolve.  Must not be null
+     * @param declaringClass The class of the entity declaring the lookingForType. Must not be null
+     * @return The resolved type by way of its subclasses.  Will not return null but may
+     * return lookingForType if it could not be further resolved
+     */
+    private static Type resolveMember(Class<?> topclass, Type lookingForType, Class<?> declaringClass) {
+        Map<String, Type> typeArguments = typesFromSubClassToDeclaringClass(topclass, declaringClass);
+        if (typeArguments == null) {
+            return lookingForType;
+        }
+
+        if (lookingForType instanceof ParameterizedType) {
+            return fixTypeVariables((ParameterizedType) lookingForType, typeArguments);
+        }
+
+        if (lookingForType instanceof GenericArrayType) {
+            return fixGenericArrayTypeVariables((GenericArrayType) lookingForType, typeArguments);
+        }
+
+        if (!(lookingForType instanceof TypeVariable)) {
+            return lookingForType;
+        }
+
+        TypeVariable<?> tv = (TypeVariable<?>) lookingForType;
+        String typeVariableName = tv.getName();
+
+        Type retVal = typeArguments.get(typeVariableName);
+        if (retVal == null) {
+            return lookingForType;
+        }
+
+        if (retVal instanceof Class) {
+            return retVal;
+        }
+
+        if (retVal instanceof ParameterizedType) {
+            return fixTypeVariables((ParameterizedType) retVal, typeArguments);
+        }
+
+        if (retVal instanceof GenericArrayType) {
+            return fixGenericArrayTypeVariables((GenericArrayType) retVal, typeArguments);
+        }
+
+        return retVal;
+    }
+
+    private static Map<String, Type> typesFromSubClassToDeclaringClass(Class<?> topClass, Class<?> declaringClass) {
+        if (topClass.equals(declaringClass)) {
+            return null;
+        }
+
+        Type superType = topClass.getGenericSuperclass();
+        Class<?> superClass = getRawClass(superType);
+
+        while (superType != null && superClass != null) {
+            if (!(superType instanceof ParameterizedType)) {
+                // superType MUST be a Class in this case
+                if (superClass.equals(declaringClass)) {
+                    return null;
+                }
+
+                superType = superClass.getGenericSuperclass();
+                superClass = getRawClass(superType);
+
+                continue;
+            }
+
+            ParameterizedType superPT = (ParameterizedType) superType;
+
+            Map<String, Type> typeArguments = getTypeArguments(superClass, superPT);
+
+            if (superClass.equals(declaringClass)) {
+                return typeArguments;
+            }
+
+            superType = superClass.getGenericSuperclass();
+            superClass = getRawClass(superType);
+
+            if (superType instanceof ParameterizedType) {
+                superType = fixTypeVariables((ParameterizedType) superType, typeArguments);
+            }
+        }
+
+        throw new AssertionError(topClass.getName() + " is not the same as or a subclass of " + declaringClass.getName());
+    }
+
+    /**
+     * Gets a mapping of type variable names of the raw class to type arguments of the parameterized type.
+     */
+    private static Map<String, Type> getTypeArguments(Class<?> rawClass, ParameterizedType type) {
+        Map<String, Type> typeMap = new HashMap<>();
+        Type[] typeArguments = type.getActualTypeArguments();
+
+        int i = 0;
+        for (TypeVariable<?> typeVariable : rawClass.getTypeParameters()) {
+            typeMap.put(typeVariable.getName(), typeArguments[i++]);
+        }
+        return typeMap;
+    }
+
+    /**
+     * Replace any TypeVariables in the given type's arguments with
+     * the actual argument types.  Return the given type if no replacing
+     * is required.
+     */
+    private static Type fixTypeVariables(ParameterizedType type, Map<String, Type> typeArgumentsMap) {
+        Type[] newTypeArguments = getNewTypeArguments(type, typeArgumentsMap);
+        if (newTypeArguments != null) {
+            return new ParameterizedTypeImpl(type.getRawType(), newTypeArguments);
+        }
+        return type;
+    }
+
+    /**
+     * Get a new array of type arguments for the given ParameterizedType, replacing any TypeVariables with
+     * actual types.  The types should be found in the given arguments map, keyed by variable name.  Return
+     * null if no arguments needed to be replaced.
+     */
+    private static Type[] getNewTypeArguments(final ParameterizedType type,
+            final Map<String, Type> typeArgumentsMap) {
+
+        Type[] typeArguments = type.getActualTypeArguments();
+        Type[] newTypeArguments = new Type[typeArguments.length];
+        boolean newArgsNeeded = false;
+
+        int i = 0;
+        for (Type argType : typeArguments) {
+            if (argType instanceof TypeVariable) {
+                newTypeArguments[i] = typeArgumentsMap.get(((TypeVariable<?>) argType).getName());
+                newArgsNeeded = true;
+            } else if (argType instanceof ParameterizedType) {
+                ParameterizedType original = (ParameterizedType) argType;
+
+                Type[] internalTypeArgs = getNewTypeArguments(original, typeArgumentsMap);
+                if (internalTypeArgs != null) {
+                    newTypeArguments[i] = new ParameterizedTypeImpl(original.getRawType(), internalTypeArgs);
+                    newArgsNeeded = true;
+                } else {
+                    newTypeArguments[i] = argType;
+                }
+            } else if (argType instanceof GenericArrayType) {
+                GenericArrayType gat = (GenericArrayType) argType;
+
+                Type internalTypeArg = getNewTypeArrayArguments(gat, typeArgumentsMap);
+                if (internalTypeArg != null) {
+                    if (internalTypeArg instanceof Class<?>) {
+                        newTypeArguments[i] = getArrayOfType((Class<?>) internalTypeArg);
+                        newArgsNeeded = true;
+                    } else if ((internalTypeArg instanceof ParameterizedType)
+                            && (((ParameterizedType) internalTypeArg).getRawType() instanceof Class<?>)) {
+                        ParameterizedType pt = (ParameterizedType) internalTypeArg;
+
+                        newTypeArguments[i] = getArrayOfType((Class<?>) pt.getRawType());
+                        newArgsNeeded = true;
+                    } else {
+                        newTypeArguments[i] = new GenericArrayTypeImpl(internalTypeArg);
+                        newArgsNeeded = true;
+                    }
+                } else {
+                    newTypeArguments[i] = argType;
+                }
+            } else {
+                newTypeArguments[i] = argType;
+            }
+
+            i++;
+        }
+
+        return newArgsNeeded ? newTypeArguments : null;
+    }
+
+    /**
+     * Get a new Type for a GenericArrayType, replacing any TypeVariables with
+     * actual types.  The types should be found in the given arguments map, keyed by variable name.  Return
+     * null if no arguments needed to be replaced.
+     */
+    private static Type getNewTypeArrayArguments(final GenericArrayType gat,
+            final Map<String, Type> typeArgumentsMap) {
+
+        Type typeArgument = gat.getGenericComponentType();
+
+        if (typeArgument instanceof TypeVariable) {
+            return typeArgumentsMap.get(((TypeVariable<?>) typeArgument).getName());
+        }
+
+        if (typeArgument instanceof ParameterizedType) {
+            ParameterizedType original = (ParameterizedType) typeArgument;
+
+            Type[] internalTypeArgs = getNewTypeArguments(original, typeArgumentsMap);
+            if (internalTypeArgs != null) {
+                return new ParameterizedTypeImpl(original.getRawType(), internalTypeArgs);
+            }
+
+            return original;
+        }
+
+        if (typeArgument instanceof GenericArrayType) {
+            GenericArrayType original = (GenericArrayType) typeArgument;
+
+            Type internalTypeArg = getNewTypeArrayArguments(original, typeArgumentsMap);
+            if (internalTypeArg != null) {
+                if (internalTypeArg instanceof Class<?>) {
+                    return getArrayOfType((Class<?>) internalTypeArg);
+                }
+
+                if (internalTypeArg instanceof ParameterizedType) {
+                    ParameterizedType pt = (ParameterizedType) internalTypeArg;
+
+                    if (pt.getRawType() instanceof Class<?>) {
+                        return getArrayOfType((Class<?>) pt.getRawType());
+                    }
+                }
+
+                return new GenericArrayTypeImpl(internalTypeArg);
+            }
+
+            return null;
+        }
+
+        return null;
+    }
+
+    /**
+     * Replace any TypeVariables in the given type's arguments with
+     * the actual argument types.  Return the given type if no replacing
+     * is required.
+     */
+    private static Type fixGenericArrayTypeVariables(GenericArrayType type, Map<String, Type> typeArgumentsMap) {
+        Type newTypeArgument = getNewTypeArrayArguments(type, typeArgumentsMap);
+
+        if (newTypeArgument != null) {
+            if (newTypeArgument instanceof Class<?>) {
+                return getArrayOfType((Class<?>) newTypeArgument);
+            }
+
+            if (newTypeArgument instanceof ParameterizedType) {
+                ParameterizedType pt = (ParameterizedType) newTypeArgument;
+                if (pt.getRawType() instanceof Class<?>) {
+                    return getArrayOfType((Class<?>) pt.getRawType());
+                }
+            }
+
+            return new GenericArrayTypeImpl(newTypeArgument);
+        }
+
+        return type;
+    }
+
+    private static Class<?> getArrayOfType(Class<?> type) {
+        return Array.newInstance(type, 0).getClass();
+    }
+
+    /**
+     * Given the type parameter gets the raw type represented
+     * by the type, or null if this has no associated raw class
+     *
+     * @param type The type to find the raw class on
+     * @return The raw class associated with this type
+     */
+    private static Class<?> getRawClass(Type type) {
+        if (type == null) {
+            return null;
+        }
+
+        if (type instanceof GenericArrayType) {
+            Type componentType = ((GenericArrayType) type).getGenericComponentType();
+
+            if (!(componentType instanceof ParameterizedType) && !(componentType instanceof Class)) {
+                // type variable is not supported
+                return null;
+            }
+
+            Class<?> rawComponentClass = getRawClass(componentType);
+
+            String forNameName = "[L" + rawComponentClass.getName() + ";";
+            try {
+                return Class.forName(forNameName);
+            } catch (Throwable th) {
+                // ignore, but return null
+                return null;
+            }
+        }
+
+        if (type instanceof Class) {
+            return (Class<?>) type;
+        }
+
+        if (type instanceof ParameterizedType) {
+            Type rawType = ((ParameterizedType) type).getRawType();
+            if (rawType instanceof Class) {
+                return (Class<?>) rawType;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets the given field to the given value
+     *
+     * @param field    The non-null field to set
+     * @param instance The non-null instance to set into
+     * @param value    The value to which the field should be set
+     * @throws Throwable If there was some exception while setting the field
+     */
+    static void setField(Field field, Object instance, Object value) throws Throwable {
+        setAccessible(field);
+
+        try {
+            field.set(instance, value);
+        } catch (IllegalArgumentException | IllegalAccessException ex) {
+            LOGGER.warning(String.format("Failed during setting a value into Class: %s, Field: %s",
+                    field.getDeclaringClass().getName(), field.getName()));
+            throw ex;
+        }
+    }
+
+    /**
+     * Sets this accessible object to be accessible using the permissions of
+     * the hk2-locator bundle (which will need the required grant)
+     *
+     * @param ao The object to change
+     */
+    private static void setAccessible(final AccessibleObject ao) {
+        if (ao.isAccessible()) {
+            return;
+        }
+
+        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
+            ao.setAccessible(true);
+            return null;
+        });
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/WrappingJerseyInjectionTarget.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/WrappingJerseyInjectionTarget.java
new file mode 100644
index 0000000..48a3ded
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/injector/WrappingJerseyInjectionTarget.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.InjectionException;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+import org.glassfish.jersey.internal.util.collection.LazyValue;
+import org.glassfish.jersey.internal.util.collection.Value;
+import org.glassfish.jersey.internal.util.collection.Values;
+
+/**
+ * An implementation of {@link InjectionTarget} that just wraps the provided {@code InjectionTarget} because of additional
+ * features in an injection phase.
+ *
+ * @author Petr Bouda
+ */
+public class WrappingJerseyInjectionTarget<T> extends AbstractInjectionTarget<T> {
+
+    private static InjectionTarget NOOP_INJECTION_TARGET = new NoOpInjectionTarget();
+
+    private final Bean<T> bean;
+    private final LazyValue<JerseyInstanceInjector<T>> injector;
+    private final InjectionTarget<T> delegate;
+    private Collection<InjectionResolver> resolvers;
+
+    /**
+     * Creates a new jersey injection target with delegate as a {@link NoOpInjectionTarget} that creates no operation that
+     * means that only jersey injection is available as a additional feature.
+     *
+     * @param bean      bean as descriptor of the class which will be injected.
+     * @param resolvers all resolvers that can provide a valued for Jersey-specific injection.
+     */
+    public WrappingJerseyInjectionTarget(Bean<T> bean, Collection<InjectionResolver> resolvers) {
+        this(NOOP_INJECTION_TARGET, bean, resolvers);
+    }
+
+    /**
+     * An implementation of {@link InjectionTarget} for classes that do not fulfill bean class requirements
+     * (e.g. are abstract or non-static inner classes). Instances of these class can be injected using this implementation. If the
+     * application attempts to {@link #produce(CreationalContext)} a new instance of the class, {@code CreationException} is
+     * thrown.
+     *
+     * @param delegate  CDI specific injection target.
+     * @param bean      bean as descriptor of the class which will be injected.
+     * @param resolvers all resolvers that can provide a valued for Jersey-specific injection.
+     */
+    public WrappingJerseyInjectionTarget(InjectionTarget<T> delegate, Bean<T> bean, Collection<InjectionResolver> resolvers) {
+        this.bean = bean;
+        this.delegate = delegate;
+        this.resolvers = resolvers;
+        this.injector = Values.lazy((Value<JerseyInstanceInjector<T>>)
+                () -> new JerseyInstanceInjector<>(bean, this.resolvers));
+    }
+
+    @Override
+    public void inject(T instance, CreationalContext<T> ctx) {
+        /*
+         * If an instance contains any fields which be injected by Jersey then Jersey attempts to inject them using annotations
+         * retrieves from registered InjectionResolvers.
+         */
+        try {
+            injector.get().inject(instance);
+        } catch (Throwable cause) {
+            throw new InjectionException(
+                    "Exception occurred during Jersey/JAX-RS annotations processing in the class: " + bean.getBeanClass(), cause);
+        }
+
+        /*
+         * The rest of the fields (annotated by @Inject) are injected using CDI.
+         */
+        super.inject(instance, ctx);
+    }
+
+    @Override
+    InjectionTarget<T> delegate() {
+        return delegate;
+    }
+
+    private static class NoOpInjectionTarget implements InjectionTarget<Object> {
+
+        @Override
+        public void inject(Object instance, CreationalContext<Object> ctx) {
+        }
+
+        @Override
+        public void postConstruct(Object instance) {
+        }
+
+        @Override
+        public void preDestroy(Object instance) {
+        }
+
+        @Override
+        public Object produce(CreationalContext<Object> ctx) {
+            return null;
+        }
+
+        @Override
+        public void dispose(Object instance) {
+        }
+
+        @Override
+        public Set<InjectionPoint> getInjectionPoints() {
+            return Collections.emptySet();
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/BinderRegisterExtension.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/BinderRegisterExtension.java
new file mode 100644
index 0000000..da291df
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/BinderRegisterExtension.java
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import javax.annotation.Priority;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.context.NormalScope;
+import javax.enterprise.context.SessionScoped;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import javax.enterprise.inject.spi.Unmanaged;
+import javax.enterprise.inject.spi.WithAnnotations;
+import javax.inject.Scope;
+import javax.inject.Singleton;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.ProcessInjectionTarget;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.RuntimeType;
+import javax.ws.rs.container.DynamicFeature;
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.ext.Provider;
+
+import org.glassfish.jersey.inject.weld.internal.data.BindingBeanPair;
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableSupplierInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.scope.RequestScopeBean;
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.bean.BeanHelper;
+import org.glassfish.jersey.inject.weld.internal.injector.ContextInjectionResolverImpl;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyInjectionTarget;
+import org.glassfish.jersey.inject.weld.internal.scope.CdiRequestScope;
+import org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization;
+import org.glassfish.jersey.internal.BootstrapBag;
+import org.glassfish.jersey.internal.ServiceFinder;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.Binder;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.Bindings;
+import org.glassfish.jersey.internal.inject.ClassBinding;
+import org.glassfish.jersey.internal.inject.CustomAnnotationLiteral;
+import org.glassfish.jersey.internal.inject.ForeignDescriptor;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+import org.glassfish.jersey.internal.inject.InjectionResolverBinding;
+import org.glassfish.jersey.internal.inject.InstanceBinding;
+import org.glassfish.jersey.internal.inject.Providers;
+import org.glassfish.jersey.internal.inject.ServiceHolder;
+import org.glassfish.jersey.internal.inject.SupplierClassBinding;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+
+import org.glassfish.jersey.internal.util.collection.Ref;
+import org.glassfish.jersey.internal.util.collection.Refs;
+import org.glassfish.jersey.process.internal.RequestScope;
+import org.glassfish.jersey.process.internal.RequestScoped;
+import org.glassfish.jersey.server.ApplicationHandler;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.jboss.weld.injection.producer.BasicInjectionTarget;
+import org.jboss.weld.injection.producer.BeanInjectionTarget;
+
+/**
+ * CDI extension that handles CDI bootstrap events and registers Jersey's internally used components and components registered
+ * using {@link Application}.
+ */
+class BinderRegisterExtension implements Extension {
+
+    private AtomicBoolean registrationDone = new AtomicBoolean(false);
+    private Supplier<BeanManager> beanManagerSupplier;
+    private Ref<InjectionManager> serverInjectionManager = Refs.emptyRef();
+
+    private BootstrapInjectionManager clientBootstrapInjectionManager = new BootstrapInjectionManager(RuntimeType.CLIENT);
+    private WrappingInjectionManager serverBootstrapInjectionManager = new WrappingInjectionManager()
+            .setInjectionManager(new BootstrapInjectionManager(RuntimeType.SERVER));
+    private BootstrapBag bootstrapBag = new BootstrapBag();
+
+    private final CachingBinder clientBindings = new CachingBinder(serverInjectionManager);
+    private final CachingBinder serverBindings = new CachingBinder(serverInjectionManager) {
+        @Override
+        protected void configure() {
+            install(new ContextInjectionResolverImpl.Binder(beanManagerSupplier));
+            bind(InitializableInstanceBinding.from(Bindings.service(serverInjectionManager.get()).to(InjectionManager.class)));
+        }
+    };
+    private final CachingBinder annotatedBeansBinder = new CachingBinder(serverInjectionManager);
+    private final MergedBindings mergedBindings = new MergedBindings(serverBindings, clientBindings);
+
+    private final List<InitializableInstanceBinding> initializableInstanceBindings = new LinkedList<>();
+    private final List<InitializableSupplierInstanceBinding> initializableSupplierInstanceBindings = new LinkedList<>();
+    private final MultivaluedMap<Type, BindingBeanPair> supplierClassBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Type, BindingBeanPair> classBindings = new MultivaluedHashMap<>();
+    private final List<JerseyInjectionTarget> jerseyInjectionTargets = new LinkedList<>();
+    private final List<InjectionResolver> injectionResolvers = new LinkedList<>();
+    private final Map<Class<?>, Class<? extends Annotation>> annotatedBeans = new HashMap<>();
+    private final List<Class<Application>> applications = new LinkedList<>();
+    final Set<Class<?>> managedBeans = new HashSet<>();
+
+    /**
+     * Ignores the classes which are manually added using bindings (through {@link Application} class) and scanned by CDI.
+     * The manual adding is privileged and the beans scanned using CDI are ignored.
+     * <p>
+     * TODO: The method counts with the condition that the all bindings are known before the CDI scanning has been started,
+     * can be changed during the migration from CDI SE to JAVA EE environment.
+     *
+     * @param pat processed type.
+     * @param <T> type of the scanned bean.
+     */
+    <T> void ignoreManuallyRegisteredComponents(
+            @Observes @WithAnnotations({ Path.class, Provider.class }) ProcessAnnotatedType<T> pat) {
+        final AnnotatedType<T> annotatedType = pat.getAnnotatedType();
+        for (Binding binding : mergedBindings.getBindings()) {
+            if (ClassBinding.class.isAssignableFrom(binding.getClass())) {
+                ClassBinding<?> classBinding = (ClassBinding<?>) binding;
+                if (annotatedType.getJavaClass() == classBinding.getService()) {
+                    pat.veto();
+                    return;
+                }
+            } else if (InstanceBinding.class.isAssignableFrom(binding.getClass())) {
+                InstanceBinding<?> instanceBinding = (InstanceBinding<?>) binding;
+                if (annotatedType.getJavaClass() == instanceBinding.getService().getClass()) {
+                    pat.veto();
+                    return;
+                }
+            }
+        }
+        if (annotatedType.isAnnotationPresent(Path.class)) {
+            boolean hasScope = false;
+            for (Annotation annotation : annotatedType.getAnnotations()) {
+                if (annotation.annotationType().isAnnotationPresent(Scope.class)
+                        || annotation.annotationType().isAnnotationPresent(NormalScope.class)) {
+                    hasScope = true;
+                    break;
+                }
+            }
+            if (!hasScope) {
+                annotatedBeans.put(annotatedType.getJavaClass(), javax.enterprise.context.RequestScoped.class);
+                pat.configureAnnotatedType().add(javax.enterprise.context.RequestScoped.Literal.INSTANCE);
+            }
+        }
+
+
+    }
+
+    <T> void registerJerseyRequestScopedResources(
+            @Observes @WithAnnotations(RequestScoped.class) ProcessAnnotatedType<T> pat) {
+        if (pat.getAnnotatedType().isAnnotationPresent(RequestScoped.class)
+                && !pat.getAnnotatedType().isAnnotationPresent(javax.enterprise.context.RequestScoped.class)) {
+            pat.configureAnnotatedType().remove(a -> RequestScoped.class.isInstance(a))
+                    .add(javax.enterprise.context.RequestScoped.Literal.INSTANCE);
+            annotatedBeans.put(pat.getAnnotatedType().getJavaClass(), javax.enterprise.context.RequestScoped.class);
+        }
+    }
+
+    void processRegistrars(@Observes BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
+        CdiInjectionManagerFactoryBase.setBeanManager(beanManager);
+        processRegistrars();
+    }
+
+    void handleRequestScoped(
+            @Observes @WithAnnotations({javax.enterprise.context.RequestScoped.class}) ProcessAnnotatedType<?> pat) {
+        final Class<?> javaClass = pat.getAnnotatedType().getJavaClass();
+        if (isJaxrs(javaClass) && isNotJerseyInternal(javaClass)) {
+            pat.configureAnnotatedType().add(CustomAnnotationLiteral.INSTANCE);
+            annotatedBeans.put(javaClass, javax.enterprise.context.RequestScoped.class);
+        }
+    }
+
+    <T> void handleApplicationScoped(
+            @Observes @WithAnnotations({ApplicationScoped.class}) ProcessAnnotatedType<T> pat) {
+        final Class<T> javaClass = pat.getAnnotatedType().getJavaClass();
+        if (Application.class.isAssignableFrom(javaClass)) {
+            pat.veto();
+            applications.add((Class<Application>) javaClass);
+        } else if (isJaxrs(javaClass) && isNotJerseyInternal(javaClass)) {
+            pat.configureAnnotatedType().add(CustomAnnotationLiteral.INSTANCE);
+            annotatedBeans.put(javaClass, ApplicationScoped.class);
+        }
+    }
+
+    void handleDependent(@Observes @WithAnnotations({Dependent.class}) ProcessAnnotatedType<?> pat) {
+        final Class<?> javaClass = pat.getAnnotatedType().getJavaClass();
+        if (isJaxrs(javaClass) && isNotJerseyInternal(javaClass)) {
+            pat.configureAnnotatedType().add(CustomAnnotationLiteral.INSTANCE);
+            annotatedBeans.put(javaClass, Dependent.class);
+        }
+    }
+
+    void handleSessionScoped(@Observes @WithAnnotations({SessionScoped.class}) ProcessAnnotatedType<?> pat) {
+        final Class<?> javaClass = pat.getAnnotatedType().getJavaClass();
+        if (isJaxrs(javaClass) && isNotJerseyInternal(javaClass)) {
+            pat.configureAnnotatedType().add(CustomAnnotationLiteral.INSTANCE);
+            annotatedBeans.put(javaClass, SessionScoped.class);
+        }
+    }
+
+    void registerSingletonSubResources(@Observes @WithAnnotations({Singleton.class}) ProcessAnnotatedType<?> pat){
+        final Class<?> resourceClass = pat.getAnnotatedType().getJavaClass();
+        if (resourceClass.getAnnotation(Path.class) != null) {
+            annotatedBeans.put(resourceClass, Singleton.class);
+        } else if (BeanHelper.isResourceClass(resourceClass)) {
+            annotatedBeans.put(resourceClass, Singleton.class);
+        }
+    }
+
+    void registerJerseyProviders(@Observes @WithAnnotations({Priority.class}) ProcessAnnotatedType<?> pat) {
+        final Class<?> javaClass = pat.getAnnotatedType().getJavaClass();
+        if (!isNotJerseyInternal(javaClass)) {
+            pat.veto(); //veto Jersey internal
+        }
+        annotatedBeans.put(javaClass, Priority.class);
+    }
+
+    /**
+     * Wraps all JAX-RS components by Jersey-specific injection target.
+     *
+     * @param pit process injection target.
+     * @param <T> type of the processed injection target.
+     */
+    public <T> void observeInjectionTarget(@Observes ProcessInjectionTarget<T> pit) {
+        if (!BeanInjectionTarget.class.isInstance(pit.getInjectionTarget())) {
+            return;
+        }
+        BasicInjectionTarget<T> it = (BasicInjectionTarget<T>) pit.getInjectionTarget();
+        JerseyInjectionTarget<T> jerseyInjectionTarget =
+                new JerseyInjectionTarget<>(it, pit.getAnnotatedType().getJavaClass());
+        jerseyInjectionTargets.add(jerseyInjectionTarget);
+        pit.setInjectionTarget(jerseyInjectionTarget);
+    }
+
+    /**
+     * Takes all registered bindings and registers them in {@link BeanManager}.
+     * <p>
+     * Method should register only Jersey internal components and class/instances registered using {@link Application}. Registered
+     * classes/instances have priority therefore CDI scanning should veto these classes/instances during {
+     *
+     * @param abd         {@code AfterBeanDiscovery} event.
+     * @param beanManager current {@code BeanManager}.
+     * @link ProcessAnnotatedType} bootstrap phase.
+     */
+    void registerBeans(@Observes AfterBeanDiscovery abd, BeanManager beanManager) {
+        serverInjectionManager.set(new CdiInjectionManager(beanManager, mergedBindings));
+
+        beanManagerSupplier = () -> beanManager; // set bean manager supplier to be called by bindings#configure
+        CdiInjectionManagerFactoryBase.setBeanManager(beanManager);
+
+        registerApplicationHandler(beanManager);
+
+        registrationDone.set(true); //
+
+        final List<InjectionResolver> contextInjectionResolvers = serverBindings.getBindings().stream()
+                .filter(binding -> InjectionResolverBinding.class.isAssignableFrom(binding.getClass()))
+                .map(InjectionResolverBinding.class::cast)
+                .map(InjectionResolverBinding::getResolver)
+                .collect(Collectors.toList());
+
+        injectionResolvers.addAll(contextInjectionResolvers);
+
+        /*
+         * Provide registered InjectionResolvers to Jersey's components which has been discovered by CDI in
+         * ProcessInjectionTarget bootstrap phase.
+         */
+        jerseyInjectionTargets.forEach(injectionTarget -> injectionTarget.setInjectionResolvers(injectionResolvers));
+
+        registerBeans(RuntimeType.SERVER, this.serverBindings, abd, beanManager);
+        registerBeans(RuntimeType.CLIENT, this.clientBindings, abd, beanManager);
+
+        abd.addBean(new RequestScopeBean(beanManager));
+
+        addAnnotatedBeans(abd, beanManager);
+
+        serverBootstrapInjectionManager.setInjectionManager(serverInjectionManager.get());
+        ((CdiInjectionManager) serverInjectionManager.get()).managedBeans = managedBeans;
+    }
+
+    private void registerBeans(RuntimeType runtimeType, CachingBinder binder, AfterBeanDiscovery abd,
+                               BeanManager beanManager) {
+        final Collection<Binding> bindings = binder.getBindings();
+        binder.setReadOnly();
+
+        allBindingsLabel:
+        for (Binding binding : bindings) {
+            if (ClassBinding.class.isAssignableFrom(binding.getClass())) {
+                if (RuntimeType.CLIENT == runtimeType) {
+                    for (Type contract : ((ClassBinding<?>) binding).getContracts()) {
+                        final List<BindingBeanPair> preregistered = classBindings.get(contract);
+                        if (preregistered != null && preregistered.size() == 1) {
+                            BeanHelper.updateBean(
+                                    (ClassBinding<?>) binding, preregistered.get(0), injectionResolvers, beanManager);
+                            continue allBindingsLabel;
+                        }
+                    }
+                }
+                BindingBeanPair pair = BeanHelper.registerBean(
+                        runtimeType, (ClassBinding<?>) binding, abd, injectionResolvers, beanManager);
+                for (Type contract : ((ClassBinding<?>) binding).getContracts()) {
+                    classBindings.add(contract, pair);
+                }
+            } else if (SupplierClassBinding.class.isAssignableFrom(binding.getClass())) {
+                if (RuntimeType.CLIENT == runtimeType) {
+                    for (Type contract : ((SupplierClassBinding<?>) binding).getContracts()) {
+                        final List<BindingBeanPair> preregistered = supplierClassBindings.get(contract);
+                        if (preregistered != null && preregistered.size() == 1) {
+                            BeanHelper.updateSupplierBean(
+                                    (SupplierClassBinding<?>) binding, preregistered.get(0), injectionResolvers, beanManager);
+                            continue allBindingsLabel;
+                        }
+                    }
+                }
+                BindingBeanPair pair = BeanHelper.registerSupplier(
+                        runtimeType, (SupplierClassBinding<?>) binding, abd, injectionResolvers, beanManager);
+                for (Type contract : ((SupplierClassBinding<?>) binding).getContracts()) {
+                    supplierClassBindings.add(contract, pair);
+                }
+            } else if (InitializableInstanceBinding.class.isAssignableFrom(binding.getClass())) {
+                if (RuntimeType.SERVER == runtimeType
+                        || !matchInitializableInstanceBinding((InitializableInstanceBinding<?>) binding)) {
+                    initializableInstanceBindings.add((InitializableInstanceBinding<?>) binding);
+                    BeanHelper.registerBean(
+                            runtimeType, (InitializableInstanceBinding<?>) binding, abd, injectionResolvers, beanManager);
+                }
+            } else if (InitializableSupplierInstanceBinding.class.isInstance(binding)) {
+                if (RuntimeType.SERVER == runtimeType
+                        || !matchInitializableSupplierInstanceBinding((InitializableSupplierInstanceBinding) binding)) {
+                    initializableSupplierInstanceBindings.add((InitializableSupplierInstanceBinding) binding);
+                    BeanHelper.registerSupplier(runtimeType, (InitializableSupplierInstanceBinding<?>) binding, abd, beanManager);
+                }
+            }
+        }
+    }
+
+    private void addAnnotatedBeans(AfterBeanDiscovery abd, BeanManager beanManager) {
+        for (Map.Entry<Class<?>, Class<? extends Annotation>> contract : annotatedBeans.entrySet()) {
+            for (Binding binding : serverBindings.getBindings()) {
+                if (ClassBinding.class.isInstance(binding)) {
+                    if (((ClassBinding) binding).getService() == contract.getClass()) {
+                        break;
+                    }
+                }
+                if (InitializableInstanceBinding.class.isInstance(binding)) {
+                    if (((InitializableInstanceBinding) binding).getImplementationType() == contract.getClass()) {
+                        break;
+                    }
+                }
+            }
+            if (isNotJerseyInternal(contract.getKey())) {
+                if (beanManager.getBeans(contract.getKey()).isEmpty()) {
+                    final ClassBinding<?> binding = bind(contract.getKey(), annotatedBeansBinder);
+                    if (Singleton.class.equals(contract.getValue())) {
+                        binding.in(Singleton.class);
+                    }
+                }
+                managedBeans.add(contract.getKey()); // add either way
+            }
+        }
+
+        registerBeans(RuntimeType.SERVER, annotatedBeansBinder, abd, beanManager);
+        serverBindings.getBindings().addAll(annotatedBeansBinder.getBindings());
+    }
+
+    private void registerApplicationHandler(BeanManager beanManager) {
+        final ResourceConfig resourceConfig = new ResourceConfig();
+
+        for (Class<Application> applicationClass : applications) {
+            bindApplication(applicationClass, resourceConfig, beanManager);
+        }
+
+        new ApplicationHandler(resourceConfig);
+    }
+
+    private void bindApplication(Class<Application> applicationClass, ResourceConfig resourceConfig, BeanManager beanManager) {
+        final Application application = new Unmanaged<>(applicationClass).newInstance().produce().get();
+
+        for (Class<?> clazz : application.getClasses()) {
+            if (beanManager.getBeans(clazz).isEmpty()) {
+                // prevent double registration of a class
+                // bind(clazz, binder);
+                resourceConfig.register(clazz);
+            } else if (!annotatedBeans.containsKey(clazz)) {
+                annotatedBeans.put(clazz, Provider.class);
+            }
+        }
+        for (Object singleton : application.getSingletons()) {
+            final Class<?> clazz = singleton.getClass();
+            if (beanManager.getBeans(clazz).isEmpty()) {
+                // prevent double registration of a class
+//                final InstanceBinding<?> binding = binder.bind(singleton);
+//                toSuper(clazz, binding);
+                resourceConfig.register(singleton);
+            } else if (!annotatedBeans.containsKey(clazz)) {
+                annotatedBeans.put(clazz, Provider.class);
+            }
+        }
+    }
+
+//    private void bindApplication(Class<Application> applicationClass, AbstractBinder binder, BeanManager beanManager) {
+//        final Application application = new Unmanaged<>(applicationClass).newInstance().produce().get();
+//        final CommonConfig commonConfig = new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL);
+//
+//        for (Class<?> clazz : application.getClasses()) {
+//            if (beanManager.getBeans(clazz).isEmpty()) {
+//                // prevent double registration of a class
+//                // bind(clazz, binder);
+//                commonConfig.register(clazz);
+//            } else if (!annotatedBeans.containsKey(clazz)) {
+//                annotatedBeans.put(clazz, Provider.class);
+//            }
+//        }
+//        for (Object singleton : application.getSingletons()) {
+//            final Class<?> clazz = singleton.getClass();
+//            if (beanManager.getBeans(clazz).isEmpty()) {
+//                // prevent double registration of a class
+////                final InstanceBinding<?> binding = binder.bind(singleton);
+////                toSuper(clazz, binding);
+//                commonConfig.register(singleton);
+//            } else if (!annotatedBeans.containsKey(clazz)) {
+//                annotatedBeans.put(clazz, Provider.class);
+//            }
+//        }
+//    }
+
+    private static <T> ClassBinding<T> bind(Class<T> clazz, AbstractBinder binder) {
+        final ClassBinding<T> binding = binder.bindAsContract(clazz);
+        return toSuper(clazz, binding);
+    }
+
+    private static <T extends Binding> T toSuper(Class<?> clazz, T binding) {
+        Class<?> superClass = clazz;
+        while (superClass != null) {
+            superClass = superClass.getSuperclass();
+            if (superClass != null) {
+                binding.to(superClass);
+            }
+        }
+        for (Class<?> intf : clazz.getInterfaces()){
+            binding.to(intf);
+        }
+        return binding;
+    }
+
+//    // Check first if a class is a JAX-RS resource, and only if so check with validation.
+//    // This prevents unnecessary warnings being logged for pure CDI beans.
+//    private final Cache<Class<?>, Boolean> jaxRsResourceCache = new Cache<>(
+//            clazz -> Resource.from(clazz, true) != null && Resource.from(clazz) != null);
+//
+//    public boolean isJaxRsResource(Class<?> resource) {
+//        return jaxRsResourceCache.apply(resource);
+//    }
+
+    private boolean isJaxrs(Class<?> clazz) {
+        return Providers.isJaxRsProvider(clazz) || BeanHelper.isResourceClass(clazz) || isJerseyRegistrable(clazz);
+    }
+
+    private boolean isJerseyRegistrable(Class<?> clazz) {
+        return Feature.class.isAssignableFrom(clazz) || DynamicFeature.class.isAssignableFrom(clazz);
+    }
+
+    private boolean isNotJerseyInternal(Class<?> clazz) {
+        final Package pkg = clazz.getPackage();
+        if (pkg == null) { // Class.getPackage() could return null
+            return false;
+        }
+
+        final String pkgName = pkg.getName();
+        return !pkgName.startsWith("org.glassfish.jersey")
+                || pkgName.startsWith("org.glassfish.jersey.examples")
+                || pkgName.startsWith("org.glassfish.jersey.tests");
+    }
+
+    private boolean matchInitializableInstanceBinding(InitializableInstanceBinding candidate) {
+        for (InitializableInstanceBinding iib : initializableInstanceBindings) {
+            if (iib.matches(candidate).matches()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean matchInitializableSupplierInstanceBinding(InitializableSupplierInstanceBinding candidate) {
+        for (InitializableSupplierInstanceBinding isib : initializableSupplierInstanceBindings) {
+            if (isib.matches(candidate).matches()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /** To be used by the tests only */
+    public void register(BeforeBeanDiscovery beforeBeanDiscovery, Binding binding) {
+        register(RuntimeType.SERVER, binding);
+    }
+
+    /** To be used by the tests only */
+    public void register(BeforeBeanDiscovery beforeBeanDiscovery, Iterable<Binding> bindings) {
+        register(RuntimeType.SERVER, bindings);
+    }
+
+    private void register(RuntimeType runtimeType, Binding binding) {
+        final AbstractBinder bindings = runtimeType == RuntimeType.CLIENT ? clientBindings : serverBindings;
+        if (InstanceBinding.class.isInstance(binding)) {
+            bindings.bind(InitializableInstanceBinding.from((InstanceBinding) binding));
+        } else if (SupplierInstanceBinding.class.isInstance(binding)) {
+            bindings.bind(InitializableSupplierInstanceBinding.from((SupplierInstanceBinding) binding));
+        } else {
+            bindings.bind(binding);
+        }
+    }
+
+    private void register(RuntimeType runtimeType, Iterable<Binding> bindings) {
+        for (Binding binding : bindings) {
+            register(runtimeType, binding);
+        }
+    }
+
+    private void processRegistrars() {
+        final List<BootstrapPreinitialization> registrars = new LinkedList<>();
+        for (BootstrapPreinitialization registrar : ServiceFinder.find(BootstrapPreinitialization.class)) {
+            registrars.add(registrar);
+        }
+        for (BootstrapPreinitialization registrar : registrars) {
+            registrar.register(RuntimeType.SERVER, serverBindings);
+        }
+
+        for (BootstrapPreinitialization registrar : registrars) {
+            registrar.register(RuntimeType.CLIENT, clientBindings);
+        }
+    }
+
+    InjectionManager getInjectionManager(RuntimeType runtimeType) {
+        if (RuntimeType.CLIENT == runtimeType) {
+            return registrationDone.get()
+                    ? new CdiClientInjectionManager(beanManagerSupplier.get(), mergedBindings)
+                    : clientBootstrapInjectionManager;
+        } else {
+            return registrationDone.get() ? serverInjectionManager.get() : serverBootstrapInjectionManager;
+        }
+    }
+
+    /**
+     * Injection manager used during the bootstrap. It is used to create the actual beans in the beans manager.
+     * Other InjectionManagers sets the beans (beans binding) by a value provided in runtime.
+     */
+    private class BootstrapInjectionManager implements InjectionManager {
+
+        private final RuntimeType runtimeType;
+
+        private BootstrapInjectionManager(RuntimeType runtimeType) {
+            this.runtimeType = runtimeType;
+        }
+
+        @Override
+        public void completeRegistration() {
+            //noop
+        }
+
+        @Override
+        public void shutdown() {
+            //noop
+        }
+
+        @Override
+        public void register(Binding binding) {
+            BinderRegisterExtension.this.register(runtimeType, binding);
+        }
+
+        @Override
+        public void register(Iterable<Binding> descriptors) {
+           for (Binding binding : descriptors) {
+               register(binding);
+           }
+        }
+
+        @Override
+        public void register(Binder binder) {
+            register(binder.getBindings());
+        }
+
+        @Override
+        public void register(Object provider) throws IllegalArgumentException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean isRegistrable(Class<?> clazz) {
+            return false;
+        }
+
+        @Override
+        public <T> T createAndInitialize(Class<T> createMe) {
+            if (RequestScope.class == createMe) {
+                return (T) new CdiRequestScope();
+            }
+            if (isNotJerseyInternal(createMe)) {
+                return null;
+            }
+            try {
+                Constructor<T> constructor = createMe.getConstructor();
+                return constructor.newInstance();
+            } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
+                return null;
+            }
+        }
+
+        @Override
+        public <T> T create(Class<T> createMe) {
+            return createAndInitialize(createMe);
+        }
+
+        @Override
+        public <T> List<ServiceHolder<T>> getAllServiceHolders(Class<T> contractOrImpl, Annotation... qualifiers) {
+            return Collections.EMPTY_LIST;
+        }
+
+        @Override
+        public <T> T getInstance(Class<T> contractOrImpl, Annotation... qualifiers) {
+            return getInstance(contractOrImpl);
+        }
+
+        @Override
+        public <T> T getInstance(Class<T> contractOrImpl, String classAnalyzer) {
+            return getInstance(contractOrImpl);
+        }
+
+        @Override
+        public <T> T getInstance(Class<T> contractOrImpl) {
+            return createAndInitialize(contractOrImpl);
+        }
+
+        @Override
+        public <T> T getInstance(Type contractOrImpl) {
+            return (T) createAndInitialize((Class) contractOrImpl);
+        }
+
+        @Override
+        public Object getInstance(ForeignDescriptor foreignDescriptor) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public ForeignDescriptor createForeignDescriptor(Binding binding) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> List<T> getAllInstances(Type contractOrImpl) {
+            final T t = getInstance(contractOrImpl);
+            return t != null ? Collections.singletonList(t) : Collections.EMPTY_LIST;
+        }
+
+        @Override
+        public void inject(Object injectMe) {
+           // noop;
+        }
+
+        @Override
+        public void inject(Object injectMe, String classAnalyzer) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void preDestroy(Object preDestroyMe) {
+            //noop
+        }
+    }
+
+    /**
+     * AbstractBinder that supports calling {@link #getBindings()} multiple times by caching the result.
+     * Each additional binding is added to the cache by the next call of {@link #getBindings()}.
+     * When {@link #setReadOnly()} is called, no additional binding is added to the cache.
+     */
+    private class CachingBinder extends AbstractBinder {
+        private final Ref<InjectionManager> injectionManager;
+        private AbstractBinder temporaryBinder = new TemporaryBinder();
+        private final Collection<Binding> bindings = new LinkedList<>();
+
+        private CachingBinder(Ref<InjectionManager> injectionManager) {
+            this.injectionManager = injectionManager;
+        }
+
+        @Override
+        protected void configure() {
+            // noop
+        }
+
+        @Override
+        public <T> ClassBinding<T> bind(Class<T> serviceType) {
+            return temporaryBinder.bind(serviceType);
+        }
+
+        @Override
+        public Binding bind(Binding binding) {
+            return temporaryBinder.bind(binding);
+        }
+
+        @Override
+        public <T> ClassBinding<T> bindAsContract(GenericType<T> serviceType) {
+            return temporaryBinder.bindAsContract(serviceType);
+        }
+
+        @Override
+        public <T> ClassBinding<T> bindAsContract(Class<T> serviceType) {
+            return temporaryBinder.bindAsContract(serviceType);
+        }
+
+        @Override
+        public ClassBinding<Object> bindAsContract(Type serviceType) {
+            return temporaryBinder.bindAsContract(serviceType);
+        }
+
+        @Override
+        public <T> InstanceBinding<T> bind(T service) {
+            return temporaryBinder.bind(service);
+        }
+
+        @Override
+        public <T> SupplierClassBinding<T> bindFactory(
+                Class<? extends Supplier<T>> supplierType, Class<? extends Annotation> supplierScope) {
+            return temporaryBinder.bindFactory(supplierType, supplierScope);
+        }
+
+        @Override
+        public <T> SupplierClassBinding<T> bindFactory(Class<? extends Supplier<T>> supplierType) {
+            return temporaryBinder.bindFactory(supplierType);
+        }
+
+        @Override
+        public <T> SupplierInstanceBinding<T> bindFactory(Supplier<T> factory) {
+            return temporaryBinder.bindFactory(factory);
+        }
+
+        @Override
+        public <T extends InjectionResolver> InjectionResolverBinding<T> bind(T resolver) {
+            return temporaryBinder.bind(resolver);
+        }
+
+        @Override
+        public Collection<Binding> getBindings() {
+            if (!readOnly) {
+                if (registrationDone.get()) {
+                    bindings.addAll(super.getBindings());
+                }
+                final Collection<Binding> newBindings = temporaryBinder.getBindings();
+                for (Binding binding : newBindings) {
+                    if (InstanceBinding.class.isAssignableFrom(binding.getClass())) {
+                        binding = InitializableInstanceBinding.from((InstanceBinding) binding);
+                    } else if (SupplierInstanceBinding.class.isAssignableFrom(binding.getClass())) {
+                        binding = InitializableSupplierInstanceBinding.from((SupplierInstanceBinding) binding);
+                    }
+                    bindings.add(binding);
+                }
+                temporaryBinder = new TemporaryBinder();
+            }
+            return bindings;
+        }
+
+        private boolean readOnly = false;
+
+        void setReadOnly() {
+            readOnly = true;
+        }
+
+        private class TemporaryBinder extends AbstractBinder {
+
+            @Override
+            protected void configure() {
+                // do nothing
+            }
+        }
+    }
+
+    private static class MergedBindings implements Binder {
+        private final AbstractBinder first;
+        private final AbstractBinder second;
+
+
+        private MergedBindings(AbstractBinder first, AbstractBinder second) {
+            this.first = first;
+            this.second = second;
+        }
+
+        public Collection<Binding> getBindings() {
+            final Collection<Binding> firstBindings = first.getBindings();
+            final Collection<Binding> secondBindings = second.getBindings();
+
+            Collection<Binding> merged = new Collection<Binding>() {
+                @Override
+                public int size() {
+                    return firstBindings.size() + secondBindings.size();
+                }
+
+                @Override
+                public boolean isEmpty() {
+                    return firstBindings.isEmpty() && secondBindings.isEmpty();
+                }
+
+                @Override
+                public boolean contains(Object o) {
+                    return firstBindings.contains(o) || secondBindings.contains(o);
+                }
+
+                @Override
+                public Iterator<Binding> iterator() {
+                    final Iterator<Binding> firstIterator = firstBindings.iterator();
+                    final Iterator<Binding> secondIterator = secondBindings.iterator();
+                    return new Iterator<Binding>() {
+                        @Override
+                        public boolean hasNext() {
+                            return firstIterator.hasNext() || secondIterator.hasNext();
+                        }
+
+                        @Override
+                        public Binding next() {
+                            return firstIterator.hasNext() ? firstIterator.next() : secondIterator.next();
+                        }
+                    };
+                }
+
+                // Used by IDE while debugging
+                @Override
+                public Object[] toArray() {
+                    Object[] array = new Object[size()];
+                    final Iterator<Binding> bindingIterator = iterator();
+                    int i = 0;
+                    while (bindingIterator.hasNext()) {
+                        array[i++] = bindingIterator.next();
+                    }
+                    return array;
+                }
+
+                @Override
+                public <T> T[] toArray(T[] a) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean add(Binding binding) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean remove(Object o) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean containsAll(Collection<?> c) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean addAll(Collection<? extends Binding> c) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean removeAll(Collection<?> c) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean retainAll(Collection<?> c) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public void clear() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+            return merged;
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiClientInjectionManager.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiClientInjectionManager.java
new file mode 100644
index 0000000..46db64b
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiClientInjectionManager.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.bean.JerseyBean;
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableSupplierInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.inject.MatchableBinding;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyClientCreationalContext;
+import org.glassfish.jersey.internal.inject.Binder;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.Bindings;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InstanceBinding;
+import org.glassfish.jersey.internal.inject.SupplierClassBinding;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+import org.jboss.weld.contexts.CreationalContextImpl;
+
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * Each Client Runtime has a unique CdiClientInjectionManager, which passes proper {@link Binding} to the Weld.
+ */
+public class CdiClientInjectionManager extends CdiInjectionManager {
+
+    private Map<InitializableInstanceBinding, InitializableInstanceBinding> clientInstanceBindings = new IdentityHashMap<>();
+    private Map<InitializableSupplierInstanceBinding, InitializableSupplierInstanceBinding> clientSupplierInstanceBindings
+            = new IdentityHashMap<>();
+    private Map<SupplierClassBinding, SupplierClassBinding> clientSupplierClassBinding = new IdentityHashMap<>();
+
+    public CdiClientInjectionManager(BeanManager beanManager, Binder bindings) {
+        super(beanManager, bindings);
+    }
+
+    @Override
+    public void register(Binding binding) {
+        if (InstanceBinding.class.isInstance(binding)) {
+            final Collection<Binding> preBindings = getBindings().getBindings();
+            MatchableBinding.Matching<InitializableInstanceBinding> matching = MatchableBinding.Matching.noneMatching();
+            for (Binding preBinding : preBindings) {
+                if (InitializableInstanceBinding.class.isInstance(preBinding)) {
+                    matching = matching.better(((InitializableInstanceBinding) preBinding).matches((InstanceBinding) binding));
+                    if (matching.isBest()) {
+                        break;
+                    }
+                }
+            }
+            if (matching.matches()) {
+                final InitializableInstanceBinding clone = matching.getBinding().clone();
+                clone.init(((InstanceBinding) binding).getService());
+                clientInstanceBindings.put(matching.getBinding(), clone);
+            } else {
+                throw new IllegalStateException("Not initialized " + ((InstanceBinding<?>) binding).getService());
+            }
+        } else if (SupplierInstanceBinding.class.isInstance(binding)) {
+            final Collection<Binding> preBindings = getBindings().getBindings();
+            MatchableBinding.Matching<InitializableSupplierInstanceBinding> matching = MatchableBinding.Matching.noneMatching();
+            for (Binding preBinding : preBindings) {
+                if (InitializableSupplierInstanceBinding.class.isInstance(preBinding)) {
+                    matching = matching.better(((InitializableSupplierInstanceBinding) preBinding).matchesContracts(binding));
+                    if (matching.isBest()) {
+                        break;
+                    }
+                }
+            }
+            if (matching.matches()) {
+                final InitializableSupplierInstanceBinding clone = matching.getBinding().clone();
+                clone.init(((SupplierInstanceBinding) binding).getSupplier());
+                clientSupplierInstanceBindings.put(matching.getBinding(), clone);
+            } else {
+                throw new IllegalStateException("Not initialized " + ((SupplierInstanceBinding<?>) binding).getSupplier());
+            }
+//        } else if (SupplierClassBinding.class.isInstance(binding)) {
+//            final Collection<Binding> preBindings = getBindings().getBindings();
+//            BindingMatching.Matching<SupplierClassBinding> matching = BindingMatching.Matching.noneMatching();
+//            for (Binding preBinding : preBindings) {
+//                if (SupplierClassBinding.class.isInstance(preBinding)) {
+//                    matching = matching.better(BindingMatching.matches(preBinding, binding));
+//                    if (matching.isBest()) {
+//                        break;
+//                    }
+//                }
+//            }
+//            if (matching.matches()) {
+//                final SupplierClassBinding clone = BindingCloner.clone((SupplierClassBinding) binding);
+//                clientSupplierClassBinding.put(matching.getBinding(), clone);
+//            } else {
+//                throw new IllegalStateException("Not initialized " + ((SupplierInstanceBinding<?>) binding).getSupplier());
+//            }
+        }
+    }
+
+    public InitializableInstanceBinding getInjectionManagerBinding(InitializableInstanceBinding binding) {
+        InitializableInstanceBinding clientBinding = clientInstanceBindings.get(binding);
+        return clientBinding != null ? clientBinding : binding;
+    }
+
+    public InitializableSupplierInstanceBinding getInjectionManagerBinding(InitializableSupplierInstanceBinding binding) {
+        InitializableSupplierInstanceBinding clientBinding = clientSupplierInstanceBindings.get(binding);
+        return clientBinding != null ? clientBinding : binding;
+    }
+
+    public SupplierClassBinding getInjectionManagerBinding(SupplierClassBinding binding) {
+        SupplierClassBinding clientBinding = clientSupplierClassBinding.get(binding);
+        return clientBinding;
+    }
+
+    @Override
+    public void shutdown() {
+        clientInstanceBindings.clear();
+    }
+
+    @Override
+    protected <T> CreationalContext<T> createCreationalContext(Bean<T> bean) {
+        final CreationalContext<T> ctx = new JerseyClientCreationalContext<T>(
+                (CreationalContextImpl<T>) super.createCreationalContext(bean)).setInjectionManager(this);
+        return ctx;
+    }
+
+    @Override
+    public void completeRegistration() throws IllegalStateException {
+        register(Bindings.service(this).to(InjectionManager.class));
+    }
+
+    @Override
+    protected boolean isRuntimeTypeBean(Bean<?> bean) {
+        return !JerseyBean.class.isInstance(bean) || ((JerseyBean) bean).getRutimeType() == RuntimeType.CLIENT;
+    }
+
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiInjectionManager.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiInjectionManager.java
new file mode 100644
index 0000000..a99f2f0
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiInjectionManager.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.inject.spi.Unmanaged;
+import javax.inject.Singleton;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.inject.InitializableSupplierInstanceBinding;
+import org.glassfish.jersey.inject.weld.internal.bean.JerseyBean;
+import org.glassfish.jersey.inject.weld.internal.inject.MatchableBinding;
+import org.glassfish.jersey.internal.inject.Binder;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.Bindings;
+import org.glassfish.jersey.internal.inject.ClassBinding;
+import org.glassfish.jersey.internal.inject.ForeignDescriptor;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InstanceBinding;
+import org.glassfish.jersey.internal.inject.ServiceHolder;
+import org.glassfish.jersey.internal.inject.ServiceHolderImpl;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+
+/**
+ * Implementation of {@link InjectionManager} used on the server side.
+ */
+@Singleton
+public class CdiInjectionManager implements InjectionManager {
+
+    private final BeanManager beanManager;
+    private final Binder bindings;
+    private boolean isCompleted = false;
+    Set<Class<?>> managedBeans;
+
+    // Keeps all binders and bindings added to the InjectionManager during the bootstrap.
+
+    public CdiInjectionManager(BeanManager beanManager, Binder bindings) {
+        this.beanManager = beanManager;
+        this.bindings = bindings;
+    }
+
+    @Override
+    public void register(Binding binding) {
+        if (isManagedClass(binding)) {
+            return;
+        }
+        if (InstanceBinding.class.isInstance(binding)) {
+            final Collection<Binding> preBindings = bindings.getBindings();
+            MatchableBinding.Matching<InitializableInstanceBinding> matching = MatchableBinding.Matching.noneMatching();
+            for (Binding preBinding : preBindings) {
+                if (InitializableInstanceBinding.class.isInstance(preBinding)) {
+                    matching = matching.better(((InitializableInstanceBinding) preBinding).matches((InstanceBinding) binding));
+                    if (matching.isBest()) {
+                        break;
+                    }
+                }
+            }
+            if (matching.matches()) {
+               matching.getBinding().init(((InstanceBinding) binding).getService());
+            } else if (findClassBinding(binding.getImplementationType()) == null) {
+                throw new IllegalStateException("Not initialized " + ((InstanceBinding<?>) binding).getService());
+            }
+        } else if (SupplierInstanceBinding.class.isInstance(binding)) {
+            final Collection<Binding> preBindings = bindings.getBindings();
+            MatchableBinding.Matching<InitializableSupplierInstanceBinding> matching = MatchableBinding.Matching.noneMatching();
+            for (Binding preBinding : preBindings) {
+                if (InitializableSupplierInstanceBinding.class.isInstance(preBinding)) {
+                    matching = matching.better(
+                            ((InitializableSupplierInstanceBinding) preBinding).matches((SupplierInstanceBinding) binding));
+                    if (matching.isBest()) {
+                        break;
+                    }
+                }
+            }
+            if (matching.matches()) {
+                matching.getBinding().init(((SupplierInstanceBinding) binding).getSupplier());
+            } else {
+                throw new IllegalStateException("Not initialized " + ((SupplierInstanceBinding<?>) binding).getSupplier());
+            }
+        } else if (ClassBinding.class.isInstance(binding)) {
+            if (findClassBinding(binding.getImplementationType()) == null) {
+//            final Collection<Binding> preBindings = bindings.getBindings();
+//            boolean found = false;
+//            for (Binding preBinding : preBindings) {
+//                if (ClassBinding.class.isInstance(preBinding)
+//                        && ((ClassBinding) preBinding).getImplementationType()
+//                            .equals(((ClassBinding) binding).getImplementationType())) {
+//                        found = true;
+//                        break;
+//                }
+//            }
+//            if (!found) {
+                throw new IllegalStateException("ClassBinding for " + binding.getImplementationType() + " not preregistered");
+            }
+        }
+    }
+
+    private <T> ClassBinding<T> findClassBinding(Class<T> implementationType) {
+        final Collection<Binding> preBindings = bindings.getBindings();
+        boolean found = false;
+        for (Binding preBinding : preBindings) {
+            if (ClassBinding.class.isInstance(preBinding)
+                    && ((ClassBinding) preBinding).getImplementationType().equals(implementationType)) {
+                return (ClassBinding<T>) preBinding;
+            }
+        }
+        return null;
+    }
+
+    private boolean isManagedClass(Binding binding) {
+        return managedBeans != null
+                && binding.getImplementationType() != null
+                && (managedBeans.contains(binding.getImplementationType())
+                    || (managedBeans.contains(binding.getImplementationType().getSuperclass())));
+    }
+
+    @Override
+    public void register(Iterable<Binding> bindings) {
+        for (Binding binding : bindings) {
+            register(binding);
+        }
+    }
+
+    @Override
+    public void register(Binder binder) {
+        for (Binding binding : Bindings.getBindings(this, binder)) {
+            register(binding);
+        }
+    }
+
+    @Override
+    public void register(Object provider) throws IllegalArgumentException {
+        throw new IllegalArgumentException(LocalizationMessages.CDI_2_PROVIDER_NOT_REGISTRABLE(provider.getClass()));
+    }
+
+    @Override
+    public boolean isRegistrable(Class<?> clazz) {
+        return false;
+    }
+
+    @Override
+    public <T> T create(Class<T> createMe) {
+        Unmanaged.UnmanagedInstance<T> unmanaged = new Unmanaged<>(createMe).newInstance();
+        return unmanaged.produce().get();
+    }
+
+    @Override
+    public <T> T createAndInitialize(Class<T> createMe) {
+        Unmanaged.UnmanagedInstance<T> unmanaged = new Unmanaged<>(createMe).newInstance();
+        return unmanaged.produce()
+                .inject()
+                .postConstruct()
+                .get();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> List<ServiceHolder<T>> getAllServiceHolders(Class<T> contractOrImpl, Annotation... qualifiers) {
+        List<ServiceHolder<T>> result = new ArrayList<>();
+        for (Bean<?> bean : beanManager.getBeans(contractOrImpl, qualifiers)) {
+
+            if (!isRuntimeTypeBean(bean)) {
+                continue;
+            }
+
+            CreationalContext<?> ctx = createCreationalContext(bean);
+            T reference = (T) beanManager.getReference(bean, contractOrImpl, ctx);
+
+            int rank = 1;
+            if (bean instanceof JerseyBean) {
+                rank = ((JerseyBean) bean).getRank();
+            }
+
+            result.add(new ServiceHolderImpl<>(reference, (Class<T>) bean.getBeanClass(), bean.getTypes(), rank));
+        }
+        return result;
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl, Annotation... qualifiers) {
+        return getInstanceInternal(contractOrImpl, qualifiers);
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl) {
+        return getInstanceInternal(contractOrImpl);
+    }
+
+    @Override
+    public <T> T getInstance(Type contractOrImpl) {
+        return getInstanceInternal(contractOrImpl);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T getInstanceInternal(Type contractOrImpl, Annotation... qualifiers) {
+//        if (contractOrImpl.getTypeName().contains("HelloResource")) {
+//            T t = (T) CDI.current().select((Class) contractOrImpl, qualifiers).get();
+//            try {
+//                System.out.println(t.getClass().getMethod("hello").invoke(t));
+////                t.getClass().getMethod("hello").invoke(t);
+//            } catch (IllegalAccessException e) {
+//                e.printStackTrace();
+//            } catch (InvocationTargetException e) {
+//                e.printStackTrace();
+//            } catch (NoSuchMethodException e) {
+//                e.printStackTrace();
+//            }
+//            return t;
+//        }
+        Set<Bean<?>> beans = beanManager.getBeans(contractOrImpl, qualifiers);
+        if (beans.isEmpty()) {
+            return null; //ScopesTest
+        }
+
+        final Iterator<?> beansIterator = beans.iterator();
+        Bean<?> bean = (Bean<?>) beansIterator.next();
+        while (beansIterator.hasNext() && !JerseyBean.class.isInstance(bean) && !isRuntimeTypeBean(bean)) {
+            bean = (Bean<?>) beansIterator.next(); // prefer Jersey binding
+        }
+        CreationalContext<T> ctx = createCreationalContext((Bean<T>) bean);
+        return (T) beanManager.getReference(bean, contractOrImpl, ctx);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Object getInstance(ForeignDescriptor foreignDescriptor) {
+        Bean bean = (Bean) foreignDescriptor.get();
+        CreationalContext ctx = createCreationalContext(bean);
+        return bean.create(ctx);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ForeignDescriptor createForeignDescriptor(Binding binding) {
+        Class<?> clazz;
+        if (ClassBinding.class.isAssignableFrom(binding.getClass())) {
+            clazz = ((ClassBinding<?>) binding).getService();
+        } else if (InstanceBinding.class.isAssignableFrom(binding.getClass())) {
+            clazz = ((InstanceBinding<?>) binding).getService().getClass();
+        } else {
+            throw new RuntimeException(
+                    org.glassfish.jersey.internal.LocalizationMessages
+                            .UNKNOWN_DESCRIPTOR_TYPE(binding.getClass().getSimpleName()));
+        }
+
+        Set<Bean<?>> beans = beanManager.getBeans(clazz);
+        if (beans.isEmpty()) {
+            return null;
+        }
+
+        Bean bean = beans.iterator().next();
+        CreationalContext ctx = createCreationalContext(bean);
+        return ForeignDescriptor.wrap(bean, instance -> bean.destroy(instance, ctx));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> List<T> getAllInstances(Type contractOrImpl) {
+        List<T> result = new ArrayList<>();
+        for (Bean<?> bean : beanManager.getBeans(contractOrImpl)) {
+            CreationalContext<?> ctx = createCreationalContext(bean);
+            Object reference = beanManager.getReference(bean, contractOrImpl, ctx);
+            result.add((T) reference);
+        }
+        return result;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void inject(Object instance) {
+        AnnotatedType annotatedType = beanManager.createAnnotatedType((Class) instance.getClass());
+        InjectionTarget injectionTarget = beanManager.createInjectionTarget(annotatedType);
+        CreationalContext context = createCreationalContext(null);
+        injectionTarget.inject(instance, context);
+    }
+
+    @Override
+    public void preDestroy(Object preDestroyMe) {
+    }
+
+    @Override
+    public void completeRegistration() throws IllegalStateException {
+//        bindings.bind(Bindings.service(this).to(InjectionManager.class));
+//        bindings.install(new ContextInjectionResolverImpl.Binder(this::getBeanManager));
+//
+//        this.beanManager = new DefaultBeanManagerProvider().getBeanManager();
+//        beanManager = new DefaultBeanManagerProvider().getBeanManager();
+//
+//        AbstractBinder masterBinder = beanManager.getExtension(SeBeanRegisterExtension.class).bindings;
+//        masterBinder.getBindings().addAll(bindings.getBindings());
+
+//        bindings.bind(Bindings.service(this).to(InjectionManager.class));
+//        bindings.install(new ContextInjectionResolverImpl.Binder(this::getBeanManager));
+
+        if (!isCompleted) {
+            register(Bindings.service(this).to(InjectionManager.class));
+            isCompleted = false;
+        }
+    }
+
+    @Override
+    public void shutdown() {
+
+    }
+
+    protected Binder getBindings() {
+        return bindings;
+    }
+
+    protected BeanManager getBeanManager() {
+        return beanManager;
+    }
+
+    protected <T> CreationalContext<T> createCreationalContext(Bean<T> bean) {
+        return (CreationalContext<T>) beanManager.createCreationalContext(bean);
+    }
+
+//    protected void registerInjectionResolver(InjectionResolverBinding<?> injectionResolverBinding) {
+//       // beanManager.getExtension(BinderRegisterExtension.class).addInjectionResolver(injectionResolverBinding.getResolver());
+//    }
+
+    /**
+     * Identifies Jersey beans that are from different runtime (CLIENT vs SERVER). Used to exclude Jersey beans of incorrect
+     * {@link RuntimeType}.
+     * @param bean the given CDI bean.
+     * @return true iff the given bean is not a Jersey Bean or the Jersey Bean is of the proper {@code RuntimeType}.
+     */
+    protected boolean isRuntimeTypeBean(Bean<?> bean) {
+        return !JerseyBean.class.isInstance(bean) || ((JerseyBean) bean).getRutimeType() == RuntimeType.SERVER;
+    }
+
+    @Override
+    public void inject(Object injectMe, String classAnalyzer) {
+        // TODO: Used only in legacy CDI integration.
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl, String classAnalyzer) {
+        // TODO: Used only in legacy CDI integration.
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiInjectionManagerFactoryBase.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiInjectionManagerFactoryBase.java
new file mode 100644
index 0000000..c0c48f6
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/CdiInjectionManagerFactoryBase.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.inject.spi.BeanManager;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InjectionManagerFactory;
+
+/**
+ * CDI Injection Manager Factory base class that holds the current bean manager.
+ */
+public abstract class CdiInjectionManagerFactoryBase implements InjectionManagerFactory {
+    private static BeanManager beanManager;
+
+    /* package */ static void setBeanManager(BeanManager bm) {
+        beanManager = bm;
+    }
+
+    protected static InjectionManager getInjectionManager(RuntimeType runtimeType) {
+        return beanManager.getExtension(BinderRegisterExtension.class).getInjectionManager(runtimeType);
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ClientBootstrapPreinitialization.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ClientBootstrapPreinitialization.java
new file mode 100644
index 0000000..e82f0e0
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ClientBootstrapPreinitialization.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.ws.rs.RuntimeType;
+import javax.ws.rs.client.ClientBuilder;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.ClientRequest;
+import org.glassfish.jersey.client.JerseyClient;
+import org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization;
+import org.glassfish.jersey.internal.PropertiesDelegate;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.ReferencingFactory;
+import org.glassfish.jersey.internal.util.collection.Ref;
+
+import java.util.function.Supplier;
+
+/**
+ * Jersey Client Runtime pre-initialization implementation.
+ */
+// TODO: put to a proper Jersey module
+public class ClientBootstrapPreinitialization implements BootstrapPreinitialization {
+
+    @Override
+    public void register(RuntimeType runtimeType, AbstractBinder binder) {
+        if (runtimeType == RuntimeType.SERVER) {
+            return;
+        }
+
+        ClientConfig config = new ClientConfig();
+        JerseyClient client = (JerseyClient) ClientBuilder.newClient(config);
+        client.getConfiguration().getClientExecutor();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ServerBootstrapPreinitialization.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ServerBootstrapPreinitialization.java
new file mode 100644
index 0000000..a35f806
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/ServerBootstrapPreinitialization.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.RuntimeType;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.core.GenericType;
+
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization;
+import org.glassfish.jersey.internal.ServiceFinderBinder;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.ClassBinding;
+import org.glassfish.jersey.internal.inject.ReferencingFactory;
+import org.glassfish.jersey.internal.spi.AutoDiscoverable;
+import org.glassfish.jersey.internal.util.collection.Ref;
+import org.glassfish.jersey.model.internal.CommonConfig;
+import org.glassfish.jersey.model.internal.ComponentBag;
+import org.glassfish.jersey.process.internal.RequestScoped;
+import org.glassfish.jersey.server.wadl.WadlFeature;
+import org.glassfish.jersey.server.wadl.processor.OptionsMethodProcessor;
+import org.glassfish.jersey.server.wadl.processor.WadlModelProcessor;
+import org.glassfish.jersey.servlet.WebConfig;
+import org.glassfish.jersey.servlet.spi.AsyncContextDelegateProvider;
+import org.glassfish.jersey.servlet.spi.FilterUrlMappingsProvider;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * Jersey server side pre-initialization implementation.
+ */
+// TODO : put to a proper module
+public class ServerBootstrapPreinitialization implements BootstrapPreinitialization {
+
+
+    /**
+     * Referencing factory for Grizzly request.
+     */
+    private static class GrizzlyRequestReferencingFactory extends ReferencingFactory<Request> {
+
+        @Inject
+        public GrizzlyRequestReferencingFactory(final Provider<Ref<Request>> referenceFactory) {
+            super(referenceFactory);
+        }
+    }
+
+    /**
+     * Referencing factory for Grizzly response.
+     */
+    private static class GrizzlyResponseReferencingFactory extends ReferencingFactory<Response> {
+
+        @Inject
+        public GrizzlyResponseReferencingFactory(final Provider<Ref<Response>> referenceFactory) {
+            super(referenceFactory);
+        }
+    }
+
+    @SuppressWarnings("JavaDoc")
+    private static class HttpServletRequestReferencingFactory extends ReferencingFactory<HttpServletRequest> {
+
+        @Inject
+        public HttpServletRequestReferencingFactory(final Provider<Ref<HttpServletRequest>> referenceFactory) {
+            super(referenceFactory);
+        }
+    }
+
+    @SuppressWarnings("JavaDoc")
+    private static class HttpServletResponseReferencingFactory extends ReferencingFactory<HttpServletResponse> {
+
+        @Inject
+        public HttpServletResponseReferencingFactory(final Provider<Ref<HttpServletResponse>> referenceFactory) {
+            super(referenceFactory);
+        }
+    }
+
+    private static class WebConfigInitializer implements WebConfig {
+
+        @Override
+        public ConfigType getConfigType() {
+            return ConfigType.ServletConfig;
+        }
+
+        @Override
+        public ServletConfig getServletConfig() {
+            return new ServletConfig() {
+                @Override
+                public String getServletName() {
+                    return "Preinit";
+                }
+
+                @Override
+                public ServletContext getServletContext() {
+                    return WebConfigInitializer.this.getServletContext();
+                }
+
+                @Override
+                public String getInitParameter(String name) {
+                    return null;
+                }
+
+                @Override
+                public Enumeration<String> getInitParameterNames() {
+                    return null;
+                }
+            };
+        }
+
+        @Override
+        public FilterConfig getFilterConfig() {
+            return null;
+        }
+
+        @Override
+        public String getName() {
+            return "Preinit";
+        }
+
+        @Override
+        public String getInitParameter(String name) {
+            return getName();
+        }
+
+        @Override
+        public Enumeration getInitParameterNames() {
+            return null;
+        }
+
+        @Override
+        public ServletContext getServletContext() {
+            return new ServletContext() {
+                @Override
+                public String getContextPath() {
+                    return null;
+                }
+
+                @Override
+                public ServletContext getContext(String uripath) {
+                    return WebConfigInitializer.this.getServletContext();
+                }
+
+                @Override
+                public int getMajorVersion() {
+                    return 0;
+                }
+
+                @Override
+                public int getMinorVersion() {
+                    return 0;
+                }
+
+                @Override
+                public int getEffectiveMajorVersion() {
+                    return 0;
+                }
+
+                @Override
+                public int getEffectiveMinorVersion() {
+                    return 0;
+                }
+
+                @Override
+                public String getMimeType(String file) {
+                    return null;
+                }
+
+                @Override
+                public Set<String> getResourcePaths(String path) {
+                    return null;
+                }
+
+                @Override
+                public URL getResource(String path) throws MalformedURLException {
+                    return null;
+                }
+
+                @Override
+                public InputStream getResourceAsStream(String path) {
+                    return null;
+                }
+
+                @Override
+                public RequestDispatcher getRequestDispatcher(String path) {
+                    return null;
+                }
+
+                @Override
+                public RequestDispatcher getNamedDispatcher(String name) {
+                    return null;
+                }
+
+                @Override
+                public Servlet getServlet(String name) throws ServletException {
+                    return null;
+                }
+
+                @Override
+                public Enumeration<Servlet> getServlets() {
+                    return null;
+                }
+
+                @Override
+                public Enumeration<String> getServletNames() {
+                    return null;
+                }
+
+                @Override
+                public void log(String msg) {
+
+                }
+
+                @Override
+                public void log(Exception exception, String msg) {
+
+                }
+
+                @Override
+                public void log(String message, Throwable throwable) {
+
+                }
+
+                @Override
+                public String getRealPath(String path) {
+                    return null;
+                }
+
+                @Override
+                public String getServerInfo() {
+                    return null;
+                }
+
+                @Override
+                public String getInitParameter(String name) {
+                    return null;
+                }
+
+                @Override
+                public Enumeration<String> getInitParameterNames() {
+                    return null;
+                }
+
+                @Override
+                public boolean setInitParameter(String name, String value) {
+                    return false;
+                }
+
+                @Override
+                public Object getAttribute(String name) {
+                    return null;
+                }
+
+                @Override
+                public Enumeration<String> getAttributeNames() {
+                    return null;
+                }
+
+                @Override
+                public void setAttribute(String name, Object object) {
+
+                }
+
+                @Override
+                public void removeAttribute(String name) {
+
+                }
+
+                @Override
+                public String getServletContextName() {
+                    return null;
+                }
+
+                @Override
+                public ServletRegistration.Dynamic addServlet(String servletName, String className) {
+                    return null;
+                }
+
+                @Override
+                public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
+                    return null;
+                }
+
+                @Override
+                public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
+                    return null;
+                }
+
+                @Override
+                public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) {
+                    return null;
+                }
+
+                @Override
+                public <T extends Servlet> T createServlet(Class<T> clazz) throws ServletException {
+                    return null;
+                }
+
+                @Override
+                public ServletRegistration getServletRegistration(String servletName) {
+                    return null;
+                }
+
+                @Override
+                public Map<String, ? extends ServletRegistration> getServletRegistrations() {
+                    return null;
+                }
+
+                @Override
+                public FilterRegistration.Dynamic addFilter(String filterName, String className) {
+                    return null;
+                }
+
+                @Override
+                public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
+                    return null;
+                }
+
+                @Override
+                public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
+                    return null;
+                }
+
+                @Override
+                public <T extends Filter> T createFilter(Class<T> clazz) throws ServletException {
+                    return null;
+                }
+
+                @Override
+                public FilterRegistration getFilterRegistration(String filterName) {
+                    return null;
+                }
+
+                @Override
+                public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+                    return null;
+                }
+
+                @Override
+                public SessionCookieConfig getSessionCookieConfig() {
+                    return null;
+                }
+
+                @Override
+                public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {
+
+                }
+
+                @Override
+                public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+                    return null;
+                }
+
+                @Override
+                public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+                    return null;
+                }
+
+                @Override
+                public void addListener(String className) {
+
+                }
+
+                @Override
+                public <T extends EventListener> void addListener(T t) {
+
+                }
+
+                @Override
+                public void addListener(Class<? extends EventListener> listenerClass) {
+
+                }
+
+                @Override
+                public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException {
+                    return null;
+                }
+
+                @Override
+                public JspConfigDescriptor getJspConfigDescriptor() {
+                    return null;
+                }
+
+                @Override
+                public ClassLoader getClassLoader() {
+                    return null;
+                }
+
+                @Override
+                public void declareRoles(String... roleNames) {
+
+                }
+
+                @Override
+                public String getVirtualServerName() {
+                    return null;
+                }
+
+                @Override
+                public int getSessionTimeout() {
+                    return 0;
+                }
+
+                @Override
+                public void setSessionTimeout(int sessionTimeout) {
+
+                }
+
+                @Override
+                public String getRequestCharacterEncoding() {
+                    return null;
+                }
+
+                @Override
+                public void setRequestCharacterEncoding(String encoding) {
+
+                }
+
+                @Override
+                public String getResponseCharacterEncoding() {
+                    return null;
+                }
+
+                @Override
+                public void setResponseCharacterEncoding(String encoding) {
+
+                }
+            };
+        }
+    }
+
+    private static class PreinitializationFeatureContext implements FeatureContext {
+
+        private final AbstractBinder binder;
+
+        private PreinitializationFeatureContext(AbstractBinder binder) {
+            this.binder = binder;
+        }
+
+        @Override
+        public Configuration getConfiguration() {
+            return new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL);
+        }
+
+        @Override
+        public FeatureContext property(String name, Object value) {
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Class<?> componentClass) {
+            binder.bindAsContract(componentClass);
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Class<?> componentClass, int priority) {
+            binder.bindAsContract(componentClass).ranked(priority);
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Class<?> componentClass, Class<?>... contracts) {
+            final ClassBinding binding = binder.bind(componentClass);
+            if (contracts != null) {
+                for (Class<?> contract : contracts) {
+                    binding.to(contract);
+                }
+            }
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Class<?> componentClass, Map<Class<?>, Integer> contracts) {
+            for (Map.Entry<Class<?>, Integer> contract : contracts.entrySet()) {
+                final AbstractBinder abstractBinder = new AbstractBinder() {
+                    @Override
+                    protected void configure() {
+                    }
+                };
+                final ClassBinding binding = abstractBinder.bind(componentClass);
+                binding.to(contract.getKey()).ranked(contract.getValue());
+                binder.install(abstractBinder);
+            }
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Object component) {
+            if (AbstractBinder.class.isInstance(component)) {
+                binder.install((AbstractBinder) component);
+            } else {
+                binder.bind(component).to(component.getClass());
+            }
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Object component, int priority) {
+            binder.bind(component).to(component.getClass()).ranked(priority);
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Object component, Class<?>... contracts) {
+            Binding binding = binder.bind(component);
+            if (contracts != null) {
+                for (Class<?> contract : contracts) {
+                    binding.to(contract);
+                }
+            }
+            return this;
+        }
+
+        @Override
+        public FeatureContext register(Object component, Map<Class<?>, Integer> contracts) {
+            for (Map.Entry<Class<?>, Integer> contract : contracts.entrySet()) {
+                final AbstractBinder abstractBinder = new AbstractBinder() {
+                    @Override
+                    protected void configure() {
+                    }
+                };
+                final Binding binding = abstractBinder.bind(component);
+                binding.to(contract.getKey()).ranked(contract.getValue());
+                binder.install(abstractBinder);
+            }
+            return this;
+        }
+    }
+
+    @Override
+    public void register(RuntimeType runtimeType, AbstractBinder binder) {
+//        binder.install(new MessagingBinders.MessageBodyProviders(null, RuntimeType.SERVER),
+//                new MessagingBinders.HeaderDelegateProviders());
+//
+//        // Server Binder
+//        binder.install(new MappableExceptionWrapperInterceptor.Binder(),
+//                new MonitoringContainerListener.Binder());
+//        binder.bind(ChunkedResponseWriter.class).to(MessageBodyWriter.class).in(Singleton.class);
+//        binder.bind(JsonWithPaddingInterceptor.class).to(WriterInterceptor.class).in(Singleton.class);
+
+        if (runtimeType == RuntimeType.SERVER) {
+            // new ApplicationHandler(new ResourceConfig());
+
+            //grizzly
+            binder.bindFactory(GrizzlyRequestReferencingFactory.class).to(Request.class)
+                    .proxy(false).in(RequestScoped.class);
+            binder.bindFactory(ReferencingFactory.<Request>referenceFactory()).to(new GenericType<Ref<Request>>() {})
+                    .in(RequestScoped.class);
+
+            binder.bindFactory(GrizzlyResponseReferencingFactory.class).to(Response.class)
+                    .proxy(true).proxyForSameScope(false).in(RequestScoped.class);
+            binder.bindFactory(ReferencingFactory.<Response>referenceFactory()).to(new GenericType<Ref<Response>>() {})
+                    .in(RequestScoped.class);
+
+            // servlet
+            binder.bindFactory(HttpServletRequestReferencingFactory.class).to(HttpServletRequest.class)
+                    .proxy(true).proxyForSameScope(false).in(RequestScoped.class);
+
+            binder.bindFactory(ReferencingFactory.referenceFactory())
+                    .to(new GenericType<Ref<HttpServletRequest>>() {}).in(RequestScoped.class);
+
+            binder.bindFactory(HttpServletResponseReferencingFactory.class).to(HttpServletResponse.class)
+                    .proxy(true).proxyForSameScope(false).in(RequestScoped.class);
+            binder.bindFactory(ReferencingFactory.referenceFactory())
+                    .to(new GenericType<Ref<HttpServletResponse>>() {}).in(RequestScoped.class);
+
+            final WebConfig webConfig = new WebConfigInitializer();
+            final Map<String, Object> applicationProperties = Collections.EMPTY_MAP;
+
+            binder.bindFactory(() -> webConfig.getServletContext()).to(ServletContext.class).in(Singleton.class);
+            binder.bindFactory(() -> webConfig).to(WebConfig.class).in(Singleton.class);
+            binder.install(
+                    new ServiceFinderBinder<>(AsyncContextDelegateProvider.class, applicationProperties, RuntimeType.SERVER));
+            binder.install(
+                    new ServiceFinderBinder<>(FilterUrlMappingsProvider.class, applicationProperties, RuntimeType.SERVER));
+
+            final ServletConfig servletConfig = webConfig.getServletConfig();
+            binder.bindFactory(() -> servletConfig).to(ServletConfig.class).in(Singleton.class);
+
+            // WADL TODO put to a proper module
+            try {
+                new WadlFeature().configure(new PreinitializationFeatureContext(binder) {
+                    @Override
+                    public FeatureContext register(Class<?> componentClass) {
+                        if (WadlModelProcessor.class.isAssignableFrom(componentClass)) {
+                            super.register(WadlModelProcessor.OptionsHandler.class);
+                        }
+                        super.register(componentClass);
+                        return this;
+                    }
+                });
+            } catch (Exception e) {
+
+            }
+            try {
+                Class[] classes = OptionsMethodProcessor.class.getDeclaredClasses();
+                for (Class clz : classes) {
+                    binder.bindAsContract(clz);
+                }
+            } catch (Exception e) {
+
+            }
+        }
+
+//
+//        //ApplicationConfigurator
+//        binder.bind(new InitializableInstanceBinding((Application) null).to(Application.class));
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/WrappingInjectionManager.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/WrappingInjectionManager.java
new file mode 100644
index 0000000..a3bea1a
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/managed/WrappingInjectionManager.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import org.glassfish.jersey.internal.inject.Binder;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.ForeignDescriptor;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.ServiceHolder;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * Holder of an InjectionManager that is referenced by Beans created in bootstrap.
+ * The original bootstrap injection manager is replaced by the proper injection manager
+ * after the pre-initialization phase.
+ */
+class WrappingInjectionManager implements InjectionManager {
+
+    private InjectionManager injectionManager;
+
+    WrappingInjectionManager setInjectionManager(InjectionManager injectionManager) {
+        this.injectionManager = injectionManager;
+        return this;
+    }
+
+    @Override
+    public void completeRegistration() {
+        injectionManager.completeRegistration();
+    }
+
+    @Override
+    public void shutdown() {
+        injectionManager.shutdown();
+    }
+
+    @Override
+    public void register(Binding binding) {
+        injectionManager.register(binding);
+    }
+
+    @Override
+    public void register(Iterable<Binding> descriptors) {
+        injectionManager.register(descriptors);
+    }
+
+    @Override
+    public void register(Binder binder) {
+        injectionManager.register(binder);
+    }
+
+    @Override
+    public void register(Object provider) throws IllegalArgumentException {
+        injectionManager.register(provider);
+    }
+
+    @Override
+    public boolean isRegistrable(Class<?> clazz) {
+        return injectionManager.isRegistrable(clazz);
+    }
+
+    @Override
+    public <T> T create(Class<T> createMe) {
+        return injectionManager.create(createMe);
+    }
+
+    @Override
+    public <T> T createAndInitialize(Class<T> createMe) {
+        return injectionManager.createAndInitialize(createMe);
+    }
+
+    @Override
+    public <T> List<ServiceHolder<T>> getAllServiceHolders(Class<T> contractOrImpl, Annotation... qualifiers) {
+        return injectionManager.getAllServiceHolders(contractOrImpl, qualifiers);
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl, Annotation... qualifiers) {
+        return injectionManager.getInstance(contractOrImpl, qualifiers);
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl, String classAnalyzer) {
+        return injectionManager.getInstance(contractOrImpl, classAnalyzer);
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl) {
+        return injectionManager.getInstance(contractOrImpl);
+    }
+
+    @Override
+    public <T> T getInstance(Type contractOrImpl) {
+        return injectionManager.getInstance(contractOrImpl);
+    }
+
+    @Override
+    public Object getInstance(ForeignDescriptor foreignDescriptor) {
+        return injectionManager.getInstance(foreignDescriptor);
+    }
+
+    @Override
+    public ForeignDescriptor createForeignDescriptor(Binding binding) {
+        return injectionManager.createForeignDescriptor(binding);
+    }
+
+    @Override
+    public <T> List<T> getAllInstances(Type contractOrImpl) {
+        return injectionManager.getAllInstances(contractOrImpl);
+    }
+
+    @Override
+    public void inject(Object injectMe) {
+        injectionManager.inject(injectMe);
+    }
+
+    @Override
+    public void inject(Object injectMe, String classAnalyzer) {
+        injectionManager.inject(injectMe, classAnalyzer);
+    }
+
+    @Override
+    public void preDestroy(Object preDestroyMe) {
+        injectionManager.preDestroy(preDestroyMe);
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/CdiRequestContext.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/CdiRequestContext.java
new file mode 100644
index 0000000..64b8ebc
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/CdiRequestContext.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.scope;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.jersey.internal.util.ExtendedLogger;
+import org.glassfish.jersey.internal.util.LazyUid;
+import org.glassfish.jersey.process.internal.RequestContext;
+
+/**
+ * Implementation of the request context.
+ */
+public final class CdiRequestContext implements RequestContext {
+
+    private static final ExtendedLogger logger =
+            new ExtendedLogger(Logger.getLogger(CdiRequestContext.class.getName()), Level.FINEST);
+
+    /*
+     * Scope instance UUID.
+     *
+     * For performance reasons, it's only generated if toString() method is invoked,
+     * e.g. as part of some low-level logging.
+     */
+    private final LazyUid id = new LazyUid();
+
+    /**
+     * Holds the number of snapshots of this scope.
+     */
+    private final AtomicInteger referenceCounter;
+
+    /**
+     * A map of injectable instances in this scope.
+     */
+    private final Map<String, Object> store;
+
+    CdiRequestContext() {
+        this.store = new HashMap<>();
+        this.referenceCounter = new AtomicInteger(1);
+    }
+
+    Map<String, Object> getStore() {
+        return store;
+    }
+
+    /**
+     * Get a "new" reference of the scope instance. This will increase
+     * the internal reference counter which prevents the scope instance
+     * to be destroyed until a {@link #release()} method is explicitly
+     * called (once per each {@code getReference()} method call).
+     *
+     * @return referenced scope instance.
+     */
+    @Override
+    public RequestContext getReference() {
+        // TODO: replace counter with a phantom reference + reference queue-based solution
+        referenceCounter.incrementAndGet();
+        return this;
+    }
+
+    /**
+     * Release a single reference to the current request scope instance.
+     * <p>
+     * Once all instance references are released, the instance will be recycled.
+     */
+    @Override
+    public void release() {
+        if (referenceCounter.decrementAndGet() < 1) {
+            try {
+                store.clear();
+            } finally {
+                logger.debugLog("Released scope instance {0}", this);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Instance{"
+                + "id=" + id
+                + ", referenceCounter=" + referenceCounter
+                + ", store size=" + store.size()
+                + '}';
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/CdiRequestScope.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/CdiRequestScope.java
new file mode 100644
index 0000000..64d2a99
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/CdiRequestScope.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.scope;
+
+import javax.inject.Inject;
+
+import org.glassfish.jersey.process.internal.RequestContext;
+import org.glassfish.jersey.process.internal.RequestScope;
+
+import org.jboss.weld.context.bound.BoundRequestContext;
+
+import java.util.concurrent.Callable;
+
+/**
+ * CDI Request scope implementation using Weld-specific {@link BoundRequestContext} which allows pass on storage for
+ * request-scoped objects.
+ */
+public class CdiRequestScope extends RequestScope {
+
+    @Inject
+    private BoundRequestContext requestContextController;
+
+    @Override
+    public RequestContext createContext() {
+        return new CdiRequestContext();
+    }
+
+    @Override
+    protected void activate(RequestContext context, RequestContext oldContext) {
+        super.activate(context, oldContext);
+
+        if (oldContext != null) {
+            CdiRequestContext oldRequestContext = (CdiRequestContext) oldContext;
+            requestContextController.deactivate();
+            requestContextController.dissociate(oldRequestContext.getStore());
+        }
+
+        CdiRequestContext cdiRequestContext = (CdiRequestContext) context;
+        requestContextController.associate(cdiRequestContext.getStore());
+        requestContextController.activate();
+    }
+
+    @Override
+    protected void resume(RequestContext context) {
+        super.resume(context);
+
+        if (context != null) {
+            CdiRequestContext cdiRequestContext = (CdiRequestContext) context;
+            requestContextController.associate(cdiRequestContext.getStore());
+            requestContextController.activate();
+        }
+    }
+
+    @Override
+    protected void release(RequestContext context) {
+        super.release(context);
+
+        CdiRequestContext cdiRequestContext = (CdiRequestContext) context;
+        requestContextController.invalidate();
+        requestContextController.deactivate();
+        requestContextController.dissociate(cdiRequestContext.getStore());
+    }
+
+    @Override
+    protected void suspend(RequestContext context) {
+        if (context != null) {
+            CdiRequestContext cdiRequestContext = (CdiRequestContext) context;
+            requestContextController.deactivate();
+            requestContextController.dissociate(cdiRequestContext.getStore());
+        }
+    }
+
+    @Override
+    public <T> T runInScope(Callable<T> task) throws Exception {
+            return super.runInScope(task);
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/RequestScopeBean.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/RequestScopeBean.java
new file mode 100644
index 0000000..6770060
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/scope/RequestScopeBean.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.scope;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Singleton;
+
+import org.glassfish.jersey.process.internal.RequestScope;
+
+/**
+ * CDI Class Bean represents {@link CdiRequestScope}.
+ *
+ * @author Petr Bouda
+ */
+public class RequestScopeBean implements Bean<CdiRequestScope> {
+
+    private final InjectionTarget<CdiRequestScope> injectionTarget;
+
+    /**
+     * Creates a new Jersey-specific {@link javax.enterprise.inject.spi.Bean} instance.
+     */
+    public RequestScopeBean(BeanManager beanManager) {
+        AnnotatedType<CdiRequestScope> annotatedType = beanManager.createAnnotatedType(CdiRequestScope.class);
+        this.injectionTarget = beanManager.createInjectionTarget(annotatedType);
+    }
+
+    @Override
+    public boolean isNullable() {
+        return false;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public CdiRequestScope create(CreationalContext<CdiRequestScope> context) {
+        CdiRequestScope instance = injectionTarget.produce(context);
+        injectionTarget.inject(instance, context);
+        injectionTarget.postConstruct(instance);
+        return instance;
+    }
+
+    @Override
+    public void destroy(CdiRequestScope instance, CreationalContext<CdiRequestScope> context) {
+        injectionTarget.preDestroy(instance);
+        injectionTarget.dispose(instance);
+        context.release();
+    }
+
+    @Override
+    public Set<Type> getTypes() {
+        return Collections.singleton(RequestScope.class);
+    }
+
+    @Override
+    public Set<InjectionPoint> getInjectionPoints() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<Annotation> getQualifiers() {
+        Set<Annotation> qualifiers = new HashSet<>();
+        qualifiers.add(new AnnotationLiteral<Default>() {});
+        qualifiers.add(new AnnotationLiteral<Any>() {});
+        return qualifiers;
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return Singleton.class;
+    }
+
+    @Override
+    public String getName() {
+        return CdiRequestScope.class.getName();
+    }
+
+    @Override
+    public Set<Class<? extends Annotation>> getStereotypes() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public boolean isAlternative() {
+        return false;
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        return CdiRequestScope.class;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/type/GenericArrayTypeImpl.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/type/GenericArrayTypeImpl.java
new file mode 100644
index 0000000..d093e26
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/type/GenericArrayTypeImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.type;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Type;
+
+/**
+ * An implementation of GenericArrayType for those times we need to create this on the fly.
+ *
+ * @author John Wells (john.wells at oracle.com)
+ */
+public class GenericArrayTypeImpl implements GenericArrayType {
+    private final Type genericComponentType;
+
+    /**
+     * Creates the GenericArrayType with the given array type
+     *
+     * @param gct the non-null type for this GenericArrayType
+     */
+    public GenericArrayTypeImpl(Type gct) {
+        genericComponentType = gct;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.reflect.GenericArrayType#getGenericComponentType()
+     */
+    @Override
+    public Type getGenericComponentType() {
+        return genericComponentType;
+    }
+
+    @Override
+    public int hashCode() {
+        return genericComponentType.hashCode();
+    }
+
+    /**
+     * Returns true if a is equals to b, or both
+     * and and b are null.  Is safe even if
+     * a or b is null.  If a or b is null but
+     * the other is not null, this returns false
+     *
+     * @param a A possibly null object to compare
+     * @param b A possibly null object to compare
+     * @return true if equal, false if not
+     */
+    private static boolean safeEquals(Object a, Object b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == null) {
+            return false;
+        }
+        if (b == null) {
+            return false;
+        }
+
+        return a.equals(b);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null) {
+            return false;
+        }
+        if (!(o instanceof GenericArrayType)) {
+            return false;
+        }
+
+        GenericArrayType other = (GenericArrayType) o;
+
+        return safeEquals(genericComponentType, other.getGenericComponentType());
+    }
+
+    public String toString() {
+        return "GenericArrayTypeImpl(" + genericComponentType + ")";
+    }
+
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/type/ParameterizedTypeImpl.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/type/ParameterizedTypeImpl.java
new file mode 100644
index 0000000..c358aa2
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/internal/type/ParameterizedTypeImpl.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.type;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+/**
+ * Simple implementation of {@link ParameterizedType}.
+ * <p>
+ * John Wells (john.wells at oracle.com)
+ */
+public class ParameterizedTypeImpl implements ParameterizedType {
+
+    private final Type rawType;
+    private final Type actualTypeArguments[];
+
+    /**
+     * A new parameterized type.
+     *
+     * @param rawType             The raw type of this type.
+     * @param actualTypeArguments The actual type arguments.
+     */
+    public ParameterizedTypeImpl(Type rawType, Type... actualTypeArguments) {
+        this.rawType = rawType;
+        this.actualTypeArguments = actualTypeArguments;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.reflect.ParameterizedType#getActualTypeArguments()
+     */
+    @Override
+    public Type[] getActualTypeArguments() {
+        return actualTypeArguments;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.reflect.ParameterizedType#getRawType()
+     */
+    @Override
+    public Type getRawType() {
+        return rawType;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.reflect.ParameterizedType#getOwnerType()
+     * This is only used for top level types
+     */
+    @Override
+    public Type getOwnerType() {
+        return null;
+    }
+
+    @Override
+    public int hashCode() {
+        int retVal = Arrays.hashCode(actualTypeArguments);
+        if (rawType == null) {
+            return retVal;
+        }
+        return retVal ^ rawType.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null) {
+            return false;
+        }
+        if (!(o instanceof ParameterizedType)) {
+            return false;
+        }
+
+        ParameterizedType other = (ParameterizedType) o;
+
+        if (!rawType.equals(other.getRawType())) {
+            return false;
+        }
+
+        Type otherActuals[] = other.getActualTypeArguments();
+
+        if (otherActuals.length != actualTypeArguments.length) {
+            return false;
+        }
+
+        for (int lcv = 0; lcv < otherActuals.length; lcv++) {
+            if (!actualTypeArguments[lcv].equals(otherActuals[lcv])) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/managed/CdiInjectionManagerFactory.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/managed/CdiInjectionManagerFactory.java
new file mode 100644
index 0000000..8ea746f
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/managed/CdiInjectionManagerFactory.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.managed;
+
+import javax.annotation.Priority;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.inject.weld.internal.injector.JerseyClientCreationalContext;
+import org.glassfish.jersey.inject.weld.internal.managed.CdiInjectionManagerFactoryBase;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InjectionManagerFactory;
+import org.glassfish.jersey.server.ApplicationHandler;
+
+/**
+ * SPI implementation of {@link InjectionManagerFactory} which provides a new instance of CDI {@link InjectionManager}.
+ */
+@Priority(20)
+public class CdiInjectionManagerFactory extends CdiInjectionManagerFactoryBase implements InjectionManagerFactory {
+
+    @Override
+    // TODO deprecate this in favor of #create(Object parent, RuntimeType runtimeType)
+    public InjectionManager create(Object parent) {
+        return create(parent, getRuntimeType());
+    }
+
+    /**
+     * Create injectionManager for {@link RuntimeType#CLIENT or get the existing injection manager for the server}
+     * @param parent Parent injection manager. Not used in this InjectionManagerFactory.
+     * @param runtimeType {@link RuntimeType} to get or create the proper injection manager.
+     * @return The required injection manager instance.
+     */
+    public InjectionManager create(Object parent, RuntimeType runtimeType) {
+        return getInjectionManager(runtimeType);
+    }
+
+    /**
+     * Get the client side InjectionManager stored in the {@link CreationalContext} or the server side InjectionManager.
+     * @param creationalContext {@link CreationalContext} subclass which may hold InjectionManager for the client
+     * @return existing client side injection or server side injection manager.
+     */
+    public static InjectionManager getInjectionManager(CreationalContext<?> creationalContext) {
+        if (JerseyClientCreationalContext.class.isInstance(creationalContext)) {
+            return ((JerseyClientCreationalContext) creationalContext).getInjectionManager();
+        } else {
+            return getInjectionManager(RuntimeType.SERVER);
+        }
+    }
+
+    // TODO refactor to call InjectionManagerFactory#create(Object, RuntimeType);
+    private static RuntimeType getRuntimeType() {
+        Exception e = new RuntimeException();
+        for (StackTraceElement element : e.getStackTrace()) {
+            if (element.getClassName().equals(ClientConfig.class.getName())) {
+                return RuntimeType.CLIENT;
+            }
+            if (element.getClassName().equals(ApplicationHandler.class.getName())) {
+                return RuntimeType.SERVER;
+            }
+        }
+        return RuntimeType.SERVER;
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/spi/BootstrapPreinitialization.java b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/spi/BootstrapPreinitialization.java
new file mode 100644
index 0000000..0c90da5
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/java/org/glassfish/jersey/inject/weld/spi/BootstrapPreinitialization.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.spi;
+
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.Beta;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+
+/**
+ * <p>
+ *     The entry point for pre-initialize Jersey during bootstrap. Register the beans that are not recognized by the injection
+ *     framework to be injected in runtime. Register beans for the specific runtime type into the {@link AbstractBinder}.
+ * </p>
+ */
+@Beta
+public interface BootstrapPreinitialization {
+    /**
+     * Manually register beans that are not automatically recognised by the injection framework.
+     * @param runtimeType
+     * @param binder
+     */
+    void register(RuntimeType runtimeType, AbstractBinder binder);
+}
diff --git a/incubator/cdi-inject-weld/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/incubator/cdi-inject-weld/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100644
index 0000000..729ccf2
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1,17 @@
+
+# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+org.glassfish.jersey.inject.weld.internal.managed.BinderRegisterExtension
\ No newline at end of file
diff --git a/incubator/cdi-inject-weld/src/main/resources/META-INF/services/org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization b/incubator/cdi-inject-weld/src/main/resources/META-INF/services/org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization
new file mode 100644
index 0000000..9e2e9ad
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/resources/META-INF/services/org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+org.glassfish.jersey.inject.weld.internal.managed.ClientBootstrapPreinitialization
+org.glassfish.jersey.inject.weld.internal.managed.ServerBootstrapPreinitialization
\ No newline at end of file
diff --git a/incubator/cdi-inject-weld/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory b/incubator/cdi-inject-weld/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
new file mode 100644
index 0000000..71491fa
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+org.glassfish.jersey.inject.weld.managed.CdiInjectionManagerFactory
diff --git a/incubator/cdi-inject-weld/src/main/resources/org/glassfish/jersey/inject/weld/internal/managed/localization.properties b/incubator/cdi-inject-weld/src/main/resources/org/glassfish/jersey/inject/weld/internal/managed/localization.properties
new file mode 100644
index 0000000..8716ee6
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/main/resources/org/glassfish/jersey/inject/weld/internal/managed/localization.properties
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+# {0} - full classname
+cdi2.provider.not.registrable=Provider registered to CdiInjectionManager cannot be process because of incompatible type: {0}.
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzerTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzerTest.java
new file mode 100644
index 0000000..eebc20d
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/CachedConstructorAnalyzerTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.enterprise.inject.InjectionException;
+import javax.ws.rs.MatrixParam;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Context;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link CachedConstructorAnalyzer}.
+ */
+public class CachedConstructorAnalyzerTest {
+
+    private static final Collection<Class<? extends Annotation>> ANNOTATIONS =
+            Arrays.asList(Context.class, PathParam.class);
+
+    @Test
+    public void testDefaultConstructor() {
+        CachedConstructorAnalyzer<DefaultConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(DefaultConstructor.class, ANNOTATIONS);
+
+        assertEquals(0, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testNoArgsConstructor() {
+        CachedConstructorAnalyzer<NoArgsConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(NoArgsConstructor.class, ANNOTATIONS);
+
+        assertEquals(0, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testSingleAnnotatedConstructor() {
+        CachedConstructorAnalyzer<SingleAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(SingleAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(1, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testSingleMultiAnnotatedConstructor() {
+        CachedConstructorAnalyzer<SingleMultiAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(SingleMultiAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(2, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testLargestAnnotatedConstructor() {
+        CachedConstructorAnalyzer<LargestAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(LargestAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(3, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testContainsSmallerNonAnnotatedConstructor() {
+        CachedConstructorAnalyzer<ContainsSmallerNonAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(ContainsSmallerNonAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(2, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testContainsLargerNonAnnotatedConstructor() {
+        CachedConstructorAnalyzer<ContainsLargerNonAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(ContainsLargerNonAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(1, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testSameNonAnnotatedConstructor() {
+        CachedConstructorAnalyzer<SameNonAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(SameNonAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(1, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testBothAnnotatedConstructor() {
+        CachedConstructorAnalyzer<BothAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(BothAnnotatedConstructor.class, ANNOTATIONS);
+
+        Constructor<BothAnnotatedConstructor> constructor = analyzer.getConstructor();
+        assertEquals(1, constructor.getParameterCount());
+        assertEquals(Integer.class, constructor.getParameterTypes()[0]);
+    }
+
+    @Test
+    public void testOneNonAnnotatedConstructor() {
+        CachedConstructorAnalyzer<OneNonAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(OneNonAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(1, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test
+    public void testMultiAnnotatedConstructor() {
+        CachedConstructorAnalyzer<MultiAnnotatedConstructor> analyzer =
+                new CachedConstructorAnalyzer<>(MultiAnnotatedConstructor.class, ANNOTATIONS);
+
+        assertEquals(2, analyzer.getConstructor().getParameterCount());
+    }
+
+    @Test(expected = InjectionException.class)
+    public void testUnknownAnnotatedConstructor() {
+        new CachedConstructorAnalyzer<>(UnknownAnnotatedConstructor.class, ANNOTATIONS).getConstructor();
+    }
+
+    @Test(expected = InjectionException.class)
+    public void testSingleNonAnnotatedConstructor() {
+        new CachedConstructorAnalyzer<>(SingleNonAnnotatedConstructor.class, ANNOTATIONS).getConstructor();
+    }
+
+    public static class DefaultConstructor {
+    }
+
+    public static class NoArgsConstructor {
+        public NoArgsConstructor() {
+        }
+    }
+
+    public static class SingleNonAnnotatedConstructor {
+        public SingleNonAnnotatedConstructor(String str) {
+        }
+    }
+
+    public static class SingleAnnotatedConstructor {
+        public SingleAnnotatedConstructor(@Context String str) {
+        }
+    }
+
+    public static class SingleMultiAnnotatedConstructor {
+        public SingleMultiAnnotatedConstructor(@Context String str, @PathParam("name") String name) {
+        }
+    }
+
+    public static class LargestAnnotatedConstructor {
+        public LargestAnnotatedConstructor(@Context String str, @PathParam("name") String name, @Context String str2) {
+        }
+
+        public LargestAnnotatedConstructor(@Context String str) {
+        }
+
+        public LargestAnnotatedConstructor(@Context String str, @PathParam("name") String name) {
+        }
+    }
+
+    public static class ContainsSmallerNonAnnotatedConstructor {
+        public ContainsSmallerNonAnnotatedConstructor(String str) {
+        }
+
+        public ContainsSmallerNonAnnotatedConstructor(@Context String str, @PathParam("name") String name) {
+        }
+    }
+
+    public static class ContainsLargerNonAnnotatedConstructor {
+        public ContainsLargerNonAnnotatedConstructor(@Context String str) {
+        }
+
+        public ContainsLargerNonAnnotatedConstructor(String str, String name) {
+        }
+    }
+
+    public static class SameNonAnnotatedConstructor {
+        public SameNonAnnotatedConstructor(@Context String str) {
+        }
+
+        public SameNonAnnotatedConstructor(Integer name) {
+        }
+    }
+
+    public static class BothAnnotatedConstructor {
+        public BothAnnotatedConstructor(@Context String str) {
+        }
+
+        public BothAnnotatedConstructor(@Context Integer name) {
+        }
+    }
+
+    public static class OneNonAnnotatedConstructor {
+        public OneNonAnnotatedConstructor(@Context String str) {
+        }
+
+        public OneNonAnnotatedConstructor(@Context Integer name, String str) {
+        }
+    }
+
+    public static class MultiAnnotatedConstructor {
+        public MultiAnnotatedConstructor(@Context Integer name, @PathParam("str") @Context String str) {
+        }
+    }
+
+    public static class UnknownAnnotatedConstructor {
+        public UnknownAnnotatedConstructor(@Context Integer name, @MatrixParam("matrix") String str) {
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java
new file mode 100644
index 0000000..76fcd88
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.injector;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Singleton;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.ext.Providers;
+
+import org.glassfish.jersey.internal.JaxrsProviders;
+import org.glassfish.jersey.internal.inject.Injectee;
+import org.glassfish.jersey.internal.inject.InjecteeImpl;
+import org.glassfish.jersey.internal.inject.InjectionResolver;
+
+import org.junit.Test;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests Jersey Proxy Resolver.
+ */
+public class JerseyProxyResolverTest {
+
+    private static Field[] FIELDS = StubForFields.class.getDeclaredFields();
+
+    @Test
+    public void testSignletonIsProxiable() {
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setInjecteeClass(TestSingleton.class);
+        injectee.setParentClassScope(Singleton.class);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        assertTrue(resolver.isProxiable(injectee));
+    }
+
+    @Test
+    public void testApplicationScopeIsProxiable() {
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setInjecteeClass(TestApplicationScope.class);
+        injectee.setParentClassScope(ApplicationScoped.class);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        assertTrue(resolver.isProxiable(injectee));
+    }
+
+    @Test
+    public void testRequestScopeFromNonAnnotatedIsNotProxiable() {
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setInjecteeClass(TestNonAnnotatedRequestScope.class);
+        injectee.setParentClassScope(RequestScoped.class);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        assertFalse(resolver.isProxiable(injectee));
+    }
+
+    @Test
+    public void testRequestScopeIsNotProxiable() {
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setInjecteeClass(TestRequestScope.class);
+        injectee.setParentClassScope(RequestScoped.class);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        assertFalse(resolver.isProxiable(injectee));
+    }
+
+    @Test
+    public void testApplicationIsNotProxiable() {
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setRequiredType(Application.class);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        assertFalse(resolver.isProxiable(injectee));
+    }
+
+    @Test
+    public void testProxyCreated() {
+        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders());
+        InjecteeImpl injectee = new InjecteeImpl();
+        injectee.setRequiredType(Providers.class);
+        injectee.setParent(FIELDS[0]);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        Object proxy = resolver.proxy(injectee, injectionResolver);
+        assertTrue(proxy.getClass().getName().contains("Proxy"));
+    }
+
+    @Test
+    public void testProxyCached() {
+        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders());
+        InjecteeImpl injectee1 = new InjecteeImpl();
+        injectee1.setRequiredType(Providers.class);
+        injectee1.setParent(FIELDS[0]);
+
+        InjecteeImpl injectee2 = new InjecteeImpl();
+        injectee2.setRequiredType(Providers.class);
+        injectee2.setParent(FIELDS[1]);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        Object proxy1 = resolver.proxy(injectee1, injectionResolver);
+        Object proxy2 = resolver.proxy(injectee2, injectionResolver);
+        assertSame(proxy1.getClass(), proxy2.getClass());
+    }
+
+    @Test
+    public void testProxyCacheNotMismatched() {
+        MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders());
+        InjecteeImpl injectee1 = new InjecteeImpl();
+        injectee1.setRequiredType(Providers.class);
+        injectee1.setParent(FIELDS[0]);
+
+        MyInjectionResolver injectionResolver2 = new MyInjectionResolver(new ArrayList<>());
+        InjecteeImpl injectee2 = new InjecteeImpl();
+        injectee2.setRequiredType(List.class);
+        injectee2.setParent(FIELDS[1]);
+
+        JerseyProxyResolver resolver = new JerseyProxyResolver();
+        Object proxy1 = resolver.proxy(injectee1, injectionResolver1);
+        Object proxy2 = resolver.proxy(injectee2, injectionResolver2);
+        assertNotSame(proxy1.getClass(), proxy2.getClass());
+    }
+
+    private static class StubForFields {
+        private Object field1;
+        private Object field2;
+    }
+
+    private static class MyInjectionResolver implements InjectionResolver {
+
+        private final Object instance;
+
+        private MyInjectionResolver(Object instance) {
+            this.instance = instance;
+        }
+
+        @Override
+        public Object resolve(Injectee injectee) {
+            return instance;
+        }
+
+        @Override
+        public boolean isConstructorParameterIndicator() {
+            return true;
+        }
+
+        @Override
+        public boolean isMethodParameterIndicator() {
+            return false;
+        }
+
+        @Override
+        public Class getAnnotation() {
+            return Context.class;
+        }
+    }
+
+    private static class TestNonAnnotatedRequestScope {
+    }
+
+    @RequestScoped
+    private static class TestRequestScope {
+    }
+
+    @Singleton
+    private static class TestSingleton {
+    }
+
+    @ApplicationScoped
+    private static class TestApplicationScope {
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/BindingTestHelper.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/BindingTestHelper.java
new file mode 100644
index 0000000..f6184eb
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/BindingTestHelper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.Injections;
+
+import java.util.function.Consumer;
+
+/**
+ * Helper class to minimize the code in tested classes.
+ *
+ * @author Petr Bouda
+ */
+class BindingTestHelper {
+
+    /**
+     * Accepts the provided consumer to created and register the binder.
+     *
+     * @param injectionManager injection manager which accepts the consumer.
+     * @param bindConsumer     consumer to populate a binder.
+     */
+    static void bind(InjectionManager injectionManager, Consumer<AbstractBinder> bindConsumer) {
+        AbstractBinder binder = new AbstractBinder() {
+            @Override
+            protected void configure() {
+                bindConsumer.accept(this);
+            }
+        };
+
+        injectionManager.register(binder);
+        // injectionManager.completeRegistration();
+    }
+
+    /**
+     * Creates a new {@link InjectionManager}.
+     *
+     * @return newly created {@code InjectionManager}.
+     */
+    static InjectionManager createInjectionManager() {
+        return Injections.createInjectionManager();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ClientInstanceInjectionTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ClientInstanceInjectionTest.java
new file mode 100644
index 0000000..37ec79f
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ClientInstanceInjectionTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Vetoed;
+import javax.inject.Inject;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.managed.CdiInjectionManagerFactory;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+public class ClientInstanceInjectionTest extends TestParent {
+
+    @Test
+    public void testInject() {
+        InjectionManager clientInjectionManager1 = new CdiInjectionManagerFactory().create(null, RuntimeType.CLIENT);
+        InjectionManager clientInjectionManager2 = new CdiInjectionManagerFactory().create(null, RuntimeType.CLIENT);
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bind(new StringInjectable(5)).to(Injectable.class);
+        });
+
+        BindingTestHelper.bind(clientInjectionManager1, binder -> {
+            binder.bind(new StringInjectable(10)).to(Injectable.class);
+        });
+
+        BindingTestHelper.bind(clientInjectionManager2, binder -> {
+            binder.bind(new StringInjectable(15)).to(Injectable.class);
+        });
+
+        InjectedBean bean = injectionManager.getInstance(InjectedBean.class);
+        Assert.assertNotNull(bean);
+        Assert.assertEquals("6", bean.get());
+
+        InjectedBean bean1 = clientInjectionManager1.getInstance(InjectedBean.class);
+        Assert.assertNotNull(bean1);
+        Assert.assertEquals("11", bean1.get());
+
+        InjectedBean bean2 = clientInjectionManager2.getInstance(InjectedBean.class);
+        Assert.assertNotNull(bean2);
+        Assert.assertEquals("16", bean2.get());
+
+        injectionManager.shutdown();
+        clientInjectionManager1.shutdown();
+        clientInjectionManager2.shutdown();
+    }
+
+    @Vetoed
+    static class InjectedBean {
+        @Inject
+        private Injectable injectable;
+
+        public String get() {
+            return injectable.get();
+        }
+    }
+
+    static class StringInjectable extends AbstractStringInjectable implements Injectable {
+        StringInjectable(int i) {
+            super(i);
+        }
+    }
+
+    static interface Injectable {
+        String get();
+    }
+
+
+    @Test
+    public void testSupplierInject() {
+        InjectionManager clientInjectionManager1 = new CdiInjectionManagerFactory().create(null, RuntimeType.CLIENT);
+        InjectionManager clientInjectionManager2 = new CdiInjectionManagerFactory().create(null, RuntimeType.CLIENT);
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(new StringInjectableSupplier2(5)).to(Injectable2.class);
+        });
+
+        BindingTestHelper.bind(clientInjectionManager1, binder -> {
+            binder.bindFactory(new StringInjectableSupplier2(10)).to(Injectable2.class);
+        });
+
+        BindingTestHelper.bind(clientInjectionManager2, binder -> {
+            binder.bindFactory(new StringInjectableSupplier2(15)).to(Injectable2.class);
+        });
+
+        InjectedSupplierBean bean = injectionManager.getInstance(InjectedSupplierBean.class);
+        Assert.assertNotNull(bean);
+        Assert.assertEquals("6", bean.get());
+
+        InjectedSupplierBean bean1 = clientInjectionManager1.getInstance(InjectedSupplierBean.class);
+        Assert.assertNotNull(bean1);
+        Assert.assertEquals("11", bean1.get());
+
+        InjectedSupplierBean bean2 = clientInjectionManager2.getInstance(InjectedSupplierBean.class);
+        Assert.assertNotNull(bean2);
+        Assert.assertEquals("16", bean2.get());
+    }
+
+    @Dependent
+    static class InjectedSupplierBean {
+        @Inject
+        private Supplier<Injectable2> injectable;
+
+        public String get() {
+            return injectable.get().get();
+        }
+    }
+
+    static class StringInjectableSupplier2 implements Supplier<Injectable2> {
+        private final int i;
+        StringInjectableSupplier2(int i) {
+            this.i = i;
+        }
+
+        @Override
+        public Injectable2 get() {
+            return new StringInjectable2(i);
+        }
+    }
+
+    private static class StringInjectable2 extends AbstractStringInjectable implements Injectable2 {
+
+        StringInjectable2(int value) {
+            super(value);
+        }
+    }
+
+    static interface Injectable2 {
+        String get();
+    }
+
+    abstract static class AbstractStringInjectable {
+        protected AtomicInteger atomicInteger = new AtomicInteger(0);
+
+        AbstractStringInjectable(int value) {
+            atomicInteger.set(value);
+        }
+
+        public String get() {
+            return String.valueOf(atomicInteger.incrementAndGet());
+        }
+    }
+
+    @Test
+    public void testSupplierClassBeanOnClientAndServer() {
+        InjectionManager clientInjectionManager = new CdiInjectionManagerFactory().create(null, RuntimeType.CLIENT);
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(InjectableClientServerSupplierServer.class).to(InjectableClientServer.class);
+        });
+
+        BindingTestHelper.bind(clientInjectionManager, binder -> {
+            binder.bindFactory(InjectableClientServerSupplierClient.class).to(InjectableClientServer.class);
+        });
+
+        InjectedClientServerSupplierBean beanServer = injectionManager.getInstance(InjectedClientServerSupplierBean.class);
+        Assert.assertNotNull(beanServer);
+        Assert.assertEquals("SERVER", beanServer.get());
+
+        InjectedClientServerSupplierBean beanClient = clientInjectionManager.getInstance(InjectedClientServerSupplierBean.class);
+        Assert.assertNotNull(beanClient);
+        Assert.assertEquals("CLIENT", beanClient.get());
+    }
+
+    @Dependent
+    static class InjectedClientServerSupplierBean {
+        @Inject
+        private Supplier<InjectableClientServer> injectable;
+
+        public String get() {
+            return injectable.get().get();
+        }
+    }
+
+    static class InjectableClientServerSupplierServer implements Supplier<InjectableClientServer> {
+        @Override
+        public InjectableClientServer get() {
+            return new InjectableClientServerServer();
+        }
+    }
+
+    static class InjectableClientServerSupplierClient implements Supplier<InjectableClientServer> {
+        @Override
+        public InjectableClientServer get() {
+            return new InjectableClientServerClient();
+        }
+    }
+
+    private static class InjectableClientServerServer implements InjectableClientServer {
+
+        @Override
+        public String get() {
+            return "SERVER";
+        }
+    }
+
+    private static class InjectableClientServerClient implements InjectableClientServer {
+        @Override
+        public String get() {
+            return "CLIENT";
+        }
+    }
+
+    static interface InjectableClientServer {
+        String get();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Conversation.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Conversation.java
new file mode 100644
index 0000000..d10dc81
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Conversation.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Vetoed;
+import javax.inject.Inject;
+
+/**
+ * @author Petr Bouda
+ */
+@Vetoed
+class Conversation {
+
+    @Inject
+    Greeting greeting;
+
+    @Inject
+    Supplier<Greeting> greetingSupplier;
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechConversation.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechConversation.java
new file mode 100644
index 0000000..b3a8594
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechConversation.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Vetoed;
+import javax.inject.Inject;
+
+/**
+ * @author Petr Bouda
+ */
+@Vetoed
+class CzechConversation {
+
+    @Inject
+    CzechGreeting greeting;
+
+    @Inject
+    Supplier<CzechGreeting> greetingSupplier;
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechGreeting.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechGreeting.java
new file mode 100644
index 0000000..a60f546
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/CzechGreeting.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.inject.Vetoed;
+
+/**
+ * @author Petr Bouda
+ */
+@Vetoed
+public class CzechGreeting implements Greeting, Printable {
+
+    static final String GREETING = "Ahoj";
+
+    @Override
+    public String getGreeting() {
+        return GREETING + "#" + Thread.currentThread().getName();
+    }
+
+    @Override
+    public void print() {
+        System.out.println(GREETING);
+    }
+
+    @Override
+    public String toString() {
+        return "CzechGreeting";
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/DisposableSupplierTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/DisposableSupplierTest.java
new file mode 100644
index 0000000..4ba137b
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/DisposableSupplierTest.java
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.lang.reflect.Type;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Vetoed;
+import javax.inject.Inject;
+import javax.ws.rs.core.GenericType;
+
+import org.glassfish.jersey.inject.weld.internal.bean.BeanHelper;
+import org.glassfish.jersey.internal.inject.DisposableSupplier;
+import org.glassfish.jersey.process.internal.RequestScope;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Tests that {@link DisposableSupplier} is properly processed by {@link BeanHelper}.
+ *
+ * @author Petr Bouda
+ */
+@Vetoed
+public class DisposableSupplierTest extends TestParent {
+
+    private static final Type DISPOSABLE_SUPPLIER_CLASS_TYPE =
+            new GenericType<DisposableSupplier<StringForSupplierClass>>() {}.getType();
+    private static final Type DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE =
+            new GenericType<DisposableSupplier<StringForSupplierSingletonClass>>() {}.getType();
+    private static final Type DISPOSABLE_SUPPLIER_INSTANCE_TYPE =
+            new GenericType<DisposableSupplier<StringForSupplierInstance>>() {}.getType();
+    private static final Type PROXIABLE_DISPOSABLE_SUPPLIER_CLASS_TYPE =
+            new GenericType<DisposableSupplier<ProxiableHolderClass>>() {}.getType();
+
+    private static AtomicBoolean onlyOnceGuard = new AtomicBoolean(false);
+
+    @Before
+    public void bindInit() {
+        if (!onlyOnceGuard.getAndSet(true)) {
+            BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(new DisposableSupplierImpl())
+                    .to(StringForSupplierInstance.class));
+        }
+    }
+
+    @Test
+    public void testBindSingletonClassDisposableSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder ->  binder.bindFactory(DisposableSupplierImpl.class, Singleton.class)
+//                .to(StringForSupplierSingletonClass.class));
+
+        Object supplier = injectionManager.getInstance(new GenericType<Supplier<StringForSupplierSingletonClass>>() {}.getType());
+        Object disposableSupplier = injectionManager.getInstance(DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        assertNotNull(supplier);
+        assertNotNull(disposableSupplier);
+        assertSame(supplier, disposableSupplier);
+    }
+
+    @Test
+    public void testBindPerLookupClassDisposableSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(DisposableSupplierImpl.class)
+//                .to(StringForSupplierClass.class));
+
+        Object supplier = injectionManager.getInstance(new GenericType<Supplier<StringForSupplierClass>>() {}.getType());
+        Object disposableSupplier = injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        assertNotNull(supplier);
+        assertNotNull(disposableSupplier);
+        assertNotSame(supplier, disposableSupplier);
+    }
+
+    @Test
+    public void testBindInstanceDisposableSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(new DisposableSupplierImpl())
+//                .to(StringForSupplierInstance.class));
+
+        Object supplier = injectionManager.getInstance(new GenericType<Supplier<StringForSupplierInstance>>() {}.getType());
+        Object disposableSupplier = injectionManager.getInstance(DISPOSABLE_SUPPLIER_INSTANCE_TYPE);
+        assertNotNull(supplier);
+        assertNotNull(disposableSupplier);
+        assertSame(supplier, disposableSupplier);
+    }
+
+    @Test
+    public void testNotBindClassDisposableSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(SupplierGreeting.class).to(GreetingsClass.class));
+        assertNull(injectionManager.getInstance(new GenericType<DisposableSupplier<GreetingsClass>>() {}.getType()));
+    }
+
+    @Test
+    public void testNotBindInstanceDisposableSupplier() {
+//        BindingTestHelper.bind(injectionManager,
+//                binder -> binder.bindFactory(new SupplierGreeting()).to(GreetingsInstance.class));
+        assertNull(injectionManager.getInstance(new GenericType<DisposableSupplier<GreetingsInstance>>() {}.getType()));
+    }
+
+    @Test
+    public void testOnlyIncrementSingletonSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(DisposableSupplierImpl.class, Singleton.class)
+//                        .to(StringForSupplierSingletonClass.class));
+
+        Object instance1 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        assertEquals("1", ((DisposableSupplier<?>) instance1).get());
+        Object instance2 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        assertEquals("2", ((DisposableSupplier<?>) instance2).get());
+        Object instance3 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        assertEquals("3", ((DisposableSupplier<?>) instance3).get());
+        dispose(instance1, instance2, instance3);
+    }
+
+    @Test
+    public void testOnlyIncrementInstanceSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(new DisposableSupplierImpl())
+//                        .to(StringForSupplierInstance.class));
+
+        Object instance1 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_INSTANCE_TYPE);
+        assertEquals("1", ((DisposableSupplier<?>) instance1).get());
+        Object instance2 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_INSTANCE_TYPE);
+        assertEquals("2", ((DisposableSupplier<?>) instance2).get());
+        Object instance3 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_INSTANCE_TYPE);
+        assertEquals("3", ((DisposableSupplier<?>) instance3).get());
+        dispose(instance1, instance2, instance3);
+    }
+
+    @Test
+    public void testOnlyIncrementPerLookupSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(DisposableSupplierImpl.class)
+//                        .to(StringForSupplierClass.class));
+
+        Object instance1 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        assertEquals("1", ((DisposableSupplier<?>) instance1).get());
+        Object instance2 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        assertEquals("1", ((DisposableSupplier<?>) instance2).get());
+        Object instance3 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        assertEquals("1", ((DisposableSupplier<?>) instance3).get());
+        dispose(instance1, instance2, instance3);
+    }
+
+    @Test
+    public void testOnlyIncrementSingletonInstances() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(DisposableSupplierImpl.class, Singleton.class)
+//                        .to(StringForSupplierSingletonClass.class));
+
+        Object instance1 = injectionManager.getInstance(StringForSupplierSingletonClass.class);
+        assertEquals("1", instance1);
+        Object instance2 = injectionManager.getInstance(StringForSupplierSingletonClass.class);
+        assertEquals("2", instance2);
+        Object instance3 = injectionManager.getInstance(StringForSupplierSingletonClass.class);
+        assertEquals("3", instance3);
+        Object o = injectionManager.getInstance(
+                new GenericType<DisposableSupplier<StringForSupplierSingletonClass>>() {}.getType());
+        dispose(o, o, o);
+    }
+
+    @Test
+    public void testOnlyIncrementInstanceInstance() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(new DisposableSupplierImpl())
+//                        .to(StringForSupplierInstance.class));
+
+        Object instance1 = injectionManager.getInstance(StringForSupplierInstance.class);
+        assertEquals("1", instance1);
+        Object instance2 = injectionManager.getInstance(StringForSupplierInstance.class);
+        assertEquals("2", instance2);
+        Object instance3 = injectionManager.getInstance(StringForSupplierInstance.class);
+        assertEquals("3", instance3);
+        Object o = injectionManager.getInstance(new GenericType<DisposableSupplier<StringForSupplierInstance>>() {}.getType());
+        dispose(o, o, o);
+    }
+
+    @Test
+    public void testDisposeSingletonSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(DisposableSupplierImpl.class, Singleton.class)
+//                        .to(StringForSupplierSingletonClass.class));
+
+        // 1-1
+        DisposableSupplier<StringForSupplierSingletonClass> supplier1 =
+                injectionManager.getInstance(DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        CharSequence instance1 = supplier1.get();
+        // 2-2
+        DisposableSupplier<StringForSupplierSingletonClass> supplier2 =
+                injectionManager.getInstance(DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        CharSequence instance2 = supplier2.get();
+        // 3-3
+        DisposableSupplier<StringForSupplierSingletonClass> supplier3 =
+                injectionManager.getInstance(DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        supplier3.get();
+        // 2-2
+        supplier1.dispose(null);
+        // 1-1
+        supplier2.dispose(null);
+        // 2-2
+        Supplier<StringForSupplierSingletonClass> supplier4 = injectionManager.getInstance(
+                DISPOSABLE_SUPPLIER_SINGLETON_CLASS_TYPE);
+        CharSequence result = supplier4.get();
+        assertEquals("2", result);
+        dispose(supplier3, supplier4);
+    }
+
+    @Test
+    public void testDisposePerLookupSupplier() {
+//        BindingTestHelper.bind(injectionManager, binder -> binder.bindFactory(DisposableSupplierImpl.class)
+//                .to(StringForSupplierClass.class));
+
+        // 1
+        DisposableSupplier<StringForSupplierClass> supplier1 =
+                injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        CharSequence instance1 = supplier1.get();
+        // 1
+        DisposableSupplier<StringForSupplierClass> supplier2 =
+                injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        CharSequence instance2 = supplier2.get();
+        // 1
+        DisposableSupplier<StringForSupplierClass> supplier3 =
+                injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        supplier3.get();
+        // 0
+        supplier1.dispose(null);
+        // 0
+        supplier2.dispose(null);
+        // 1
+        Supplier<StringForSupplierClass> supplier4 = injectionManager.getInstance(DISPOSABLE_SUPPLIER_CLASS_TYPE);
+        CharSequence result = supplier4.get();
+        assertEquals("1", result);
+        dispose(supplier3, supplier4);
+    }
+
+    @Test
+    public void testDisposeSingletonSupplierRequestScopedInstance() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//                    binder.bindFactory(ProxiableDisposableSingletonSupplierImpl.class, Singleton.class)
+//                            .to(ProxiableHolderSingletonClass.class)
+//                            .in(RequestScoped.class);
+//                });
+
+        RequestScope request = injectionManager.getInstance(RequestScope.class);
+        AtomicReference<Supplier<ProxiableHolderSingletonClass>> atomicSupplier = new AtomicReference<>();
+        request.runInScope(() -> {
+            // Save Singleton Supplier for later check that the instance was disposed.
+            Supplier<ProxiableHolderSingletonClass> supplier = injectionManager.getInstance(
+                    new GenericType<DisposableSupplier<ProxiableHolderSingletonClass>>() {}.getType());
+            atomicSupplier.set(supplier);
+
+            // All instances should be the same because they are request scoped.
+            ProxiableHolderSingletonClass instance1 = injectionManager.getInstance(ProxiableHolderSingletonClass.class);
+            assertEquals("1", instance1.getValue());
+            ProxiableHolderSingletonClass instance2 = injectionManager.getInstance(ProxiableHolderSingletonClass.class);
+            assertEquals("1", instance2.getValue());
+        });
+
+        Supplier<ProxiableHolderSingletonClass> cleanedSupplier = atomicSupplier.get();
+        // Next should be 1-1
+        assertEquals("1", cleanedSupplier.get().getValue());
+    }
+
+    /**
+     * Tests that object created in request scope is disposing at the time of ending the scope.
+     */
+    @Test
+    public void testDisposePerLookupSupplierRequestScopedInstance() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//                    binder.bindFactory(ProxiableDisposableSupplierImpl.class)
+//                            .to(ProxiableHolderClass.class)
+//                            .in(RequestScoped.class);
+//                });
+
+        RequestScope request = injectionManager.getInstance(RequestScope.class);
+        AtomicReference<Supplier<ProxiableHolderClass>> atomicSupplier = new AtomicReference<>();
+        request.runInScope(() -> {
+            // Save Singleton Supplier for later check that the instance was disposed.
+            Supplier<ProxiableHolderClass> supplier = injectionManager.getInstance(PROXIABLE_DISPOSABLE_SUPPLIER_CLASS_TYPE);
+            atomicSupplier.set(supplier);
+
+            // All instances should be the same because they are request scoped.
+            ProxiableHolderClass instance1 = injectionManager.getInstance(ProxiableHolderClass.class);
+            assertEquals("1", instance1.getValue());
+            ProxiableHolderClass instance2 = injectionManager.getInstance(ProxiableHolderClass.class);
+            assertEquals("1", instance2.getValue());
+        });
+
+        Supplier<ProxiableHolderClass> cleanedSupplier = atomicSupplier.get();
+        // Next should be 1
+        assertEquals("1", cleanedSupplier.get().getValue());
+    }
+
+    /**
+     * Tests that inherited request scoped is also cleaned by disposing the objects.
+     */
+    @Test
+    public void testDisposeSingletonSupplierMultiRequestScoped() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//                    binder.bindFactory(ProxiableDisposableSupplierImpl.class)
+//                            .to(ProxiableHolderClass.class)
+//                            .in(RequestScoped.class);
+//                });
+
+        RequestScope request = injectionManager.getInstance(RequestScope.class);
+        AtomicReference<Supplier<ProxiableHolderClass>> firstSupplier = new AtomicReference<>();
+        AtomicReference<Supplier<ProxiableHolderClass>> secondSupplier = new AtomicReference<>();
+
+        request.runInScope(() -> {
+            Supplier<ProxiableHolderClass> supplier1 = injectionManager.getInstance(PROXIABLE_DISPOSABLE_SUPPLIER_CLASS_TYPE);
+            firstSupplier.set(supplier1);
+
+            ProxiableHolderClass instance1 = injectionManager.getInstance(ProxiableHolderClass.class);
+            assertEquals("1", instance1.getValue());
+
+            request.runInScope(() -> {
+                // Save Singleton Supplier for later check that the instance was disposed.
+                Supplier<ProxiableHolderClass> supplier2 = injectionManager.getInstance(PROXIABLE_DISPOSABLE_SUPPLIER_CLASS_TYPE);
+                secondSupplier.set(supplier2);
+
+                ProxiableHolderClass instance2 = injectionManager.getInstance(ProxiableHolderClass.class);
+                // 1-2 because the same static class is used in inherited runInScope
+                assertEquals("1", instance2.getValue());
+            });
+        });
+
+        Supplier<ProxiableHolderClass> cleanedSupplier1 = firstSupplier.get();
+        Supplier<ProxiableHolderClass> cleanedSupplier2 = secondSupplier.get();
+        // Next should be 1-1
+        assertEquals("1", cleanedSupplier1.get().getValue());
+        // 1-2 because the same static class is used but the instance is cleaned.
+        assertEquals("1", cleanedSupplier2.get().getValue());
+    }
+
+    /**
+     * PerLookup fields are not disposed therefore they should never be used as a DisposedSupplier because the field stay in
+     * {@link org.glassfish.jersey.inject.weld.bean.SupplierClassBean} forever.
+     */
+    @Test
+    public void testDisposeComposedObjectWithPerLookupFields() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//                    binder.bindFactory(DisposableSupplierForComposedImpl.class, Singleton.class)
+//                            .to(StringForComposed.class);
+//
+//                    binder.bindAsContract(ComposedObject.class)
+//                            .in(RequestScoped.class);
+//                });
+
+        RequestScope request = injectionManager.getInstance(RequestScope.class);
+        AtomicReference<Supplier<StringForComposed>> atomicSupplier = new AtomicReference<>();
+        request.runInScope(() -> {
+            // Save Singleton Supplier for later check that the instance was disposed.
+            Supplier<StringForComposed> supplier = injectionManager.getInstance(
+                    new GenericType<DisposableSupplier<StringForComposed>>() {}.getType());
+            atomicSupplier.set(supplier);
+
+            // All instances should be the same because they are request scoped.
+            ComposedObject instance = injectionManager.getInstance(ComposedObject.class);
+            assertEquals("1", instance.getFirst().toString());
+            assertEquals("2", instance.getSecond().toString());
+            assertEquals("3", instance.getThird().toString());
+        });
+
+        Supplier<StringForComposed> cleanedSupplier = atomicSupplier.get();
+        // Next should be 1 - all instances are disposed and decremented back
+        assertEquals("1", cleanedSupplier.get().toString());
+    }
+
+    private void dispose(Object... objects) {
+        for (Object object : objects) {
+            if (DisposableSupplier.class.isInstance(object)) {
+                ((DisposableSupplier) object).dispose(null);
+            }
+        }
+    }
+
+    @Vetoed
+    static class ComposedObject {
+
+        @Inject
+        StringForComposed first;
+
+        @Inject
+        StringForComposed second;
+
+        @Inject
+        StringForComposed third;
+
+        public StringForComposed getFirst() {
+            return first;
+        }
+
+        public StringForComposed getSecond() {
+            return second;
+        }
+
+        public StringForComposed getThird() {
+            return third;
+        }
+    }
+
+    @Vetoed
+    static class DisposableSupplierForComposedImpl implements DisposableSupplier<StringForComposed> {
+        private final AtomicInteger counter = new AtomicInteger();
+
+        @Override
+        public StringForComposed get() {
+            // Create a new string - don't share the instances in the string pool.
+            return new StringForComposed(counter.incrementAndGet() + "");
+        }
+
+        @Override
+        public void dispose(final StringForComposed instance) {
+            counter.decrementAndGet();
+        }
+    }
+
+    @Vetoed
+    static class DisposableSupplierImpl implements DisposableSupplier<String> {
+        private final AtomicInteger counter = new AtomicInteger();
+
+        @Override
+        public String get() {
+            // Create a new string - don't share the instances in the string pool.
+            return new String(counter.incrementAndGet() + "");
+        }
+
+        @Override
+        public void dispose(final String instance) {
+            counter.decrementAndGet();
+        }
+    }
+
+    @Vetoed
+    static class ProxiableDisposableSupplierImpl implements DisposableSupplier<AbstractProxiableHolder> {
+        private final AtomicInteger counter = new AtomicInteger();
+
+        @Override
+        public AbstractProxiableHolder get() {
+            // Create a new string - don't share the instances in the string pool.
+            return new ProxiableHolderClass(counter.incrementAndGet() + "");
+        }
+
+        @Override
+        public void dispose(AbstractProxiableHolder instance) {
+            counter.decrementAndGet();
+        }
+    }
+
+    @Vetoed
+    static class ProxiableDisposableSingletonSupplierImpl implements DisposableSupplier<AbstractProxiableHolder> {
+        private final AtomicInteger counter = new AtomicInteger();
+
+        @Override
+        public AbstractProxiableHolder get() {
+            // Create a new string - don't share the instances in the string pool.
+            return new ProxiableHolderSingletonClass(counter.incrementAndGet() + "");
+        }
+
+        @Override
+        public void dispose(AbstractProxiableHolder instance) {
+            counter.decrementAndGet();
+        }
+    }
+
+    @Vetoed
+    static class ProxiableHolderSingletonClass extends AbstractProxiableHolder {
+        public ProxiableHolderSingletonClass(String value) {
+            super(value);
+        }
+    }
+
+    @Vetoed
+    static class ProxiableHolderClass extends AbstractProxiableHolder {
+        public ProxiableHolderClass(String value) {
+            super(value);
+        }
+    }
+
+    @Vetoed
+    abstract static class AbstractProxiableHolder {
+        private String value;
+
+        public AbstractProxiableHolder(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+
+    @Vetoed
+    static final class GreetingsInstance extends ExtendableString {
+        public GreetingsInstance(CharSequence inner) {
+            super(inner);
+        }
+    }
+
+    @Vetoed
+    static final class GreetingsClass extends ExtendableString {
+        public GreetingsClass(CharSequence inner) {
+            super(inner);
+        }
+    }
+
+    @Vetoed
+    static final class StringForComposed extends ExtendableString {
+        public StringForComposed(CharSequence inner) {
+            super(inner);
+        }
+    }
+
+    @Vetoed
+    static final class StringForSupplierSingletonClass extends ExtendableString {
+        public StringForSupplierSingletonClass(CharSequence inner) {
+            super(inner);
+        }
+    }
+
+    @Vetoed
+    static final class StringForSupplierClass extends ExtendableString {
+        public StringForSupplierClass(CharSequence inner) {
+            super(inner);
+        }
+    }
+
+    @Vetoed
+    static final class StringForSupplierInstance extends ExtendableString {
+        public StringForSupplierInstance(CharSequence inner) {
+            super(inner);
+        }
+    }
+
+    static class ExtendableString implements CharSequence, Comparable<ExtendableString> {
+
+        private final CharSequence inner;
+
+        protected ExtendableString(CharSequence inner) {
+            this.inner = inner;
+        }
+
+        @Override
+        public int length() {
+            return inner.length();
+        }
+
+        @Override
+        public char charAt(int index) {
+            return inner.charAt(index);
+        }
+
+        @Override
+        public CharSequence subSequence(int start, int end) {
+            return inner.subSequence(start, end);
+        }
+
+        @Override
+        public String toString() {
+            return inner.toString();
+        }
+
+        @Override
+        public int compareTo(ExtendableString o) {
+            if (this == o) return 0;
+            if (o == null) return -1;
+            return Objects.compare(inner.toString(), o.toString(), String.CASE_INSENSITIVE_ORDER);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null) return false;
+            return Objects.equals(inner.toString(), inner.toString());
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(inner);
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/EnglishGreeting.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/EnglishGreeting.java
new file mode 100644
index 0000000..767b117
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/EnglishGreeting.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.inject.Vetoed;
+
+/**
+ * @author Petr Bouda
+ */
+@Vetoed
+public class EnglishGreeting implements Greeting, Printable {
+
+    static final String GREETING = "Hello";
+
+    @Override
+    public String getGreeting() {
+        return GREETING + "#" + Thread.currentThread().getName();
+    }
+
+    @Override
+    public void print() {
+        System.out.println(GREETING);
+    }
+
+    @Override
+    public String toString() {
+        return "EnglishGreeting";
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Greeting.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Greeting.java
new file mode 100644
index 0000000..5f0551e
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Greeting.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+/**
+ * @author Petr Bouda
+ */
+@FunctionalInterface
+public interface Greeting {
+
+    /**
+     * Returns greeting in a specific language.
+     *
+     * @return type of the greeting.
+     */
+    String getGreeting();
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/InjectionManagerTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/InjectionManagerTest.java
new file mode 100644
index 0000000..6cf1053
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/InjectionManagerTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.managed.CdiInjectionManagerFactory;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class InjectionManagerTest extends TestParent {
+
+    @Test
+    public void injectionManagerTest() {
+        injectionManager.completeRegistration();
+        final InjectionManagerInjectedBean bean = injectionManager.getInstance(InjectionManagerInjectedBean.class);
+        Assert.assertNotNull(bean);
+        InjectionManager got = bean.getInjectionManager();
+        Assert.assertEquals(injectionManager, got);
+
+        final InjectionManager clientInjectionManager = new CdiInjectionManagerFactory().create(null, RuntimeType.CLIENT);
+        clientInjectionManager.completeRegistration();
+        final InjectionManagerInjectedBean clientBean = clientInjectionManager.getInstance(InjectionManagerInjectedBean.class);
+        Assert.assertNotNull(clientBean);
+        InjectionManager gotClient = clientBean.getInjectionManager();
+        Assert.assertEquals(clientInjectionManager, gotClient);
+    }
+
+    @Dependent
+    public static class InjectionManagerInjectedBean {
+        @Inject
+        InjectionManager injectionManager;
+
+        InjectionManager getInjectionManager() {
+            return injectionManager;
+        }
+    }
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/MyVetoedLongSupplier.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/MyVetoedLongSupplier.java
new file mode 100644
index 0000000..fe1f720
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/MyVetoedLongSupplier.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Vetoed;
+
+@Vetoed
+public class MyVetoedLongSupplier implements Supplier<Long> {
+
+    private final AtomicLong counter = new AtomicLong();
+
+    @Override
+    public Long get() {
+        return counter.incrementAndGet();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Printable.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Printable.java
new file mode 100644
index 0000000..4307ea8
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/Printable.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+/**
+ * @author Petr Bouda
+ */
+@FunctionalInterface
+public interface Printable {
+
+    void print();
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/PrintableConversation.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/PrintableConversation.java
new file mode 100644
index 0000000..f507e55
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/PrintableConversation.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Vetoed;
+import javax.inject.Inject;
+
+/**
+ * @author Petr Bouda
+ */
+@Vetoed
+class PrintableConversation {
+
+    @Inject
+    Greeting greeting;
+
+    @Inject
+    Supplier<Greeting> greetingSupplier;
+
+    @Inject
+    Printable printable;
+
+    @Inject
+    Supplier<Printable> printableSupplier;
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ProviderInjectionTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ProviderInjectionTest.java
new file mode 100644
index 0000000..3fe20cf
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ProviderInjectionTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Vetoed;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.ws.rs.core.Context;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+
+import org.hamcrest.core.StringStartsWith;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertThat;
+
+public class ProviderInjectionTest extends TestParent {
+
+    @BeforeClass
+    public static void setup() {
+        SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
+        containerInitializer.addExtensions(new ProviderInjectionTestExtension());
+        container = containerInitializer.initialize();
+    }
+
+
+    @Test
+    public void testProviderInject() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bind(CzechGreeting.class).to(Greeting.class);
+//            binder.bindAsContract(ProviderInject.class);
+//        });
+
+        Greeting greeting = injectionManager.getInstance(Greeting.class);
+        Assert.assertNotNull(greeting);
+
+        ProviderInject instance = injectionManager.getInstance(ProviderInject.class);
+        assertThat(instance.greeting.get().getGreeting(), StringStartsWith.startsWith(CzechGreeting.GREETING));
+    }
+
+    @Test
+    public void testProviderContext() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bind(CzechGreeting.class).to(Greeting.class);
+//            binder.bindAsContract(ProviderContext.class);
+//        });
+
+        ProviderContext instance = injectionManager.getInstance(ProviderContext.class);
+        assertThat(instance.greeting.get().getGreeting(), StringStartsWith.startsWith(CzechGreeting.GREETING));
+    }
+
+    @Test
+    public void testProviderFactoryInject() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class).to(Greeting2.class);
+//            binder.bindAsContract(ProviderInject2.class);
+//        });
+
+        ProviderInject2 conversation = injectionManager.getInstance(ProviderInject2.class);
+        assertThat(conversation.greeting.get().getGreeting(), StringStartsWith.startsWith(CzechGreeting.GREETING));
+    }
+
+
+    @Test
+    public void testProviderFactoryContext() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class).to(Greeting2.class);
+//            binder.bindAsContract(ProviderContext2.class);
+//        });
+
+        ProviderContext2 conversation = injectionManager.getInstance(ProviderContext2.class);
+        assertThat(conversation.greeting.get().getGreeting(), StringStartsWith.startsWith(CzechGreeting.GREETING));
+    }
+
+    public static class ProviderInject2 {
+        @Inject
+        Provider<Greeting2> greeting;
+    }
+
+    public static class ProviderContext2 {
+        @Context
+        Provider<Greeting2> greeting;
+    }
+
+    public static class ProviderInject {
+        @Inject
+        Provider<Greeting> greeting;
+    }
+
+    public static class ProviderContext {
+        @Context
+        Provider<Greeting> greeting;
+    }
+
+    @Vetoed
+    static class SupplierGreeting implements Supplier<Greeting2> {
+
+        private final String greetingType;
+
+        /**
+         * Default constructor.
+         */
+        public SupplierGreeting() {
+            this(CzechGreeting.GREETING);
+        }
+
+        /**
+         * Supplier's constructor.
+         *
+         * @param greetingType greetingType in a specific language.
+         */
+        public SupplierGreeting(String greetingType) {
+            this.greetingType = greetingType;
+        }
+
+        @Override
+        public Greeting2 get() {
+            if (CzechGreeting.GREETING.equals(greetingType)) {
+                return new CzechGreeting2();
+            } else {
+                return new EnglishGreeting2();
+            }
+        }
+    }
+
+    @Vetoed
+    static class EnglishGreeting2 extends EnglishGreeting implements Greeting2 {
+    }
+
+    @Vetoed
+    static class CzechGreeting2 extends CzechGreeting implements Greeting2 {
+    }
+
+    @Vetoed
+    static class EnglishGreeting implements Greeting, Printable {
+
+        static final String GREETING = "Hello";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public void print() {
+            System.out.println(GREETING);
+        }
+
+        @Override
+        public String toString() {
+            return "EnglishGreeting";
+        }
+    }
+
+    @Vetoed
+    static class CzechGreeting implements Greeting, Printable {
+
+        static final String GREETING = "Ahoj";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public void print() {
+            System.out.println(GREETING);
+        }
+
+        @Override
+        public String toString() {
+            return "CzechGreeting";
+        }
+    }
+
+    @FunctionalInterface
+    interface Greeting2 {
+        String getGreeting();
+    }
+
+    @FunctionalInterface
+    interface Greeting {
+        String getGreeting();
+    }
+
+    @FunctionalInterface
+    public interface Printable {
+        void print();
+    }
+
+    private static class ProviderInjectionTestExtension implements Extension {
+        void registerBindings(@Observes BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
+            AbstractBinder testBinder = new AbstractBinder() {
+                @Override
+                protected void configure() {
+                    bind(CzechGreeting.class).to(Greeting.class);
+                    bindAsContract(ProviderInject.class);
+                    bindAsContract(ProviderContext.class);
+
+                    bindFactory(SupplierGreeting.class).to(Greeting2.class);
+                    bindAsContract(ProviderInject2.class);
+                    bindAsContract(ProviderContext2.class);
+                }
+            };
+
+            beanManager.getExtension(BinderRegisterExtension.class).register(beforeBeanDiscovery, testBinder.getBindings());
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierClassBindingTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierClassBindingTest.java
new file mode 100644
index 0000000..bf10029
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierClassBindingTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.function.Supplier;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Vetoed;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+
+import org.hamcrest.core.StringStartsWith;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests that {@link Supplier} can be registered as a class-factory.
+ */
+@Vetoed
+public class SupplierClassBindingTest extends TestParent {
+
+    public static final String GREET = "Hi";
+
+    @BeforeClass
+    public static void setup() {
+        SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
+        containerInitializer.addExtensions(new SupplierClassBindingTestExtension());
+        container = containerInitializer.initialize();
+    }
+
+    @Test
+    public void testMessages() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class).to(Greeting.class);
+//            binder.bindAsContract(Conversation.class);
+//        });
+
+        Conversation conversation = injectionManager.getInstance(Conversation.class);
+        assertThat(conversation.greeting.getGreeting(), StringStartsWith.startsWith(GREET));
+    }
+
+    @Test
+    public void testSupplierPerLookupInstancePerLookup() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class).to(Greeting.class);
+//            binder.bindAsContract(Conversation.class);
+//        });
+
+        Conversation conversation1 = injectionManager.getInstance(Conversation.class);
+        Greeting greeting1 = conversation1.greeting;
+        Conversation conversation2 = injectionManager.getInstance(Conversation.class);
+        Greeting greeting2 = conversation2.greeting;
+        Conversation conversation3 = injectionManager.getInstance(Conversation.class);
+        Greeting greeting3 = conversation3.greeting;
+
+        assertNotSame(greeting1, greeting2);
+        assertNotSame(greeting2, greeting3);
+
+        Supplier<Greeting> supplier1 = injectionManager.getInstance(Conversation.class).greetingSupplier;
+        Supplier<Greeting> supplier2 = injectionManager.getInstance(Conversation.class).greetingSupplier;
+        Supplier<Greeting> supplier3 = injectionManager.getInstance(Conversation.class).greetingSupplier;
+
+        assertNotSame(supplier1, supplier2);
+        assertNotSame(supplier2, supplier3);
+    }
+
+    @Test
+    public void testSupplierSingletonInstancePerLookup() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierSingletonInstancePerLookup.class, Singleton.class)
+//                    .to(GreetingSupplierSingletonInstancePerLookup.class);
+//            binder.bindAsContract(ConversationSupplierSingletonInstancePerLookup.class);
+//        });
+
+        GreetingSupplierSingletonInstancePerLookup greeting1 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstancePerLookup.class).greeting;
+        GreetingSupplierSingletonInstancePerLookup greeting2 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstancePerLookup.class).greeting;
+        GreetingSupplierSingletonInstancePerLookup greeting3 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstancePerLookup.class).greeting;
+
+        assertNotSame(greeting1, greeting2);
+        assertNotSame(greeting2, greeting3);
+
+        Supplier<GreetingSupplierSingletonInstancePerLookup> supplier1 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstancePerLookup.class).greetingSupplier;
+        Supplier<GreetingSupplierSingletonInstancePerLookup> supplier2 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstancePerLookup.class).greetingSupplier;
+        Supplier<GreetingSupplierSingletonInstancePerLookup> supplier3 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstancePerLookup.class).greetingSupplier;
+
+        assertSame(supplier1, supplier2);
+        assertSame(supplier2, supplier3);
+    }
+
+    @Test
+    public void testSupplierPerLookupInstanceSingleton() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierPerLookupInstanceSingleton.class)
+//                    .to(GreetingSupplierPerLookupInstanceSingleton.class).in(Singleton.class);
+//            binder.bindAsContract(ConversationSupplierPerLookupInstanceSingleton.class);
+//        });
+
+        GreetingSupplierPerLookupInstanceSingleton greeting1 = injectionManager
+                .getInstance(ConversationSupplierPerLookupInstanceSingleton.class).greeting;
+        GreetingSupplierPerLookupInstanceSingleton greeting2 = injectionManager
+                .getInstance(ConversationSupplierPerLookupInstanceSingleton.class).greeting;
+        GreetingSupplierPerLookupInstanceSingleton greeting3 = injectionManager
+                .getInstance(ConversationSupplierPerLookupInstanceSingleton.class).greeting;
+
+        assertSame(greeting1, greeting2);
+        assertSame(greeting2, greeting3);
+
+        Supplier<GreetingSupplierPerLookupInstanceSingleton> supplier1 = injectionManager
+                .getInstance(ConversationSupplierPerLookupInstanceSingleton.class).greetingSupplier;
+        Supplier<GreetingSupplierPerLookupInstanceSingleton> supplier2 = injectionManager
+                .getInstance(ConversationSupplierPerLookupInstanceSingleton.class).greetingSupplier;
+        Supplier<GreetingSupplierPerLookupInstanceSingleton> supplier3 = injectionManager
+                .getInstance(ConversationSupplierPerLookupInstanceSingleton.class).greetingSupplier;
+
+        assertNotSame(supplier1, supplier2);
+        assertNotSame(supplier2, supplier3);
+    }
+
+    @Test
+    public void testSupplierSingletonInstanceSingleton() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierSingletonInstanceSingleton.class, Singleton.class)
+//                    .to(GreetingSupplierSingletonInstanceSingleton.class).in(Singleton.class);
+//            binder.bindAsContract(ConversationSupplierSingletonInstanceSingleton.class);
+//        });
+
+        GreetingSupplierSingletonInstanceSingleton greeting1 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstanceSingleton.class).greeting;
+        GreetingSupplierSingletonInstanceSingleton greeting2 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstanceSingleton.class).greeting;
+        GreetingSupplierSingletonInstanceSingleton greeting3 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstanceSingleton.class).greeting;
+
+        assertSame(greeting1, greeting2);
+        assertSame(greeting2, greeting3);
+
+        Supplier<GreetingSupplierSingletonInstanceSingleton> supplier1 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstanceSingleton.class).greetingSupplier;
+        Supplier<GreetingSupplierSingletonInstanceSingleton> supplier2 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstanceSingleton.class).greetingSupplier;
+        Supplier<GreetingSupplierSingletonInstanceSingleton> supplier3 = injectionManager
+                .getInstance(ConversationSupplierSingletonInstanceSingleton.class).greetingSupplier;
+
+        assertSame(supplier1, supplier2);
+        assertSame(supplier2, supplier3);
+    }
+
+    @Vetoed
+    static class SupplierSingletonInstanceSingleton implements Supplier<GreetingSupplierSingletonInstanceSingleton> {
+        @Override
+        public GreetingSupplierSingletonInstanceSingleton get() {
+            return new GreetingSupplierSingletonInstanceSingleton() {
+                @Override
+                public String getGreeting() {
+                    return GREET;
+                }
+            };
+        }
+    }
+
+    @Vetoed
+    static class ConversationSupplierSingletonInstanceSingleton {
+        @Inject
+        GreetingSupplierSingletonInstanceSingleton greeting;
+
+        @Inject
+        Supplier<GreetingSupplierSingletonInstanceSingleton> greetingSupplier;
+    }
+
+    @FunctionalInterface
+    static interface GreetingSupplierSingletonInstanceSingleton {
+        String getGreeting();
+    }
+
+    // ---
+
+    @Vetoed
+    static class SupplierPerLookupInstanceSingleton implements Supplier<GreetingSupplierPerLookupInstanceSingleton> {
+        @Override
+        public GreetingSupplierPerLookupInstanceSingleton get() {
+            return () -> GREET;
+        }
+    }
+
+    @Vetoed
+    static class ConversationSupplierPerLookupInstanceSingleton {
+        @Inject
+        GreetingSupplierPerLookupInstanceSingleton greeting;
+
+        @Inject
+        Supplier<GreetingSupplierPerLookupInstanceSingleton> greetingSupplier;
+    }
+
+    @FunctionalInterface
+    static interface GreetingSupplierPerLookupInstanceSingleton {
+        String getGreeting();
+    }
+
+    // ---
+
+    @Vetoed
+    static class SupplierSingletonInstancePerLookup implements Supplier<GreetingSupplierSingletonInstancePerLookup> {
+        @Override
+        public GreetingSupplierSingletonInstancePerLookup get() {
+            return new GreetingSupplierSingletonInstancePerLookup() { // Using Lambda will provide singletons
+                @Override
+                public String getGreeting() {
+                    return GREET;
+                }
+            };
+        }
+    }
+
+    @Vetoed
+    static class ConversationSupplierSingletonInstancePerLookup {
+        @Inject
+        GreetingSupplierSingletonInstancePerLookup greeting;
+
+        @Inject
+        Supplier<GreetingSupplierSingletonInstancePerLookup> greetingSupplier;
+    }
+
+    @FunctionalInterface
+    static interface GreetingSupplierSingletonInstancePerLookup {
+        String getGreeting();
+    }
+
+    // ---
+
+    @Vetoed
+    static class SupplierGreeting implements Supplier<Greeting> {
+        @Override
+        public Greeting get() {
+            return new Greeting() { // Using Lambda will provide singletons
+                @Override
+                public String getGreeting() {
+                    return GREET;
+                }
+            };
+        }
+    }
+
+    @Vetoed
+    static class Conversation {
+        @Inject
+        Greeting greeting;
+
+        @Inject
+        Supplier<Greeting> greetingSupplier;
+    }
+
+    @FunctionalInterface
+    static interface Greeting {
+        String getGreeting();
+    }
+
+    private static class SupplierClassBindingTestExtension implements Extension {
+        void registerBindings(@Observes BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
+            AbstractBinder testBinder = new AbstractBinder() {
+                @Override
+                protected void configure() {
+                    bindFactory(SupplierGreeting.class).to(Greeting.class);
+                    bindAsContract(Conversation.class);
+
+                    bindFactory(SupplierSingletonInstancePerLookup.class, Singleton.class)
+                            .to(GreetingSupplierSingletonInstancePerLookup.class);
+                    bindAsContract(ConversationSupplierSingletonInstancePerLookup.class);
+
+                    bindFactory(SupplierPerLookupInstanceSingleton.class)
+                            .to(GreetingSupplierPerLookupInstanceSingleton.class).in(Singleton.class);
+                    bindAsContract(ConversationSupplierPerLookupInstanceSingleton.class);
+
+                    bindFactory(SupplierSingletonInstanceSingleton.class, Singleton.class)
+                            .to(GreetingSupplierSingletonInstanceSingleton.class).in(Singleton.class);
+                    bindAsContract(ConversationSupplierSingletonInstanceSingleton.class);
+                }
+            };
+
+            beanManager.getExtension(BinderRegisterExtension.class).register(beforeBeanDiscovery, testBinder.getBindings());
+        }
+    }
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierContractsTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierContractsTest.java
new file mode 100644
index 0000000..8f576e1
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierContractsTest.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Vetoed;
+import javax.enterprise.inject.se.SeContainer;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.inject.Singleton;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+
+import org.glassfish.jersey.internal.inject.Injections;
+import org.jboss.weld.exceptions.DeploymentException;
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.function.Consumer;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Tests that {@link java.util.function.Supplier} can contain multiple contracts.
+ *
+ * @author Petr Bouda
+ */
+@Vetoed
+public class SupplierContractsTest {
+
+    protected static SeContainer container;
+    protected InjectionManager injectionManager;
+
+    public void setup(Consumer<AbstractBinder> binding) {
+        Extension extension = new Extension() {
+            void registerBindings(@Observes BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
+                AbstractBinder testBinder = new AbstractBinder() {
+                    @Override
+                    protected void configure() {
+                        binding.accept(this);
+                    }
+                };
+                beanManager.getExtension(BinderRegisterExtension.class).register(beforeBeanDiscovery, testBinder.getBindings());
+            }
+        };
+
+        SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
+        containerInitializer.addExtensions(extension);
+        container = containerInitializer.initialize();
+        injectionManager = Injections.createInjectionManager();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (container != null && container.isRunning()) {
+            container.close();
+        }
+    }
+
+    @Test
+    public void testClassFactoryInstanceInterface() {
+//        setup(new SupplierContractsTestExtension() {
+//            @Override
+//            void bind(AbstractBinder binder) {
+//                binder.bindFactory(SupplierGreeting.class).to(Greeting.class);
+//                binder.bindAsContract(Conversation.class);
+//            }
+//        });
+
+        setup((binder) -> {
+            binder.bindFactory(SupplierGreeting.class).to(Greeting.class);
+            binder.bindAsContract(Conversation.class);
+        });
+
+        Conversation conversation = injectionManager.getInstance(Conversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.greetingSupplier.get());
+    }
+
+    @Test
+    public void testClassFactoryInstanceImplementation() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class).to(CzechGreeting.class);
+//            binder.bindAsContract(CzechConversation.class);
+//        });
+        setup((binder) -> {
+            binder.bindFactory(SupplierGreeting.class).to(CzechGreeting.class);
+            binder.bindAsContract(CzechConversation.class);
+        });
+
+        CzechConversation conversation = injectionManager.getInstance(CzechConversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.greetingSupplier.get());
+    }
+
+    @Test
+    public void testInstanceFactoryInstanceInterface() {
+        setup((binder) -> {
+            binder.bindFactory(new SupplierGreeting()).to(Greeting.class);
+            binder.bindAsContract(Conversation.class);
+        });
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(new SupplierGreeting()).to(Greeting.class);
+//            binder.bindAsContract(Conversation.class);
+        });
+
+        Conversation conversation = injectionManager.getInstance(Conversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.greetingSupplier.get());
+    }
+
+    @Test
+    public void testInstanceFactoryInstanceImplementation() {
+        setup((binder) -> {
+            binder.bindFactory(new SupplierGreeting()).to(CzechGreeting.class);
+            binder.bindAsContract(CzechConversation.class);
+        });
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(new SupplierGreeting()).to(CzechGreeting.class);
+//            binder.bindAsContract(CzechConversation.class);
+        });
+
+        CzechConversation conversation = injectionManager.getInstance(CzechConversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.greetingSupplier.get());
+    }
+
+    @Test
+    public void testClassFactoryMultipleContracts() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class)
+//                    .to(Greeting.class)
+//                    .to(Printable.class);
+//            binder.bindAsContract(PrintableConversation.class);
+//        });
+
+        setup((binder) -> {
+            binder.bindFactory(SupplierGreeting.class).to(Greeting.class).to(Printable.class);
+            binder.bindAsContract(PrintableConversation.class);
+        });
+
+        PrintableConversation conversation = injectionManager.getInstance(PrintableConversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.printable);
+        assertNotNull(conversation.greetingSupplier);
+        assertNotNull(conversation.printableSupplier);
+
+        assertNotSame(conversation.greeting, conversation.printable);
+        assertNotSame(conversation.greetingSupplier, conversation.printableSupplier);
+    }
+
+    @Test
+    public void testClassFactorySingletonMultipleContracts() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class, Singleton.class)
+//                    .to(Greeting.class)
+//                    .to(Printable.class);
+//            binder.bindAsContract(PrintableConversation.class);
+//        });
+
+        setup((binder) -> {
+            binder.bindFactory(SupplierGreeting.class, Singleton.class).to(Greeting.class).to(Printable.class);
+            binder.bindAsContract(PrintableConversation.class);
+        });
+
+        PrintableConversation conversation = injectionManager.getInstance(PrintableConversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.printable);
+        assertNotNull(conversation.greetingSupplier);
+        assertNotNull(conversation.printableSupplier);
+
+        assertNotSame(conversation.greeting, conversation.printable);
+        assertSame(conversation.greetingSupplier, conversation.printableSupplier);
+    }
+
+    @Test
+    public void testClassFactoryMultipleContractsSingleton() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class)
+//                    .to(Greeting.class)
+//                    .to(Printable.class)
+//                    .in(Singleton.class);
+//            binder.bindAsContract(PrintableConversation.class);
+//        });
+
+        setup((binder) -> {
+            binder.bindFactory(SupplierGreeting.class).to(Greeting.class).to(Printable.class).in(Singleton.class);
+            binder.bindAsContract(PrintableConversation.class);
+        });
+
+        PrintableConversation conversation = injectionManager.getInstance(PrintableConversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.printable);
+        assertNotNull(conversation.greetingSupplier);
+        assertNotNull(conversation.printableSupplier);
+
+        assertSame(conversation.greeting, conversation.printable);
+        assertNotSame(conversation.greetingSupplier, conversation.printableSupplier);
+    }
+
+    @Test
+    public void testInstanceFactoryMultipleContracts() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(new SupplierGreeting())
+//                    .to(Greeting.class)
+//                    .to(Printable.class);
+//            binder.bindAsContract(PrintableConversation.class);
+//        });
+
+        setup((binder) -> {
+            binder.bindFactory(new SupplierGreeting()).to(Greeting.class).to(Printable.class);
+            binder.bindAsContract(PrintableConversation.class);
+        });
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(new SupplierGreeting())
+                    .to(Greeting.class)
+                    .to(Printable.class);
+//            binder.bindAsContract(PrintableConversation.class);
+        });
+
+        PrintableConversation conversation = injectionManager.getInstance(PrintableConversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.printable);
+        assertNotNull(conversation.greetingSupplier);
+        assertNotNull(conversation.printableSupplier);
+
+        assertNotSame(conversation.greeting, conversation.printable);
+        assertSame(conversation.greetingSupplier, conversation.printableSupplier);
+    }
+
+    @Test
+    public void testInstanceFactoryMultipleContractsSingleton() {
+        setup((binder) -> {
+            binder.bindFactory(new SupplierGreeting()).to(Greeting.class).to(Printable.class).in(Singleton.class);
+            binder.bindAsContract(PrintableConversation.class);
+        });
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(new SupplierGreeting())
+                    .to(Greeting.class)
+                    .to(Printable.class)
+                    .in(Singleton.class);
+//            binder.bindAsContract(PrintableConversation.class);
+        });
+
+        PrintableConversation conversation = injectionManager.getInstance(PrintableConversation.class);
+        assertNotNull(conversation.greeting);
+        assertNotNull(conversation.printable);
+        assertNotNull(conversation.greetingSupplier);
+        assertNotNull(conversation.printableSupplier);
+
+        assertSame(conversation.greeting, conversation.printable);
+        assertSame(conversation.greetingSupplier, conversation.printableSupplier);
+    }
+
+    @Test(expected = DeploymentException.class)
+    public void testClassFactoryFailedWrongImplementation() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(SupplierGreeting.class).to(EnglishGreeting.class);
+//            binder.bindAsContract(Conversation.class);
+//        });
+
+        setup((binder) -> {
+            binder.bindFactory(SupplierGreeting.class).to(EnglishGreeting.class);
+            binder.bindAsContract(Conversation.class);
+        });
+
+        injectionManager.getInstance(Conversation.class);
+    }
+
+    @Test(expected = DeploymentException.class)
+    public void testInstanceFactoryFailsWrongImplementation() {
+        setup((binder) -> {
+            binder.bindFactory(new SupplierGreeting()).to(EnglishGreeting.class);
+            binder.bindAsContract(Conversation.class);
+        });
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(new SupplierGreeting()).to(EnglishGreeting.class);
+//            binder.bindAsContract(Conversation.class);
+        });
+
+        injectionManager.getInstance(Conversation.class);
+    }
+
+    @Test(expected = DeploymentException.class)
+    public void testFailsImplementationButInterfaceExpected() {
+        setup((binder) -> {
+            binder.bindFactory(new SupplierGreeting()).to(CzechGreeting.class);
+            binder.bindAsContract(Conversation.class);
+        });
+
+        BindingTestHelper.bind(injectionManager, binder -> {
+            binder.bindFactory(new SupplierGreeting()).to(CzechGreeting.class);
+//            binder.bindAsContract(Conversation.class);
+        });
+
+        injectionManager.getInstance(Conversation.class);
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierGreeting.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierGreeting.java
new file mode 100644
index 0000000..2f97170
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierGreeting.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.Vetoed;
+
+/**
+ * @author Petr Bouda
+ */
+@Vetoed
+public class SupplierGreeting implements Supplier<Greeting> {
+
+    private final String greetingType;
+
+    /**
+     * Default constructor.
+     */
+    public SupplierGreeting() {
+        this(CzechGreeting.GREETING);
+    }
+
+    /**
+     * Supplier's constructor.
+     *
+     * @param greetingType greetingType in a specific language.
+     */
+    public SupplierGreeting(String greetingType) {
+        this.greetingType = greetingType;
+    }
+
+    @Override
+    public Greeting get() {
+        if (CzechGreeting.GREETING.equals(greetingType)) {
+            return new CzechGreeting();
+        } else {
+            return new EnglishGreeting();
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierInstanceBindingTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierInstanceBindingTest.java
new file mode 100644
index 0000000..eb90843
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/SupplierInstanceBindingTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.Vetoed;
+import javax.inject.Inject;
+import javax.ws.rs.core.GenericType;
+
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+
+import org.hamcrest.core.StringStartsWith;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests that {@link Supplier} can be registered as a instance-factory.
+ *
+ * @author Petr Bouda
+ */
+@Vetoed
+public class SupplierInstanceBindingTest extends TestParent {
+
+    private static long supplierHit = 2;
+    private static AtomicBoolean runOnlyOnceGuard = new AtomicBoolean(false);
+
+    @BeforeClass
+    public static void setup() {
+        SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
+        containerInitializer.addExtensions(new SupplierInstanceBindingTestExtension());
+        container = containerInitializer.initialize();
+    }
+
+    @Before
+    public void initBinding() {
+        if (!runOnlyOnceGuard.getAndSet(true)) {
+            MyVetoedLongSupplier supplier = new MyVetoedLongSupplier();
+            supplier.get();
+            supplier.get();
+
+            BindingTestHelper.bind(injectionManager, binder ->
+                    binder.bindFactory(supplier).to(Long.class));
+
+            BindingTestHelper.bind(injectionManager, binder -> {
+                binder.bindFactory(new SupplierGreeting()).to(Greeting.class);
+            });
+        }
+    }
+
+    @Test
+    public void testInstanceFactorySupplierOnly() {
+//        MyVetoedLongSupplier supplier = new MyVetoedLongSupplier();
+//        supplier.get();
+//        supplier.get();
+//
+//        BindingTestHelper.bind(injectionManager, binder ->
+//                binder.bindFactory(supplier).to(Long.class));
+
+        Supplier<Long> instance = injectionManager.getInstance(new GenericType<Supplier<Long>>() {
+        }.getType());
+        assertEquals((Long) (supplierHit++ + 1), instance.get());
+        assertEquals((Long) (supplierHit++ + 1), instance.get());
+    }
+
+    @Test
+    public void testInstanceFactoryValuesOnly() {
+//        MyVetoedLongSupplier supplier = new MyVetoedLongSupplier();
+//        supplier.get();
+//        supplier.get();
+//
+//        BindingTestHelper.bind(injectionManager, binder ->
+//                binder.bindFactory(supplier).to(Long.class));
+
+        Long instance3 = injectionManager.getInstance(Long.class);
+        Long instance4 = injectionManager.getInstance(Long.class);
+
+        assertEquals((Long) (supplierHit++ + 1), instance3);
+        assertEquals((Long) (supplierHit++ + 1), instance4);
+    }
+
+    @Test
+    public void testMessages() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(new SupplierGreeting()).to(Greeting.class);
+//            binder.bindAsContract(Conversation.class);
+//        });
+
+        Conversation conversation = injectionManager.getInstance(Conversation.class);
+        assertThat(conversation.greeting.getGreeting(), StringStartsWith.startsWith(CzechGreeting.GREETING));
+    }
+
+    @Test
+    public void testSupplierSingletonInstancePerLookup() {
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindFactory(new SupplierGreeting()).to(Greeting.class);
+//            binder.bindAsContract(Conversation.class);
+//        });
+
+        Greeting greeting1 = injectionManager.getInstance(Conversation.class).greeting;
+        Greeting greeting2 = injectionManager.getInstance(Conversation.class).greeting;
+        Greeting greeting3 = injectionManager.getInstance(Conversation.class).greeting;
+
+        assertNotSame(greeting1, greeting2);
+        assertNotSame(greeting2, greeting3);
+
+        Supplier<Greeting> supplier1 = injectionManager.getInstance(Conversation.class).greetingSupplier;
+        Supplier<Greeting> supplier2 = injectionManager.getInstance(Conversation.class).greetingSupplier;
+        Supplier<Greeting> supplier3 = injectionManager.getInstance(Conversation.class).greetingSupplier;
+
+        assertSame(supplier1, supplier2);
+        assertSame(supplier2, supplier3);
+    }
+
+    @Vetoed
+    static class Conversation {
+        @Inject
+        Greeting greeting;
+
+        @Inject
+        Supplier<Greeting> greetingSupplier;
+    }
+
+    @Vetoed
+    static class SupplierGreeting implements Supplier<Greeting> {
+
+        private final String greetingType;
+
+        /**
+         * Default constructor.
+         */
+        public SupplierGreeting() {
+            this(CzechGreeting.GREETING);
+        }
+
+        /**
+         * Supplier's constructor.
+         *
+         * @param greetingType greetingType in a specific language.
+         */
+        public SupplierGreeting(String greetingType) {
+            this.greetingType = greetingType;
+        }
+
+        @Override
+        public Greeting get() {
+            if (CzechGreeting.GREETING.equals(greetingType)) {
+                return new CzechGreeting();
+            } else {
+                return new EnglishGreeting();
+            }
+        }
+    }
+
+    static class EnglishGreeting implements Greeting {
+
+        static final String GREETING = "Hello";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public String toString() {
+            return "EnglishGreeting";
+        }
+    }
+
+    static class CzechGreeting implements Greeting {
+
+        static final String GREETING = "Ahoj";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public String toString() {
+            return "CzechGreeting";
+        }
+    }
+
+    @FunctionalInterface
+    static interface Greeting {
+        /**
+         * Returns greeting in a specific language.
+         *
+         * @return type of the greeting.
+         */
+        String getGreeting();
+    }
+
+    private static class SupplierInstanceBindingTestExtension implements Extension {
+        void registerBindings(@Observes BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
+            AbstractBinder testBinder = new AbstractBinder() {
+                @Override
+                protected void configure() {
+                    MyVetoedLongSupplier supplier = new MyVetoedLongSupplier();
+                    supplier.get();
+                    supplier.get();
+                    bindFactory(supplier).to(Long.class);
+
+                    bindFactory(new SupplierGreeting()).to(Greeting.class);
+                    bindAsContract(Conversation.class);
+                }
+            };
+
+            beanManager.getExtension(BinderRegisterExtension.class).register(beforeBeanDiscovery, testBinder.getBindings());
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestParent.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestParent.java
new file mode 100644
index 0000000..0938dd2
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestParent.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.inject.se.SeContainer;
+import javax.enterprise.inject.se.SeContainerInitializer;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.Injections;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+public class TestParent {
+    protected static SeContainer container;
+    protected InjectionManager injectionManager;
+
+
+    @BeforeClass
+    public static void setup() {
+        SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
+        container = containerInitializer.initialize();
+    }
+
+    @Before
+    public void init() {
+        injectionManager = Injections.createInjectionManager();
+    }
+
+    @AfterClass
+    public static void tearDown() throws Exception {
+        container.close();
+    }
+
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestPreinitialization.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestPreinitialization.java
new file mode 100644
index 0000000..a9096b0
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/TestPreinitialization.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Singleton;
+import javax.ws.rs.RuntimeType;
+
+import org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization;
+import org.glassfish.jersey.internal.inject.AbstractBinder;
+import org.glassfish.jersey.internal.inject.PerThread;
+import org.glassfish.jersey.process.internal.RequestScoped;
+
+public class TestPreinitialization implements BootstrapPreinitialization {
+    @Override
+    public void register(RuntimeType runtimeType, AbstractBinder binder) {
+        if (RuntimeType.CLIENT == runtimeType) {
+            //ClientInstanceInjectionTest
+            {
+                binder.bindFactory(ClientInstanceInjectionTest.InjectableClientServerSupplierClient.class)
+                        .to(ClientInstanceInjectionTest.InjectableClientServer.class);
+            }
+            return;
+        }
+
+        // Disposable supplier test
+        {
+            binder.bindFactory(DisposableSupplierTest.DisposableSupplierImpl.class, Singleton.class)
+                    .to(DisposableSupplierTest.StringForSupplierSingletonClass.class);
+            binder.bindFactory(DisposableSupplierTest.DisposableSupplierImpl.class)
+                    .to(DisposableSupplierTest.StringForSupplierClass.class);
+            binder.bindFactory(new DisposableSupplierTest.DisposableSupplierImpl())
+                    .to(DisposableSupplierTest.StringForSupplierInstance.class);
+            binder.bindFactory(SupplierGreeting.class)
+                    .to(DisposableSupplierTest.GreetingsClass.class);
+            binder.bindFactory(new SupplierGreeting())
+                    .to(DisposableSupplierTest.GreetingsInstance.class);
+
+            binder.bindFactory(DisposableSupplierTest.ProxiableDisposableSingletonSupplierImpl.class, Singleton.class)
+                    .to(DisposableSupplierTest.ProxiableHolderSingletonClass.class)
+                    .in(RequestScoped.class);
+            binder.bindFactory(DisposableSupplierTest.ProxiableDisposableSupplierImpl.class)
+                    .to(DisposableSupplierTest.ProxiableHolderClass.class)
+                    .in(RequestScoped.class);
+
+            binder.bindFactory(DisposableSupplierTest.DisposableSupplierForComposedImpl.class, Singleton.class)
+                    .to(DisposableSupplierTest.StringForComposed.class);
+            binder.bindAsContract(DisposableSupplierTest.ComposedObject.class)
+                    .in(RequestScoped.class);
+        }
+
+        // ThreadScopeTest
+        {
+            //testThreadScopedInDifferentThread
+            binder.bindAsContract(ThreadScopeTest.SingletonObject.class)
+                    .in(Singleton.class);
+            binder.bindFactory(new ThreadScopeTest.SupplierGreeting())
+                    .to(ThreadScopeTest.Greeting.class)
+                    .in(PerThread.class);
+
+            //testThreadScopedInRequestScope
+            binder.bindAsContract(ThreadScopeTest.RequestScopedInterface.class)
+                    .in(javax.enterprise.context.RequestScoped.class);
+//                    bindFactory(new SupplierGreeting())
+//                            .to(Greeting.class)
+//                            .in(PerThread.class);
+
+            //testThreadScopedInRequestScopeImplementation
+            binder.bindAsContract(ThreadScopeTest.RequestScopedCzech.class)
+                    .in(javax.enterprise.context.RequestScoped.class);
+            binder.bindFactory(new ThreadScopeTest.SupplierGreeting())
+                    .to(ThreadScopeTest.CzechGreeting.class)
+                    .in(PerThread.class);
+
+            //testThreadScopedInRequestTwoTypes
+            binder.bindAsContract(ThreadScopeTest.RequestScopedCzech2.class)
+                    .in(javax.enterprise.context.RequestScoped.class);
+            binder.bindAsContract(ThreadScopeTest.RequestScopedEnglish2.class)
+                    .in(javax.enterprise.context.RequestScoped.class);
+            binder.bindFactory(new ThreadScopeTest.SupplierGreeting2(ThreadScopeTest.CzechGreeting2.GREETING))
+                    .to(ThreadScopeTest.CzechGreeting2.class)
+                    .in(PerThread.class);
+            binder.bindFactory(new ThreadScopeTest.SupplierGreeting2(ThreadScopeTest.EnglishGreeting2.GREETING))
+                    .to(ThreadScopeTest.EnglishGreeting2.class)
+                    .in(PerThread.class);
+        }
+
+        //ClientInstanceInjectionTest
+        {
+            binder.bind(new ClientInstanceInjectionTest.StringInjectable(0))
+                    .to(ClientInstanceInjectionTest.Injectable.class).in(Dependent.class);
+            binder.bindAsContract(ClientInstanceInjectionTest.InjectedBean.class);
+
+            binder.bindFactory(new ClientInstanceInjectionTest.StringInjectableSupplier2(0))
+                    .to(ClientInstanceInjectionTest.Injectable2.class).in(Dependent.class);
+            //bindAsContract(ClientInstanceInjectionTest.InjectedSupplierBean.class);
+
+            binder.bindFactory(ClientInstanceInjectionTest.InjectableClientServerSupplierServer.class)
+                    .to(ClientInstanceInjectionTest.InjectableClientServer.class);
+        }
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ThreadScopeTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ThreadScopeTest.java
new file mode 100644
index 0000000..e3fc4d2
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/managed/ThreadScopeTest.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.inject.weld.internal.managed;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
+
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.inject.Vetoed;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.glassfish.jersey.internal.inject.PerThread;
+import org.glassfish.jersey.process.internal.RequestScope;
+
+import org.hamcrest.core.StringStartsWith;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Testing thread scope integration.
+ *
+ * @author Petr Bouda
+ */
+public class ThreadScopeTest extends TestParent {
+
+    private static AtomicBoolean runOnlyOnceGuard = new AtomicBoolean(false);
+
+    @Before
+    public void initOnce() {
+        if (!runOnlyOnceGuard.getAndSet(true)) {
+            BindingTestHelper.bind(injectionManager, binder -> {
+                binder.bindFactory(new SupplierGreeting())
+                        .to(Greeting.class)
+                        .in(PerThread.class);
+            });
+        }
+    }
+
+    @Test
+    public void testThreadScopedInDifferentThread() throws InterruptedException {
+//        InjectionManager injectionManager = BindingTestHelper.createInjectionManager();
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindAsContract(SingletonObject.class)
+//                    .in(Singleton.class);
+//
+//            binder.bindFactory(new SupplierGreeting())
+//                    .to(Greeting.class)
+//                    .in(PerThread.class);
+//        });
+
+        SingletonObject instance1 = injectionManager.getInstance(SingletonObject.class);
+        Greeting greeting1 = instance1.getGreeting();
+        String greetingString1 = greeting1.getGreeting();
+        assertThat(greetingString1, StringStartsWith.startsWith(CzechGreeting.GREETING));
+
+        CountDownLatch latch = new CountDownLatch(1);
+        new Thread(() -> {
+            // Precisely the same object
+            SingletonObject instance2 = injectionManager.getInstance(SingletonObject.class);
+            Greeting greeting2 = instance2.getGreeting();
+            String greetingString2 = greeting2.getGreeting();
+            assertThat(greetingString2, StringStartsWith.startsWith(CzechGreeting.GREETING));
+
+            assertNotEquals(greetingString1, greetingString2);
+            latch.countDown();
+        }).start();
+
+        latch.await();
+
+        SingletonObject instance3 = injectionManager.getInstance(SingletonObject.class);
+        assertEquals(instance3.getGreeting().getGreeting(), greetingString1);
+    }
+
+    @Test
+    public void testThreadScopedInRequestScope() {
+//        InjectionManager injectionManager = BindingTestHelper.createInjectionManager();
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindAsContract(RequestScopedInterface.class)
+//                    .in(RequestScoped.class);
+//
+//            binder.bindFactory(new SupplierGreeting())
+//                    .to(Greeting.class)
+//                    .in(PerThread.class);
+//        });
+
+        RequestScope request = injectionManager.getInstance(RequestScope.class);
+        request.runInScope(() -> {
+            RequestScopedInterface instance1 = injectionManager.getInstance(RequestScopedInterface.class);
+            Greeting greeting1 = instance1.getGreeting();
+            assertNotNull(greeting1);
+
+            // Precisely the same object
+            RequestScopedInterface instance2 = injectionManager.getInstance(RequestScopedInterface.class);
+            Greeting greeting2 = instance2.getGreeting();
+            assertNotNull(greeting2);
+
+            assertEquals(greeting1, greeting2);
+        });
+    }
+
+    @Test
+    public void testThreadScopedInRequestScopeImplementation() {
+//        InjectionManager injectionManager = BindingTestHelper.createInjectionManager();
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindAsContract(RequestScopedCzech.class)
+//                    .in(RequestScoped.class);
+//
+//            binder.bindFactory(new SupplierGreeting())
+//                    .to(CzechGreeting.class)
+//                    .in(PerThread.class);
+//        });
+
+        RequestScope request = injectionManager.getInstance(RequestScope.class);
+        request.runInScope(() -> {
+            RequestScopedCzech instance1 = injectionManager.getInstance(RequestScopedCzech.class);
+            CzechGreeting greeting1 = instance1.getGreeting();
+            assertNotNull(greeting1);
+
+            // Precisely the same object
+            RequestScopedCzech instance2 = injectionManager.getInstance(RequestScopedCzech.class);
+            CzechGreeting greeting2 = instance2.getGreeting();
+            assertNotNull(greeting2);
+
+            assertEquals(greeting1, greeting2);
+        });
+    }
+
+    @Test
+    public void testThreadScopedInRequestTwoTypes() {
+//        InjectionManager injectionManager = BindingTestHelper.createInjectionManager();
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindAsContract(RequestScopedCzech.class)
+//                    .in(RequestScoped.class);
+//
+//            binder.bindAsContract(RequestScopedEnglish.class)
+//                    .in(RequestScoped.class);
+//
+//            binder.bindFactory(new SupplierGreeting(CzechGreeting.GREETING))
+//                    .to(CzechGreeting.class)
+//                    .in(PerThread.class);
+//
+//            binder.bindFactory(new SupplierGreeting(EnglishGreeting.GREETING))
+//                    .to(EnglishGreeting.class)
+//                    .in(PerThread.class);
+//        });
+
+        RequestScope request = injectionManager.getInstance(RequestScope.class);
+        request.runInScope(() -> {
+            RequestScopedCzech2 instance1 = injectionManager.getInstance(RequestScopedCzech2.class);
+            CzechGreeting2 greeting1 = instance1.getGreeting();
+            assertNotNull(greeting1);
+
+            // Precisely the same object
+            RequestScopedEnglish2 instance2 = injectionManager.getInstance(RequestScopedEnglish2.class);
+            EnglishGreeting2 greeting2 = instance2.getGreeting();
+            assertNotNull(greeting2);
+
+            assertNotSame(greeting1, greeting2);
+        });
+    }
+
+    @Test
+    public void testThreadScopedInSingletonScope() {
+//        InjectionManager injectionManager = BindingTestHelper.createInjectionManager();
+//        BindingTestHelper.bind(injectionManager, binder -> {
+//            binder.bindAsContract(SingletonObject.class)
+//                    .in(Singleton.class);
+//
+//            binder.bindFactory(new SupplierGreeting())
+//                    .to(Greeting.class)
+//                    .in(PerThread.class);
+//        });
+
+        SingletonObject instance1 = injectionManager.getInstance(SingletonObject.class);
+        Greeting greeting1 = instance1.getGreeting();
+        assertNotNull(greeting1);
+
+        // Precisely the same object
+        SingletonObject instance2 = injectionManager.getInstance(SingletonObject.class);
+        Greeting greeting2 = instance2.getGreeting();
+        assertNotNull(greeting2);
+
+        assertEquals(greeting1, greeting2);
+    }
+
+    @RequestScoped
+    public static class RequestScopedInterface {
+
+        @Inject
+        Greeting greeting;
+
+        public Greeting getGreeting() {
+            return greeting;
+        }
+    }
+
+    @RequestScoped
+    public static class RequestScopedCzech {
+
+        @Inject
+        CzechGreeting greeting;
+
+        public CzechGreeting getGreeting() {
+            return greeting;
+        }
+    }
+
+    @Singleton
+    public static class SingletonObject {
+
+        @Inject
+        Greeting greeting;
+
+        public Greeting getGreeting() {
+            return greeting;
+        }
+    }
+
+    @RequestScoped
+    public static class RequestScopedCzech2 {
+
+        @Inject
+        CzechGreeting2 greeting;
+
+        public CzechGreeting2 getGreeting() {
+            return greeting;
+        }
+    }
+
+    @RequestScoped
+    public static class RequestScopedEnglish2 {
+
+        @Inject
+        EnglishGreeting2 greeting;
+
+        public EnglishGreeting2 getGreeting() {
+            return greeting;
+        }
+    }
+
+    @Vetoed
+    static class SupplierGreeting2 implements Supplier<Greeting2> {
+
+        private final String greetingType;
+
+        /**
+         * Default constructor.
+         */
+        public SupplierGreeting2() {
+            this(CzechGreeting.GREETING);
+        }
+
+        /**
+         * Supplier's constructor.
+         *
+         * @param greetingType greetingType in a specific language.
+         */
+        public SupplierGreeting2(String greetingType) {
+            this.greetingType = greetingType;
+        }
+
+        @Override
+        public Greeting2 get() {
+            if (CzechGreeting2.GREETING.equals(greetingType)) {
+                return new CzechGreeting2();
+            } else {
+                return new EnglishGreeting2();
+            }
+        }
+    }
+
+    @Vetoed
+    static class CzechGreeting2 implements Greeting2 {
+
+        static final String GREETING = "Ahoj";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public String toString() {
+            return "CzechGreeting";
+        }
+    }
+
+    @Vetoed
+    static class EnglishGreeting2 implements Greeting2 {
+
+        static final String GREETING = "Hello";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public String toString() {
+            return "EnglishGreeting";
+        }
+    }
+
+    @Vetoed
+    static class SupplierGreeting implements Supplier<Greeting> {
+
+        private final String greetingType;
+
+        /**
+         * Default constructor.
+         */
+        public SupplierGreeting() {
+            this(CzechGreeting.GREETING);
+        }
+
+        /**
+         * Supplier's constructor.
+         *
+         * @param greetingType greetingType in a specific language.
+         */
+        public SupplierGreeting(String greetingType) {
+            this.greetingType = greetingType;
+        }
+
+        @Override
+        public Greeting get() {
+            if (CzechGreeting.GREETING.equals(greetingType)) {
+                return new CzechGreeting();
+            } else {
+                return new EnglishGreeting();
+            }
+        }
+    }
+
+    @Vetoed
+    static class EnglishGreeting implements Greeting {
+
+        static final String GREETING = "Hello";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public String toString() {
+            return "EnglishGreeting";
+        }
+    }
+
+    @Vetoed
+    static class CzechGreeting implements Greeting {
+
+        static final String GREETING = "Ahoj";
+
+        @Override
+        public String getGreeting() {
+            return GREETING + "#" + Thread.currentThread().getName();
+        }
+
+        @Override
+        public String toString() {
+            return "CzechGreeting";
+        }
+    }
+
+    @FunctionalInterface
+    static interface Greeting2 {
+        String getGreeting();
+    }
+
+    @FunctionalInterface
+    static interface Greeting {
+        String getGreeting();
+    }
+}
diff --git a/incubator/cdi-inject-weld/src/test/resources/META-INF/beans.xml b/incubator/cdi-inject-weld/src/test/resources/META-INF/beans.xml
new file mode 100644
index 0000000..678e3dc
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<beans  bean-discovery-mode="annotated" />
diff --git a/incubator/cdi-inject-weld/src/test/resources/META-INF/services/org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization b/incubator/cdi-inject-weld/src/test/resources/META-INF/services/org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization
new file mode 100644
index 0000000..7909bcf
--- /dev/null
+++ b/incubator/cdi-inject-weld/src/test/resources/META-INF/services/org.glassfish.jersey.inject.weld.spi.BootstrapPreinitialization
@@ -0,0 +1,17 @@
+
+# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0, which is available at
+# http://www.eclipse.org/legal/epl-2.0.
+#
+# This Source Code may also be made available under the following Secondary
+# Licenses when the conditions for such availability set forth in the
+# Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+# version 2 with the GNU Classpath Exception, which is available at
+# https://www.gnu.org/software/classpath/license.html.
+#
+# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+#
+
+org.glassfish.jersey.inject.weld.internal.managed.TestPreinitialization
\ No newline at end of file
diff --git a/incubator/pom.xml b/incubator/pom.xml
index fd6b57b..930f5f8 100644
--- a/incubator/pom.xml
+++ b/incubator/pom.xml
@@ -36,6 +36,7 @@
     </description>
 
     <modules>
+        <module>cdi-inject-weld</module>
         <module>declarative-linking</module>
         <module>gae-integration</module>
         <module>html-json</module>
diff --git a/tests/e2e-inject/cdi-inject-weld/pom.xml b/tests/e2e-inject/cdi-inject-weld/pom.xml
new file mode 100644
index 0000000..60690bf
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/pom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.glassfish.jersey.tests</groupId>
+        <artifactId>e2e-inject</artifactId>
+        <version>2.35-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>e2e-inject-cdi-inject-weld</artifactId>
+    <packaging>jar</packaging>
+    <name>jersey-tests-e2e-inject-cdi-inject-weld</name>
+
+    <description>Jersey E2E Inject CDI SE tests</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>jakarta.enterprise</groupId>
+            <artifactId>jakarta.enterprise.cdi-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.weld.se</groupId>
+            <artifactId>weld-se-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.incubator</groupId>
+            <artifactId>jersey-cdi-inject-weld</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-bundle</artifactId>
+            <type>pom</type>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.glassfish.jersey.media</groupId>
+                    <artifactId>jersey-media-jaxb</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>jakarta.xml.bind</groupId>
+                    <artifactId>jakarta.xml.bind-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-util</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-library</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Account.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Account.java
new file mode 100644
index 0000000..c09845a
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Account.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+
+/**
+ * Keeps current state of money.
+ *
+ * @author Petr Bouda
+ */
+@ApplicationScoped
+public class Account {
+
+    private long current = 0;
+
+    public void observeCredit(@Observes @Credit Long amount) {
+        current += amount;
+    }
+
+    public void observeDebit(@Observes @Debit Long amount) {
+        current -= amount;
+    }
+
+    public long getCurrent() {
+        return current;
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/AccountResource.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/AccountResource.java
new file mode 100644
index 0000000..49ef2a9
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/AccountResource.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+
+import javax.enterprise.event.Event;
+import javax.inject.Inject;
+
+/**
+ * Testing resource for CDI events.
+ *
+ * @author Petr Bouda
+ */
+@Path("account")
+public class AccountResource {
+
+    @Inject
+    @Credit
+    private Event<Long> creditEvent;
+
+    @Inject
+    @Debit
+    private Event<Long> debitEvent;
+
+    @Inject
+    private Account account;
+
+    @POST
+    public void credit(@QueryParam("amount") long amount) {
+        creditEvent.fire(amount);
+    }
+
+    @DELETE
+    public void debit(@QueryParam("amount") long amount) {
+        debitEvent.fire(amount);
+    }
+
+    @GET
+    public long current() {
+        return account.getCurrent();
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Credit.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Credit.java
new file mode 100644
index 0000000..14ed675
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Credit.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Event qualifier.
+ *
+ * @author Petr Bouda
+ */
+@Qualifier
+@Target({METHOD, FIELD, PARAMETER, TYPE})
+@Retention(RUNTIME)
+public @interface Credit {
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Debit.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Debit.java
new file mode 100644
index 0000000..56d60d9
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Debit.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Event qualifier.
+ *
+ * @author Petr Bouda
+ */
+@Qualifier
+@Target({METHOD, FIELD, PARAMETER, TYPE})
+@Retention(RUNTIME)
+public @interface Debit {
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Hello.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Hello.java
new file mode 100644
index 0000000..8d9fc45
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Hello.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+/**
+ * Interface used to activate decorator.
+ *
+ * @author Petr Bouda
+ */
+public interface Hello {
+
+    String hello();
+
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/HelloResource.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/HelloResource.java
new file mode 100644
index 0000000..512506f
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/HelloResource.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import javax.inject.Inject;
+import org.glassfish.jersey.tests.e2e.inject.cdi.weld.subresources.MyBean;
+
+/**
+ * Intercepted and decorated resource.
+ *
+ * @author Petr Bouda
+ */
+@Secured
+@Path("intercepted")
+public class HelloResource implements Hello {
+
+    @Inject
+    private NameService service;
+
+    @Inject
+    MyBean mybean;
+
+    @GET
+    @Override
+    public String hello() {
+        System.out.println(mybean.hello());
+        return "Hello " + service.getName();
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/HelloStarDecorator.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/HelloStarDecorator.java
new file mode 100644
index 0000000..cbd3ad7
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/HelloStarDecorator.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.decorator.Decorator;
+import javax.decorator.Delegate;
+import javax.enterprise.inject.Any;
+import javax.inject.Inject;
+
+/**
+ * Decorator wraps the hello resource by stars.
+ *
+ * @author Petr Bouda
+ */
+@Decorator
+public class HelloStarDecorator implements Hello {
+
+    @Inject
+    @Delegate
+    @Any
+    Hello account;
+
+    @Override
+    public String hello() {
+        return "***" + account.hello() + "***";
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/JaxrsService.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/JaxrsService.java
new file mode 100644
index 0000000..2847170
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/JaxrsService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+
+import javax.enterprise.context.ApplicationScoped;
+
+/**
+ * Holder for JAX-RS information to inject them into interceptor. JAX-RS does not work in interceptor.
+ *
+ * @author Petr Bouda
+ */
+@ApplicationScoped
+public class JaxrsService {
+
+    @Context
+    private UriInfo uriInfo;
+
+    public UriInfo getUriInfo() {
+        return uriInfo;
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/NameService.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/NameService.java
new file mode 100644
index 0000000..5205ffb
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/NameService.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.enterprise.context.ApplicationScoped;
+
+/**
+ * Service returning the name.
+ *
+ * @author Petr Bouda
+ */
+@ApplicationScoped
+public class NameService {
+
+    public static final String NAME = "James";
+
+    public String getName() {
+       return NAME;
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Secured.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Secured.java
new file mode 100644
index 0000000..f3971ea
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/Secured.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.interceptor.InterceptorBinding;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Security annotation bound to {@link SecurityInterceptor}.
+ *
+ * @author Petr Bouda
+ */
+@Inherited
+@InterceptorBinding
+@Retention(RUNTIME)
+@Target({ METHOD, TYPE })
+public @interface Secured {
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/SecurityInterceptor.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/SecurityInterceptor.java
new file mode 100644
index 0000000..a2e3966
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/SecurityInterceptor.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.core.MultivaluedMap;
+
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+/**
+ * Interceptor checking James as a user in query params.
+ *
+ * @author Petr Bouda
+ */
+@Secured
+@Interceptor
+public class SecurityInterceptor {
+
+    @Inject
+    NameService nameService;
+
+    @Inject
+    JaxrsService jaxrsService;
+
+    @AroundInvoke
+    public Object logMethodEntry(InvocationContext ctx) throws Exception {
+        MultivaluedMap<String, String> params = jaxrsService.getUriInfo().getQueryParameters();
+        String user = params.getFirst("user");
+
+        if (nameService.getName().equals(user)) {
+            return ctx.proceed();
+        } else {
+            throw new ForbiddenException("Forbidden resource for the user: " + user);
+        }
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/ApplicationCounterBean.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/ApplicationCounterBean.java
new file mode 100644
index 0000000..9835419
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/ApplicationCounterBean.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.scopes;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.enterprise.context.ApplicationScoped;
+
+/**
+ * Request counter.
+ *
+ * @author Petr Bouda
+ */
+@ApplicationScoped
+public class ApplicationCounterBean {
+
+    private AtomicInteger counter = new AtomicInteger();
+
+    public int getNumber() {
+        return counter.incrementAndGet();
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/RequestScopedResource.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/RequestScopedResource.java
new file mode 100644
index 0000000..1e24e8d
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/RequestScopedResource.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.scopes;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+
+import javax.inject.Inject;
+
+import org.glassfish.jersey.process.internal.RequestScoped;
+
+/**
+ * Request scoped resource.
+ *
+ * @author Petr Bouda
+ */
+@RequestScoped
+@Path("request")
+public class RequestScopedResource {
+
+    @Inject
+    private ApplicationCounterBean application;
+
+    @PathParam("name")
+    private String name;
+
+    private UriInfo uriInfo;
+
+    public RequestScopedResource(@Context UriInfo uriInfo) {
+        this.uriInfo = uriInfo;
+    }
+
+    @GET
+    @Path("{name}")
+    @Produces("text/plain")
+    public String getHello() {
+        return "Hello_" + name + " [" + application.getNumber() + "] " + "[" + uriInfo.getPath() + "] " + this;
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/SingletonScopedResource.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/SingletonScopedResource.java
new file mode 100644
index 0000000..ed32ad1
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/SingletonScopedResource.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.scopes;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Singleton Resource.
+ *
+ * @author Petr Bouda
+ */
+@Singleton
+@Path("singleton")
+public class SingletonScopedResource {
+
+    @Inject
+    private ApplicationCounterBean application;
+
+    @Context
+    private UriInfo uriInfo;
+
+    @GET
+    @Path("{name}")
+    @Produces("text/plain")
+    public String getHello(@PathParam("name") String name) {
+        return "Hello_" + name + " [" + application.getNumber() + "] " + "[" + uriInfo.getPath() + "] " + this;
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/ModelProcessorFeature.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/ModelProcessorFeature.java
new file mode 100644
index 0000000..7eb9357
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/ModelProcessorFeature.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.subresources;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+
+import javax.annotation.Priority;
+import javax.inject.Singleton;
+
+import org.glassfish.jersey.process.Inflector;
+import org.glassfish.jersey.process.internal.RequestScoped;
+import org.glassfish.jersey.server.model.ModelProcessor;
+import org.glassfish.jersey.server.model.Resource;
+import org.glassfish.jersey.server.model.ResourceModel;
+
+@ApplicationScoped
+public class ModelProcessorFeature implements Feature {
+
+    @Override
+    public boolean configure(FeatureContext context) {
+        context.register(SimpleModelProcessor.class);
+        return true;
+    }
+
+    @Priority(5000)
+    public static class SimpleModelProcessor implements ModelProcessor {
+
+        @Override
+        public ResourceModel processResourceModel(ResourceModel resourceModel, Configuration configuration) {
+            ResourceModel.Builder builder = new ResourceModel.Builder(resourceModel.getRootResources(), false);
+            final Resource singletonResource = Resource.from(SingletonResource.class);
+            builder.addResource(singletonResource);
+
+            final Resource requestScopeResource = Resource.from(RequestScopeResource.class);
+            builder.addResource(requestScopeResource);
+
+            final Resource.Builder resourceBuilder = Resource.builder("instance");
+            resourceBuilder.addMethod("GET").handledBy(new SimpleModelProcessorInflector());
+            final Resource instanceResource = resourceBuilder.build();
+
+            builder.addResource(instanceResource);
+
+            return builder.build();
+        }
+
+        @Override
+        public ResourceModel processSubResource(ResourceModel subResource, Configuration configuration) {
+            final Resource resource = Resource.builder()
+                    .mergeWith(Resource.from(EnhancedSubResourceSingleton.class))
+                    .mergeWith(Resource.from(EnhancedSubResource.class))
+                    .mergeWith(subResource.getResources().get(0)).build();
+
+            return new ResourceModel.Builder(true).addResource(resource).build();
+        }
+
+        @Priority(5000)
+        private static class SimpleModelProcessorInflector implements Inflector<ContainerRequestContext, String> {
+            private int counter = 0;
+
+            @Override
+            public String apply(ContainerRequestContext containerRequestContext) {
+                return String.valueOf("Inflector:" + counter++);
+            }
+        }
+    }
+
+    @Singleton
+    public static class EnhancedSubResourceSingleton {
+        private int counter = 0;
+
+        @GET
+        @Path("enhanced-singleton")
+        public String get() {
+            return "EnhancedSubResourceSingleton:" + String.valueOf(counter++);
+        }
+    }
+
+    @RequestScoped
+    public static class EnhancedSubResource {
+
+        private int counter = 0;
+
+        @GET
+        @Path("enhanced")
+        public String get() {
+            return String.valueOf("EnhancedSubResource:" + counter++);
+        }
+    }
+
+    @Path("request-scope")
+    public static class RequestScopeResource {
+        private int counter = 0;
+
+        @GET
+        public String get() {
+            return String.valueOf("RequestScopeResource:" + counter++);
+        }
+    }
+
+    @Path("singleton")
+    @Singleton
+    public static class SingletonResource {
+        private int counter = 0;
+
+        @GET
+        public String get() {
+            return String.valueOf("SingletonResource:" + counter++);
+        }
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/MyBean.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/MyBean.java
new file mode 100644
index 0000000..29127df
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/MyBean.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.subresources;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import org.glassfish.jersey.tests.e2e.inject.cdi.weld.Hello;
+import org.glassfish.jersey.tests.e2e.inject.cdi.weld.NameService;
+import org.glassfish.jersey.tests.e2e.inject.cdi.weld.Secured;
+
+@ApplicationScoped
+@Secured
+public class MyBean implements Hello {
+    @Inject
+    private NameService service;
+
+    public String hello() {
+        System.out.println("mybean");
+        return "Hello " + service.getName();
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/RootResource.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/RootResource.java
new file mode 100644
index 0000000..00d4922
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/RootResource.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.subresources;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+@Path("root")
+public class RootResource {
+
+    @GET
+    public String get() {
+        return "root";
+    }
+
+    @Path("sub-resource-singleton")
+    public Class<SubResourceSingleton> getSubResourceSingleton() {
+        return SubResourceSingleton.class;
+    }
+
+    @Path("sub-resource-instance")
+    public SubResourceSingleton getSubResourceSingletonInstance() {
+        return new SubResourceSingleton();
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/RootSingletonResource.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/RootSingletonResource.java
new file mode 100644
index 0000000..14b2734
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/RootSingletonResource.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.subresources;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import javax.inject.Singleton;
+
+@Path("root-singleton")
+@Singleton
+public class RootSingletonResource {
+
+    private int counter = 0;
+
+    @GET
+    public String get() {
+        return "RootSingletonResource:" + String.valueOf(counter++);
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/SubResourceSingleton.java b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/SubResourceSingleton.java
new file mode 100644
index 0000000..aacd442
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/SubResourceSingleton.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.subresources;
+
+import javax.ws.rs.GET;
+
+import javax.inject.Singleton;
+
+@Singleton
+public class SubResourceSingleton {
+
+    private int counter = 0;
+
+    @GET
+    public String get() {
+        return String.valueOf("SubResourceSingleton:" + counter++);
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/main/resources/META-INF/beans.xml b/tests/e2e-inject/cdi-inject-weld/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..ee4acc6
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+                           http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+       bean-discovery-mode="all">
+    <interceptors>
+        <class>org.glassfish.jersey.tests.e2e.inject.cdi.weld.SecurityInterceptor</class>
+    </interceptors>
+    <decorators>
+        <class>org.glassfish.jersey.tests.e2e.inject.cdi.weld.HelloStarDecorator</class>
+    </decorators>
+</beans>
diff --git a/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/EventsTest.java b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/EventsTest.java
new file mode 100644
index 0000000..4c0cb29
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/EventsTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+
+import org.jboss.weld.environment.se.Weld;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests that the resource can fire an event.
+ *
+ * @author Petr Bouda
+ */
+public class EventsTest extends JerseyTest {
+
+    private Weld weld;
+
+    @Before
+    public void setup() {
+        Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy());
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        if (Hk2InjectionManagerFactory.isImmediateStrategy()) {
+            weld = new Weld();
+            weld.initialize();
+            super.setUp();
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (Hk2InjectionManagerFactory.isImmediateStrategy()) {
+            weld.shutdown();
+            super.tearDown();
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(AccountResource.class);
+    }
+
+    @Test
+    public void testFiredEvents() {
+        Response credit = target("account").queryParam("amount", 50).request().post(Entity.json(""));
+        assertEquals(204, credit.getStatus());
+
+        Response debit = target("account").queryParam("amount", 25).request().delete();
+        assertEquals(204, debit.getStatus());
+
+        Long current = target("account").queryParam("amount", 25).request().get(Long.class);
+        assertEquals(25, current.longValue());
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/InterceptorDecoratorTest.java b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/InterceptorDecoratorTest.java
new file mode 100644
index 0000000..a7752bd
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/InterceptorDecoratorTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+
+import org.jboss.weld.environment.se.Weld;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests that the resource can be intercepted and decorated.
+ *
+ * @author Petr Bouda
+ */
+public class InterceptorDecoratorTest extends JerseyTest {
+
+    private Weld weld;
+
+    @Before
+    public void setup() {
+        Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy());
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        if (Hk2InjectionManagerFactory.isImmediateStrategy()) {
+            weld = new Weld();
+            weld.initialize();
+            super.setUp();
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (Hk2InjectionManagerFactory.isImmediateStrategy()) {
+            weld.shutdown();
+            super.tearDown();
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(HelloResource.class);
+    }
+
+    @Test
+    public void testInterceptedGet() {
+        String intercepted = target("intercepted").queryParam("user", NameService.NAME).request().get(String.class);
+        assertEquals("***Hello James***", intercepted);
+    }
+
+    @Test
+    public void testForbiddenGet() {
+        Response result = target("intercepted").queryParam("user", "unknown").request().get();
+        assertEquals(403, result.getStatus());
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/RequestContextBuilder.java b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/RequestContextBuilder.java
new file mode 100644
index 0000000..d4cc5c5
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/RequestContextBuilder.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.WriterInterceptor;
+
+import org.glassfish.jersey.internal.MapPropertiesDelegate;
+import org.glassfish.jersey.internal.PropertiesDelegate;
+import org.glassfish.jersey.message.MessageBodyWorkers;
+import org.glassfish.jersey.message.internal.HeaderUtils;
+import org.glassfish.jersey.server.ContainerRequest;
+
+/**
+ * Used by tests to create mock JerseyContainerRequestContext instances.
+ *
+ * @author Martin Matula
+ */
+public class RequestContextBuilder {
+
+    public class TestContainerRequest extends ContainerRequest {
+
+        private Object entity;
+        private GenericType entityType;
+        private final PropertiesDelegate propertiesDelegate;
+
+        public TestContainerRequest(final URI baseUri,
+                                    final URI requestUri,
+                                    final String method,
+                                    final SecurityContext securityContext,
+                                    final PropertiesDelegate propertiesDelegate) {
+            super(baseUri, requestUri, method, securityContext, propertiesDelegate, null);
+            this.propertiesDelegate = propertiesDelegate;
+        }
+
+        public void setEntity(final Object entity) {
+            if (entity instanceof GenericEntity) {
+                this.entity = ((GenericEntity) entity).getEntity();
+                this.entityType = new GenericType(((GenericEntity) entity).getType());
+            } else {
+                this.entity = entity;
+                this.entityType = new GenericType(entity.getClass());
+            }
+        }
+
+        @Override
+        public void setWorkers(final MessageBodyWorkers workers) {
+            super.setWorkers(workers);
+            final byte[] entityBytes;
+            if (entity != null) {
+                final MultivaluedMap<String, Object> myMap = new MultivaluedHashMap<String, Object>(getHeaders());
+                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                OutputStream stream = null;
+                try {
+                    stream = workers.writeTo(entity, entity.getClass(), entityType.getType(),
+                            new Annotation[0], getMediaType(),
+                            myMap,
+                            propertiesDelegate, baos, Collections.<WriterInterceptor>emptyList());
+                } catch (final IOException | WebApplicationException ex) {
+                    Logger.getLogger(TestContainerRequest.class.getName()).log(Level.SEVERE, null, ex);
+                } finally {
+                    if (stream != null) {
+                        try {
+                            stream.close();
+                        } catch (final IOException e) {
+                            // ignore
+                        }
+                    }
+                }
+                entityBytes = baos.toByteArray();
+            } else {
+                entityBytes = new byte[0];
+            }
+            setEntityStream(new ByteArrayInputStream(entityBytes));
+        }
+    }
+
+    private final TestContainerRequest request;
+
+    public static RequestContextBuilder from(final String requestUri, final String method) {
+        return from(null, requestUri, method);
+    }
+
+    public static RequestContextBuilder from(final String baseUri, final String requestUri, final String method) {
+        return new RequestContextBuilder(baseUri, requestUri, method);
+    }
+
+    public static RequestContextBuilder from(final URI requestUri, final String method) {
+        return from(null, requestUri, method);
+    }
+
+    public static RequestContextBuilder from(final URI baseUri, final URI requestUri, final String method) {
+        return new RequestContextBuilder(baseUri, requestUri, method);
+    }
+
+    private RequestContextBuilder(final String baseUri, final String requestUri, final String method) {
+        this(baseUri == null || baseUri.isEmpty() ? null : URI.create(baseUri), URI.create(requestUri), method);
+    }
+
+    private RequestContextBuilder(final URI baseUri, final URI requestUri, final String method) {
+        request = new TestContainerRequest(baseUri, requestUri, method, null,
+                new MapPropertiesDelegate());
+    }
+
+    public ContainerRequest build() {
+        return request;
+    }
+
+    public RequestContextBuilder accept(final String... acceptHeader) {
+        putHeaders(HttpHeaders.ACCEPT, acceptHeader);
+        return this;
+    }
+
+    public RequestContextBuilder accept(final MediaType... acceptHeader) {
+        putHeaders(HttpHeaders.ACCEPT, (Object[]) acceptHeader);
+        return this;
+    }
+
+    public RequestContextBuilder entity(final Object entity) {
+        request.setEntity(entity);
+        return this;
+    }
+
+    public RequestContextBuilder type(final String contentType) {
+        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, contentType);
+        return this;
+
+    }
+
+    public RequestContextBuilder type(final MediaType contentType) {
+        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HeaderUtils.asString(contentType, request.getConfiguration()));
+        return this;
+    }
+
+    public RequestContextBuilder header(final String name, final Object value) {
+        putHeader(name, value);
+        return this;
+    }
+
+    public RequestContextBuilder cookie(final Cookie cookie) {
+        putHeader(HttpHeaders.COOKIE, cookie);
+        return this;
+    }
+
+    public RequestContextBuilder cookies(final Cookie... cookies) {
+        putHeaders(HttpHeaders.COOKIE, (Object[]) cookies);
+        return this;
+    }
+
+    private void putHeader(final String name, final Object value) {
+        if (value == null) {
+            request.getHeaders().remove(name);
+            return;
+        }
+        request.header(name, HeaderUtils.asString(value, request.getConfiguration()));
+    }
+
+    private void putHeaders(final String name, final Object... values) {
+        if (values == null) {
+            request.getHeaders().remove(name);
+            return;
+        }
+        request.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), request.getConfiguration()));
+    }
+
+    private void putHeaders(final String name, final String... values) {
+        if (values == null) {
+            request.getHeaders().remove(name);
+            return;
+        }
+        request.getHeaders().addAll(name, values);
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/ScopesTest.java b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/ScopesTest.java
new file mode 100644
index 0000000..9f7522b
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/scopes/ScopesTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.scopes;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+
+import org.jboss.weld.environment.se.Weld;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Tests CDI resources.
+ */
+public class ScopesTest extends JerseyTest {
+
+    private Weld weld;
+
+    @Override
+    public void setUp() throws Exception {
+        weld = new Weld();
+        weld.initialize();
+        super.setUp();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        weld.shutdown();
+        super.tearDown();
+    }
+
+    @Override
+    protected ResourceConfig configure() {
+        return new ResourceConfig(RequestScopedResource.class, SingletonScopedResource.class);
+    }
+
+    @Test
+    public void testCheckRequest() throws InterruptedException {
+        String[] response1 = target().path("request").path("James").request().get(String.class).split(" ");
+        String[] response2 = target().path("request").path("Marcus").request().get(String.class).split(" ");
+        assertResponses("request", response1, response2);
+        assertNotEquals(response1[3], response2[3]);
+    }
+
+    @Test
+    public void testCheckSingleton() throws InterruptedException {
+        String[] response1 = target().path("singleton").path("James").request().get(String.class).split(" ");
+        String[] response2 = target().path("singleton").path("Marcus").request().get(String.class).split(" ");
+        assertResponses("singleton", response1, response2);
+        assertEquals(response1[3], response2[3]);
+    }
+
+    private void assertResponses(String type, String[] response1, String[] response2) {
+        assertEquals("Hello_James", response1[0]);
+        assertEquals("[1]", response1[1]);
+        assertEquals("[" + type + "/James]", response1[2]);
+
+        assertEquals("Hello_Marcus", response2[0]);
+        assertEquals("[2]", response2[1]);
+        assertEquals("[" + type + "/Marcus]", response2[2]);
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/ModelProcessorScopeTest.java b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/ModelProcessorScopeTest.java
new file mode 100644
index 0000000..a26cb29
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/weld/subresources/ModelProcessorScopeTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.inject.cdi.weld.subresources;
+
+import java.util.concurrent.ExecutionException;
+
+import org.glassfish.jersey.server.ApplicationHandler;
+import org.glassfish.jersey.server.ContainerResponse;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.tests.e2e.inject.cdi.weld.RequestContextBuilder;
+
+import org.jboss.weld.environment.se.Weld;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test scope of resources enhanced by model processors.
+ *
+ * @author Miroslav Fuksa
+ *
+ */
+public class ModelProcessorScopeTest {
+
+    private Weld weld;
+
+    @Before
+    public void setUp() throws Exception {
+        weld = new Weld();
+        weld.initialize();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        weld.shutdown();
+    }
+
+    private void _testCounter(ApplicationHandler applicationHandler, String requestUri, final String prefix,
+                              final String expectedSecondHit) throws
+            InterruptedException, ExecutionException {
+        ContainerResponse response = applicationHandler.apply(RequestContextBuilder.from(requestUri,
+                "GET").build()).get();
+        assertEquals(200, response.getStatus());
+        assertEquals(prefix + ":0", response.getEntity());
+        response = applicationHandler.apply(RequestContextBuilder.from(requestUri,
+                "GET").build()).get();
+        assertEquals(prefix + ":" + expectedSecondHit, response.getEntity());
+    }
+
+    @Test
+    public void testSingleton() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(ModelProcessorFeature
+                .SingletonResource.class));
+        final String requestUri = "/singleton";
+        _testCounter(applicationHandler, requestUri, "SingletonResource", "1");
+    }
+
+    @Test
+    public void testSingletonInModelProcessor() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class,
+                ModelProcessorFeature.class));
+        final String requestUri = "/singleton";
+        _testCounter(applicationHandler, requestUri, "SingletonResource", "1");
+    }
+
+    @Test
+    public void testSubResourceSingletonInOriginalModel() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class));
+        final String requestUri = "/root/sub-resource-singleton";
+        _testCounter(applicationHandler, requestUri, "SubResourceSingleton", "1");
+    }
+
+    @Test
+    public void testSubResourceEnhancedSingleton() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class));
+        final String requestUri = "/root/sub-resource-singleton/enhanced-singleton";
+        _testCounter(applicationHandler, requestUri, "EnhancedSubResourceSingleton", "1");
+    }
+
+    @Test
+    public void testSubResourceInstanceEnhancedSingleton() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class));
+        final String requestUri = "/root/sub-resource-instance/enhanced-singleton";
+        _testCounter(applicationHandler, requestUri, "EnhancedSubResourceSingleton", "1");
+    }
+
+    @Test
+    public void testSubResourceInstanceEnhancedSubResource() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class));
+        final String requestUri = "/root/sub-resource-instance/enhanced";
+        _testCounter(applicationHandler, requestUri, "EnhancedSubResource", "0");
+    }
+
+    @Test
+    public void testSubResourceEnhancedSubResource() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class));
+        final String requestUri = "/root/sub-resource-singleton/enhanced";
+        _testCounter(applicationHandler, requestUri, "EnhancedSubResource", "0");
+    }
+
+    @Test
+    public void testInstanceInModelProcessor() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class,
+                ModelProcessorFeature.class));
+        final String requestUri = "/instance";
+        _testCounter(applicationHandler, requestUri, "Inflector", "1");
+    }
+
+    @Test
+    public void testRootSingleton() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class,
+                RootSingletonResource.class));
+        final String requestUri = "/root-singleton";
+        _testCounter(applicationHandler, requestUri, "RootSingletonResource", "1");
+    }
+
+    @Test
+    public void testRequestScopeResource() throws ExecutionException, InterruptedException {
+        ApplicationHandler applicationHandler = new ApplicationHandler(new ResourceConfig(RootResource.class,
+                RootSingletonResource.class, ModelProcessorFeature.class));
+        final String requestUri = "/request-scope";
+        _testCounter(applicationHandler, requestUri, "RequestScopeResource", "0");
+    }
+}
diff --git a/tests/e2e-inject/cdi-inject-weld/src/test/resources/surefire.policy b/tests/e2e-inject/cdi-inject-weld/src/test/resources/surefire.policy
new file mode 100644
index 0000000..a6cc723
--- /dev/null
+++ b/tests/e2e-inject/cdi-inject-weld/src/test/resources/surefire.policy
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+// we do not care about java lib itself
+grant codebase "file:${java.home}/-" {
+  permission java.security.AllPermission;
+};
+
+// we do not care about our dependencies
+grant codebase "file:${settings.localRepository}/-" {
+  permission java.security.AllPermission;
+};
+
+// this is to be able to set runtime delegate instance in jax-rs from the tests
+// and to run multi-threaded tests
+grant codebase "file:${project.build.directory}/test-classes/-" {
+  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+  permission java.lang.RuntimePermission "modifyThread";
+  permission java.util.PropertyPermission "*", "write";
+  permission java.lang.RuntimePermission "getClassLoader";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.misc.*";
+  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+};
+
+grant codebase "file:${project.build.directory}/classes/-" {
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
+  permission java.lang.RuntimePermission "accessDeclaredMembers";
+  permission java.lang.RuntimePermission "getClassLoader";
+  permission java.lang.RuntimePermission "modifyThread";
+  permission java.util.PropertyPermission "*", "read";
+  permission java.io.FilePermission "<<ALL FILES>>", "read";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.misc.*";
+  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+};
diff --git a/tests/e2e-inject/pom.xml b/tests/e2e-inject/pom.xml
index 142e17b..adab97d 100644
--- a/tests/e2e-inject/pom.xml
+++ b/tests/e2e-inject/pom.xml
@@ -34,6 +34,7 @@
 
     <modules>
         <module>cdi2-se</module>
+        <module>cdi-inject-weld</module>
         <module>hk2</module>
     </modules>
 </project>
diff --git a/tests/integration/cdi-integration/context-inject-on-server/pom.xml b/tests/integration/cdi-integration/context-inject-on-server/pom.xml
index 38b31ca..f405087 100644
--- a/tests/integration/cdi-integration/context-inject-on-server/pom.xml
+++ b/tests/integration/cdi-integration/context-inject-on-server/pom.xml
@@ -57,24 +57,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.glassfish.jersey.ext.cdi</groupId>
-            <artifactId>jersey-weld2-se</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.jboss.weld.se</groupId>
             <artifactId>weld-se-core</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.glassfish.jersey.ext.cdi</groupId>
-            <artifactId>jersey-cdi1x</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.glassfish.jersey.ext.cdi</groupId>
-            <artifactId>jersey-cdi-rs-inject</artifactId>
-        </dependency>
-        <dependency>
+       <dependency>
             <groupId>org.glassfish.jersey.media</groupId>
             <artifactId>jersey-media-sse</artifactId>
         </dependency>
@@ -83,4 +70,54 @@
             <artifactId>jersey-container-servlet-core</artifactId>
         </dependency>
     </dependencies>
+    <profiles>
+        <profile>
+            <id>DefaultInject</id>
+            <activation>
+                <property><name>!cdiInject</name></property>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.glassfish.jersey.ext.cdi</groupId>
+                    <artifactId>jersey-weld2-se</artifactId>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.glassfish.jersey.ext.cdi</groupId>
+                    <artifactId>jersey-cdi1x</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.glassfish.jersey.ext.cdi</groupId>
+                    <artifactId>jersey-cdi-rs-inject</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>CdiInjectWeld</id>
+            <activation>
+                <property><name>cdiInject</name></property>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.glassfish.jersey.incubator</groupId>
+                    <artifactId>jersey-cdi-inject-weld</artifactId>
+                    <version>${project.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <configuration>
+                            <testIncludes>
+                                <testInclude>org/glassfish/jersey/tests/cdi/inject/ScopedInjectionTest.java</testInclude>
+                            </testIncludes>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java
index fc6894a..5b4de38 100644
--- a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java
@@ -51,11 +51,11 @@
     @Inject
     protected HttpHeaders injectHttpHeaders;
 
-    @Context
-    ParamConverterProvider contextParamConverterProvider;
-
-    @Inject
-    ParamConverterProvider injectParamConverterProvider;
+//    @Context
+//    ParamConverterProvider contextParamConverterProvider;
+//
+//    @Inject
+//    ParamConverterProvider injectParamConverterProvider;
 
     @Context
     protected Providers contextProviders;
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java
index a326454..75a8ccb 100644
--- a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java
@@ -28,11 +28,11 @@
         StringBuilder stringBuilder = new StringBuilder();
         boolean injected = false;
 
-        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("injected")) {
+        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("inject")) {
             injected = checkInjected(stringBuilder);
         }
 
-        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("contexted")) {
+        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("context")) {
             injected = checkContexted(stringBuilder);
         }
 
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java
index 585f045..47a9afc 100644
--- a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java
@@ -28,11 +28,11 @@
         StringBuilder stringBuilder = new StringBuilder();
         boolean injected = false;
 
-        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("injected")) {
+        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("inject")) {
             injected = checkInjected(stringBuilder);
         }
 
-        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("contexted")) {
+        if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("context")) {
             injected = checkContexted(stringBuilder);
         }
 
diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java
index 29e11d8..6a546fb 100644
--- a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java
+++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java
@@ -55,11 +55,11 @@
     @Inject
     protected HttpHeaders injectHttpHeaders;
 
-    @Context
-    protected ParamConverterProvider contextParamConverterProvider;
-
-    @Inject
-    protected ParamConverterProvider injectParamConverterProvider;
+//    @Context
+//    protected ParamConverterProvider contextParamConverterProvider;
+//
+//    @Inject
+//    protected ParamConverterProvider injectParamConverterProvider;
 
     @Context
     protected PropertiesDelegate contextPropertiesDelegate;
@@ -140,7 +140,7 @@
         injected &= checkConfiguration(injectConfiguration, stringBuilder);
         injected &= InjectionChecker.checkHttpHeaders(injectHttpHeaders, stringBuilder);
         injected &= checkPropertiesDelegate(injectPropertiesDelegate, stringBuilder);
-        injected &= InjectionChecker.checkParamConverterProvider(injectParamConverterProvider, stringBuilder);
+//        injected &= InjectionChecker.checkParamConverterProvider(injectParamConverterProvider, stringBuilder);
         injected &= InjectionChecker.checkProviders(injectProviders, stringBuilder);
         injected &= InjectionChecker.checkRequest(injectRequest, stringBuilder);
         injected &= InjectionChecker.checkResourceContext(injectResourceContext, stringBuilder);
@@ -163,7 +163,7 @@
         injected &= checkApplication(contextApplication, stringBuilder);
         injected &= checkConfiguration(contextConfiguration, stringBuilder);
         injected &= InjectionChecker.checkHttpHeaders(contextHttpHeaders, stringBuilder);
-        injected &= InjectionChecker.checkParamConverterProvider(contextParamConverterProvider, stringBuilder);
+//        injected &= InjectionChecker.checkParamConverterProvider(contextParamConverterProvider, stringBuilder);
         injected &= checkPropertiesDelegate(contextPropertiesDelegate, stringBuilder);
         injected &= InjectionChecker.checkProviders(contextProviders, stringBuilder);
         injected &= InjectionChecker.checkRequest(contextRequest, stringBuilder);