Merge pull request #4838 from senivam/3x_merged

merge master into 3.x
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java
index 92750fc..43737f1 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java
@@ -43,6 +43,7 @@
 import org.glassfish.jersey.internal.BootstrapConfigurator;
 import org.glassfish.jersey.internal.ContextResolverFactory;
 import org.glassfish.jersey.internal.ExceptionMapperFactory;
+import org.glassfish.jersey.internal.FeatureConfigurator;
 import org.glassfish.jersey.internal.JaxrsProviders;
 import org.glassfish.jersey.internal.ServiceFinder;
 import org.glassfish.jersey.internal.inject.Bindings;
@@ -53,7 +54,6 @@
 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.glassfish.jersey.message.internal.MessageBodyFactory;
 import org.glassfish.jersey.model.internal.CommonConfig;
 import org.glassfish.jersey.model.internal.ComponentBag;
 import org.glassfish.jersey.model.internal.ManagedObjectsFinalizer;
@@ -429,7 +429,8 @@
                     new ExceptionMapperFactory.ExceptionMappersConfigurator(),
                     new JaxrsProviders.ProvidersConfigurator(),
                     new AutoDiscoverableConfigurator(RuntimeType.CLIENT),
-                    new ClientComponentConfigurator());
+                    new ClientComponentConfigurator(),
+                    new FeatureConfigurator(RuntimeType.CLIENT));
             bootstrapConfigurators.forEach(configurator -> configurator.init(injectionManager, bootstrapBag));
 
             // AutoDiscoverable.
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/JaxRsFeatureRegistrationClientTest.java b/core-client/src/test/java/org/glassfish/jersey/client/JaxRsFeatureRegistrationClientTest.java
new file mode 100644
index 0000000..f56bc26
--- /dev/null
+++ b/core-client/src/test/java/org/glassfish/jersey/client/JaxRsFeatureRegistrationClientTest.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.client;
+
+import org.glassfish.jersey.CommonProperties;
+import org.junit.Test;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.core.Feature;
+import jakarta.ws.rs.core.FeatureContext;
+import jakarta.ws.rs.core.Response;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class JaxRsFeatureRegistrationClientTest {
+
+    private static final String REGISTERED_FEATURE_RESPONSE = "RegisteredFeature";
+
+    private static final ClientRequestFilter component =
+            requestContext -> requestContext
+                    .abortWith(Response.status(400).entity(REGISTERED_FEATURE_RESPONSE).build());
+
+    public static class FeatureClientImpl implements Feature {
+
+        @Override
+        public boolean configure(FeatureContext context) {
+            if ("true".equals(context.getConfiguration().getProperty("runWithJaxRsClient"))) {
+                context.register(component);
+            }
+            return true;
+        }
+    }
+
+    @Test
+    public void featureRegistrationTest() {
+        final ClientConfig config = new ClientConfig().property("runWithJaxRsClient", "true");
+        final Client client = ClientBuilder.newClient(config);
+        final Invocation.Builder request = client.target("").request();
+
+        assertEquals(REGISTERED_FEATURE_RESPONSE, request.get().readEntity(String.class));
+
+        client.close();
+    }
+
+    @Test
+    public void featureNotRegistrationTest() {
+        final ClientConfig config = new ClientConfig()
+                .property(CommonProperties.JAXRS_SERVICE_LOADING_ENABLE, false);
+        final Client client = ClientBuilder.newClient(config);
+        final Invocation.Builder request = client.target("").request();
+
+        assertFalse(client.getConfiguration().isRegistered(FeatureClientImpl.class));
+
+        client.close();
+    }
+
+}
\ No newline at end of file
diff --git a/core-client/src/test/resources/META-INF/services/jakarta.ws.rs.core.Feature b/core-client/src/test/resources/META-INF/services/jakarta.ws.rs.core.Feature
new file mode 100644
index 0000000..99c6b86
--- /dev/null
+++ b/core-client/src/test/resources/META-INF/services/jakarta.ws.rs.core.Feature
@@ -0,0 +1 @@
+org.glassfish.jersey.client.JaxRsFeatureRegistrationClientTest$FeatureClientImpl
\ No newline at end of file
diff --git a/core-common/src/main/java/org/glassfish/jersey/AbstractFeatureConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/AbstractFeatureConfigurator.java
new file mode 100644
index 0000000..0e4be99
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/AbstractFeatureConfigurator.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+import org.glassfish.jersey.internal.AbstractServiceFinderConfigurator;
+import org.glassfish.jersey.internal.BootstrapBag;
+import org.glassfish.jersey.internal.ServiceFinder;
+import org.glassfish.jersey.internal.spi.AutoDiscoverable;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
+
+import jakarta.ws.rs.RuntimeType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public abstract class AbstractFeatureConfigurator<T> extends AbstractServiceFinderConfigurator<T> {
+    /**
+     * Create a new configurator.
+     *
+     * @param contract    contract of the service providers bound by this binder.
+     * @param runtimeType runtime (client or server) where the service finder binder is used.
+     */
+    protected AbstractFeatureConfigurator(Class contract, RuntimeType runtimeType) {
+        super(contract, runtimeType);
+    }
+
+    /**
+     * Specification specific implementation which allows find classes by specified classloader
+     *
+     * @param applicationProperties map of properties to check if search is allowed
+     * @param loader specific classloader (must not be NULL)
+     * @return list of found classes
+     */
+    protected List<Class<T>> loadImplementations(Map<String, Object> applicationProperties, ClassLoader loader) {
+        if (PropertiesHelper.isMetaInfServicesEnabled(applicationProperties, getRuntimeType())) {
+            return Stream.of(ServiceFinder.find(getContract(), loader, true).toClassArray())
+                    .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Allows feature registration as part of autoDiscoverables list
+     *
+     * @param features list of features to be registered
+     * @param bootstrapBag place where features are being registered
+     */
+    protected void registerFeatures(List<Class<T>> features,
+                                    BootstrapBag bootstrapBag) {
+        final List<AutoDiscoverable> autoDiscoverables = new ArrayList<>();
+
+        features.forEach(feature -> autoDiscoverables.add(registerClass(feature)));
+
+        bootstrapBag.getAutoDiscoverables().addAll(autoDiscoverables);
+    }
+
+    /**
+     * Register particular feature as an autoDiscoverable
+     *
+     * @param classToRegister class to be registered
+     * @param <T> type of class which is being registered
+     * @return initialized autoDiscoverable
+     */
+    private static <T> AutoDiscoverable registerClass(Class<T> classToRegister) {
+        return context -> {
+            if (!context.getConfiguration().isRegistered(classToRegister)) {
+                context.register(classToRegister, AutoDiscoverable.DEFAULT_PRIORITY);
+            }
+        };
+    }
+
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
index a05f199..6b2021d 100644
--- a/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
+++ b/core-common/src/main/java/org/glassfish/jersey/CommonProperties.java
@@ -245,6 +245,16 @@
      */
     public static final String PROVIDER_DEFAULT_DISABLE = "jersey.config.disableDefaultProvider";
 
+
+    /**
+     * Allows API services loading. If absent or true JAXRS services loading is allowed.
+     * Services shall implement Feature or DynamicFeature interface and be listed as SPI
+     * in user's application.
+     *
+     * @since 2.35
+     */
+    public static final String JAXRS_SERVICE_LOADING_ENABLE = "jakarta.ws.rs.loadServices";
+
     /**
      * Prevent instantiation.
      */
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
index 0f16119..ea7c62c 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -65,4 +65,22 @@
         }
         return Collections.emptyList();
     }
+
+    /**
+     * Mainly aimed to provide runtime type to abstract classes which extends this finder
+     *
+     * @return runtime type
+     */
+    protected RuntimeType getRuntimeType() {
+        return runtimeType;
+    }
+
+    /**
+     * Mainly aimed to provide contract class to abstract classes which extends this finder
+     *
+     * @return contract class
+     */
+    protected Class<T> getContract() {
+        return contract;
+    }
 }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/DynamicFeatureConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/internal/DynamicFeatureConfigurator.java
new file mode 100644
index 0000000..e17770e
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/DynamicFeatureConfigurator.java
@@ -0,0 +1,60 @@
+/*
+ * 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.internal;
+
+import org.glassfish.jersey.AbstractFeatureConfigurator;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
+
+import jakarta.ws.rs.RuntimeType;
+import jakarta.ws.rs.container.DynamicFeature;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Registers JAX-RS {@link DynamicFeature} which are listed as SPIs for registration.
+ * Also checks if JAX-RS service loading is enabled by the jakarta.ws.rs.loadServices property. In order for
+ * registration to proceed the property shall be true (or null).
+ *
+ * Configurator is used only at Server side.
+ *
+ * This configurator's instance shall be after {@link AutoDiscoverableConfigurator}
+ * in the list of configurators due to same list of {@link org.glassfish.jersey.internal.spi.AutoDiscoverable}
+ * used in the {@link BootstrapBag} to register discovered features.
+ */
+public class DynamicFeatureConfigurator extends AbstractFeatureConfigurator<DynamicFeature> {
+
+    /**
+     * Create a new configurator.
+     *
+     * Must be used at server side only (takes no effect as a client).
+     */
+    public DynamicFeatureConfigurator() {
+        super(DynamicFeature.class, RuntimeType.SERVER);
+    }
+
+    @Override
+    public void init(InjectionManager injectionManager, BootstrapBag bootstrapBag) {
+        final Map<String, Object> properties = bootstrapBag.getConfiguration().getProperties();
+        if (PropertiesHelper.isJaxRsServiceLoadingEnabled(properties)) {
+            final List<Class<DynamicFeature>> dynamicFeatures = loadImplementations(properties);
+            dynamicFeatures.addAll(loadImplementations(properties, DynamicFeature.class.getClassLoader()));
+
+            registerFeatures(dynamicFeatures, bootstrapBag);
+        }
+    }
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/FeatureConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/internal/FeatureConfigurator.java
new file mode 100644
index 0000000..c3cdfc9
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/FeatureConfigurator.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.internal;
+
+import org.glassfish.jersey.AbstractFeatureConfigurator;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
+
+import jakarta.ws.rs.RuntimeType;
+import jakarta.ws.rs.core.Feature;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Registers JAX-RS {@link Feature} which are listed as SPIs for registration.
+ * Also checks if JAX-RS service loading is enabled by the jakarta.ws.rs.loadServices property. In order for
+ * registration to proceed the property shall be true (or null).
+ *
+ * This configurator's instance shall be the last (or at least after {@link AutoDiscoverableConfigurator})
+ * in the list of configurators due to same list of {@link org.glassfish.jersey.internal.spi.AutoDiscoverable}
+ * used in the {@link BootstrapBag} to register discovered features.
+ */
+public class FeatureConfigurator extends AbstractFeatureConfigurator<Feature> {
+
+    public FeatureConfigurator(RuntimeType runtimeType) {
+        super(Feature.class, runtimeType);
+    }
+
+    @Override
+    public void init(InjectionManager injectionManager, BootstrapBag bootstrapBag) {
+        final Map<String, Object> properties = bootstrapBag.getConfiguration().getProperties();
+        if (PropertiesHelper.isJaxRsServiceLoadingEnabled(properties)) {
+            final List<Class<Feature>> features = loadImplementations(properties);
+            features.addAll(loadImplementations(properties, Feature.class.getClassLoader()));
+
+            registerFeatures(features, bootstrapBag);
+        }
+    }
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java b/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java
index 1b8b5b6..94acf7c 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -41,6 +41,7 @@
 
     private static final Logger LOGGER = Logger.getLogger(PropertiesHelper.class.getName());
     private static final boolean METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT = false;
+    private static final boolean JAXRS_SERVICE_LOADING_ENABLE_DEFAULT = true;
 
     /**
      * Get system properties.
@@ -334,6 +335,24 @@
     }
 
     /**
+     * Check whether loading of JAX-RS services is allowed or not. Services shall implement Feature or DynamicFeature
+     * interface and be listed as SPI in an application
+     *
+     * @param properties list of properties to be checked
+     * @return false if loading of JAX-RS services is not enabled
+     *
+     * @since 2.35
+     */
+    public static boolean isJaxRsServiceLoadingEnabled(Map<String, Object> properties) {
+        boolean enableServicesLoading = JAXRS_SERVICE_LOADING_ENABLE_DEFAULT;
+        if (properties != null) {
+            enableServicesLoading = CommonProperties.getValue(properties,
+                    CommonProperties.JAXRS_SERVICE_LOADING_ENABLE, JAXRS_SERVICE_LOADING_ENABLE_DEFAULT);
+        }
+        return enableServicesLoading;
+    }
+
+    /**
      * Get the value of the property with a given name converted to {@code boolean}. Returns {@code false} if the value is
      * not convertible.
      *
diff --git a/core-server/pom.xml b/core-server/pom.xml
index 4a8d442..fe4ea1c 100644
--- a/core-server/pom.xml
+++ b/core-server/pom.xml
@@ -156,6 +156,7 @@
                     <threadCount>1</threadCount>
                     <forkCount>1C</forkCount>
                     <reuseForks>true</reuseForks>
+                    <systemPropertiesFile>${project.basedir}/../etc/jenkins/systemPropertiesFile</systemPropertiesFile>
                 </configuration>
             </plugin>
         </plugins>
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
index c4c95e5..42d11dd 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2018 Payara Foundation and/or its affiliates.
  *
  * This program and the accompanying materials are made available under the
@@ -50,8 +50,10 @@
 import org.glassfish.jersey.internal.BootstrapBag;
 import org.glassfish.jersey.internal.BootstrapConfigurator;
 import org.glassfish.jersey.internal.ContextResolverFactory;
+import org.glassfish.jersey.internal.DynamicFeatureConfigurator;
 import org.glassfish.jersey.internal.Errors;
 import org.glassfish.jersey.internal.ExceptionMapperFactory;
+import org.glassfish.jersey.internal.FeatureConfigurator;
 import org.glassfish.jersey.internal.JaxrsProviders;
 import org.glassfish.jersey.internal.Version;
 import org.glassfish.jersey.internal.inject.Binder;
@@ -285,7 +287,9 @@
                 new ResourceMethodInvokerConfigurator(),
                 new ProcessingProvidersConfigurator(),
                 new ContainerProviderConfigurator(RuntimeType.SERVER),
-                new AutoDiscoverableConfigurator(RuntimeType.SERVER));
+                new AutoDiscoverableConfigurator(RuntimeType.SERVER),
+                new DynamicFeatureConfigurator(),
+                new FeatureConfigurator(RuntimeType.SERVER));
 
         bootstrapConfigurators.forEach(configurator -> configurator.init(injectionManager, bootstrapBag));
 
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/JaxRsFeatureRegistrationTest.java b/core-server/src/test/java/org/glassfish/jersey/server/JaxRsFeatureRegistrationTest.java
new file mode 100644
index 0000000..1ac3403
--- /dev/null
+++ b/core-server/src/test/java/org/glassfish/jersey/server/JaxRsFeatureRegistrationTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.server;
+
+import org.glassfish.jersey.CommonProperties;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jakarta.ws.rs.container.DynamicFeature;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Feature;
+import jakarta.ws.rs.core.FeatureContext;
+
+public class JaxRsFeatureRegistrationTest {
+
+    public static class FeatureImpl implements Feature {
+
+        @Override
+        public boolean configure(FeatureContext context) {
+            return true;
+        }
+    }
+
+    public static class DynamicFeatureImpl implements DynamicFeature {
+
+        @Override
+        public void configure(ResourceInfo resourceInfo, FeatureContext context) {
+        }
+    }
+
+    @Test
+    public void featureRegistrationTest() {
+        final ResourceConfig config = new ResourceConfig();
+        final ApplicationHandler ah = new ApplicationHandler(config);
+
+        Assert.assertTrue(ah.getConfiguration().isRegistered(FeatureImpl.class));
+        Assert.assertTrue(ah.getConfiguration().isRegistered(DynamicFeatureImpl.class));
+    }
+
+    @Test
+    public void serviceLoadingPropertyTest() {
+
+        final ResourceConfig config = new ResourceConfig()
+                .property(CommonProperties.JAXRS_SERVICE_LOADING_ENABLE, "false");
+        final ApplicationHandler ah = new ApplicationHandler(config);
+
+        Assert.assertFalse(ah.getConfiguration().isRegistered(FeatureImpl.class));
+        Assert.assertFalse(ah.getConfiguration().isRegistered(DynamicFeatureImpl.class));
+    }
+}
\ No newline at end of file
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/TestInjectionManagerFactory.java b/core-server/src/test/java/org/glassfish/jersey/server/TestInjectionManagerFactory.java
index da2fee8..53501e6 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/TestInjectionManagerFactory.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/TestInjectionManagerFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2018 Payara Foundation and/or its affiliates.
  *
  * This program and the accompanying materials are made available under the
@@ -25,7 +25,9 @@
 import org.glassfish.jersey.internal.AutoDiscoverableConfigurator;
 import org.glassfish.jersey.internal.BootstrapConfigurator;
 import org.glassfish.jersey.internal.ContextResolverFactory;
+import org.glassfish.jersey.internal.DynamicFeatureConfigurator;
 import org.glassfish.jersey.internal.ExceptionMapperFactory;
+import org.glassfish.jersey.internal.FeatureConfigurator;
 import org.glassfish.jersey.internal.inject.AbstractBinder;
 import org.glassfish.jersey.internal.inject.Binder;
 import org.glassfish.jersey.internal.inject.InjectionManager;
@@ -113,7 +115,9 @@
                 new ExternalRequestScopeConfigurator(),
                 new ModelProcessorConfigurator(),
                 new ResourceModelConfigurator(),
-                new ServerExecutorProvidersConfigurator());
+                new ServerExecutorProvidersConfigurator(),
+                new DynamicFeatureConfigurator(),
+                new FeatureConfigurator(RuntimeType.SERVER));
 
         bootstrapConfigurators.forEach(configurator -> configurator.init(injectionManager, bootstrapBag));
 
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java
index d92393e..d8f9a8c 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java
@@ -37,12 +37,6 @@
     private static final int COLLISION_BUFFER_POWER = 3;
     private static final double DELTA = 0.0001;
 
-    @BeforeClass
-    public static void beforeClass() {
-        System.setProperty(ServerProperties.COLLISION_BUFFER_POWER_JVM_ARG,
-                Integer.toString(COLLISION_BUFFER_POWER));
-    }
-
     @Test
     public void jvmLoaded() {
         assertEquals(COLLISION_BUFFER_POWER, ReservoirConstants.COLLISION_BUFFER_POWER);
diff --git a/core-server/src/test/resources/META-INF/services/jakarta.ws.rs.container.DynamicFeature b/core-server/src/test/resources/META-INF/services/jakarta.ws.rs.container.DynamicFeature
new file mode 100644
index 0000000..56c113e
--- /dev/null
+++ b/core-server/src/test/resources/META-INF/services/jakarta.ws.rs.container.DynamicFeature
@@ -0,0 +1 @@
+org.glassfish.jersey.server.JaxRsFeatureRegistrationTest$DynamicFeatureImpl
\ No newline at end of file
diff --git a/core-server/src/test/resources/META-INF/services/jakarta.ws.rs.core.Feature b/core-server/src/test/resources/META-INF/services/jakarta.ws.rs.core.Feature
new file mode 100644
index 0000000..050876b
--- /dev/null
+++ b/core-server/src/test/resources/META-INF/services/jakarta.ws.rs.core.Feature
@@ -0,0 +1 @@
+org.glassfish.jersey.server.JaxRsFeatureRegistrationTest$FeatureImpl
\ No newline at end of file
diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml
index e74f459..4814b9d 100644
--- a/docs/src/main/docbook/client.xml
+++ b/docs/src/main/docbook/client.xml
@@ -848,7 +848,7 @@
         </example>
         <para>
             For more information see javadoc of &jersey.client.InjectionManagerClientProvider;
-            (and javadoc of &jersey.common.InjectionManagerProvider; which supports common JAX-RS components).
+            (and javadoc of &lit.jersey.common.InjectionManagerProvider; which supports common JAX-RS components).
         </para>
     </section>
 
diff --git a/docs/src/main/docbook/graalvm-native-image.xml b/docs/src/main/docbook/graalvm-native-image.xml
new file mode 100644
index 0000000..c64bbc3
--- /dev/null
+++ b/docs/src/main/docbook/graalvm-native-image.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<!--
+
+    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
+
+-->
+
+<!DOCTYPE chapter [<!ENTITY % ents SYSTEM "jersey.ent" > %ents; ]>
+<chapter xmlns="http://docbook.org/ns/docbook"
+         version="5.0"
+         xml:lang="en"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xsi:schemaLocation="http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd
+                             http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd"
+         xml:id="graalvm-native-image">
+    <title>GraalVM native-image generation</title>
+    <para>
+        This chapter describes Jersey's compatibility with GraalVM native image. This functionality is available since
+        Jersey 2.35 and is under development and configuration. For now Jersey provides native image configuration
+        basics for some modules and example on how to really generate native image for an existing application.
+    </para>
+    <section xml:id="supported_modules">
+        <title>Modules with GraalVM native image support</title>
+        <para>
+            Currently Jersey provides basic support for native image generation within following modules:
+            <literal>jersey-common</literal>,<literal>jersey-server</literal>,<literal>jersey-client</literal>,
+            <literal>jersey-hk2</literal>.
+
+            This support means that most of reflection and resource related settings are extracted into reflect-config
+            and resource-config JSON files to be used while generating a native image. Those files are included in
+            the native image generation process automatically (unless some tricky configuration is applied), so there is
+            no need to include those files manually and/or duplicate their contents in some custom configuration.
+        </para>
+    </section>
+    <section xml:id="native-image">
+        <title>HelloWorld native image generation</title>
+        <para>
+            The example for the GraalVM native image generation is hidden under examples/helloworld example.
+            To generate native image there it's required to perform some preliminary steps:
+            <simplelist>
+                <member>Download GraalVM at least 20.3.2 version</member>
+                <member>Set JAVA_HOME to point to that [GraalVM_HOME]</member>
+                <member>Perform <markup>$JAVA_HOME/bin/gu install native-image</markup> because native-image tool is not bundled within GraalVM itself</member>
+                <member>Download Jersey examples source codes (preferable some released version like 2.35),
+                    and go to [path_to_jersey_examples]/examples/helloworld</member>
+                <member>Run <markup>mvn -Pnative-image clean package -DskipTests</markup></member>
+            </simplelist>
+        </para>
+        <para>
+            If all was correctly performed from previous steps the native image shall be already generated inside the targed folder
+            of the helloworld example with the name helloworld-native and it's possible to run it by
+            <programlisting language="bash">target/./helloworld-native</programlisting>
+            After it's run, console should print our following output:
+            <screen linenumbering="unnumbered">
+                "Hello World" Jersey Example App
+                May 27, 2021 1:37:49 PM org.glassfish.jersey.server.wadl.WadlFeature configure
+                WARNING: JAX-B API not found . WADL feature is disabled.
+                May 27, 2021 1:37:49 PM org.glassfish.grizzly.http.server.NetworkListener start
+                INFO: Started listener bound to [localhost:8080]
+                May 27, 2021 1:37:49 PM org.glassfish.grizzly.http.server.HttpServer start
+                INFO: [HttpServer] Started.
+                Application started.
+                Try out http://localhost:8080/base/helloworld
+                Stop the application using CTRL+C
+            </screen>
+            If you see this, you can open given link in browser and check how application actually works.
+            In general we are done here and you can use that example to generate native images for your own projects.
+        </para>
+    </section>
+    <section xml:id="undercover">
+        <title>What's under the cover</title>
+        <para>
+            For the example above the following command line was used:
+            <programlisting language="bash">
+                -H:EnableURLProtocols=http,https
+                --initialize-at-build-time=org.glassfish.jersey.client.internal.HttpUrlConnector
+                -H:+ReportExceptionStackTraces
+                --verbose
+                --no-fallback
+                --report-unsupported-elements-at-runtime
+            </programlisting>
+            This might be useful to generate another native image. It's possible to add another bunch of parameters to the command line
+            (and put those into the <literal>native-image.properties</literal> file inside of your project). Important parameter here is
+            --initialize-at-build-time (opposite to --initialize-at-run-time) and --no-fallback which says to the native
+            image to generate pure native image with everything bundled inside the image and not just fall back wrapper for JDK.
+        </para>
+        <para>
+            Another important aspect for generating the native image is the proper listing of reflection classes (classes that use reflection
+            in an application). For those needs, there is a native image agent which helps to generate those lists automatically.
+            In order to generate a list of reflection classes (and JNI classes and resources), it is required to run:
+            <programlisting language="bash">$JAVA_HOME/bin/java -agentlib:native-image-agent=config-output-dir=[output_location] -jar [app_name].jar</programlisting>
+            And afterwords, the [output_location] directory will be created with generated lists (in JSON format). Those files can be
+            included as is into native image generation, but it's very preferable to edit them manually to reduce possible ambiguous classes listings.
+        </para>
+    </section>
+</chapter>
\ No newline at end of file
diff --git a/docs/src/main/docbook/user-guide.xml b/docs/src/main/docbook/user-guide.xml
index 84530ba..34da07a 100644
--- a/docs/src/main/docbook/user-guide.xml
+++ b/docs/src/main/docbook/user-guide.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2010, 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
@@ -116,6 +116,7 @@
     <xi:include href="custom-di.xml" />
     <xi:include href="cdi.xml" />
 <!--    <xi:include href="spring.xml" />--> <!--Spring is not supported in Jakarta -->
+    <xi:include href="graalvm-native-image.xml" />
     <xi:include href="test-framework.xml" />
     <xi:include href="how-to-build.xml" />
     <xi:include href="migration.xml" />
diff --git a/etc/jenkins/jenkins_build.sh b/etc/jenkins/jenkins_build.sh
index afa8b15..e612cbb 100644
--- a/etc/jenkins/jenkins_build.sh
+++ b/etc/jenkins/jenkins_build.sh
@@ -2,4 +2,4 @@
 
 export DEBUG=true
 
-mvn -V -U -B -e clean install glassfish-copyright:check -Dcopyright.quiet=false -Dsurefire.systemPropertiesFile=${WORKSPACE}/etc/jenkins/systemPropertiesFile
\ No newline at end of file
+mvn -V -U -B -e clean install glassfish-copyright:check -Dcopyright.quiet=false
\ No newline at end of file
diff --git a/ext/microprofile/mp-rest-client/pom.xml b/ext/microprofile/mp-rest-client/pom.xml
index e90137c..02c2939 100644
--- a/ext/microprofile/mp-rest-client/pom.xml
+++ b/ext/microprofile/mp-rest-client/pom.xml
@@ -98,6 +98,11 @@
     <build>
         <plugins>
             <plugin>
+                <groupId>com.sun.istack</groupId>
+                <artifactId>istack-commons-maven-plugin</artifactId>
+                <inherited>true</inherited>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <inherited>true</inherited>
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/InterfaceModel.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/InterfaceModel.java
index fdf8ecf..254df0e 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/InterfaceModel.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/InterfaceModel.java
@@ -40,13 +40,9 @@
 import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
 import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
 import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
-import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptor;
-import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptorFactory;
 import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
-import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
 import org.glassfish.jersey.client.inject.ParameterUpdater;
 import org.glassfish.jersey.client.inject.ParameterUpdaterProvider;
-import org.glassfish.jersey.internal.inject.InjectionManager;
 import org.glassfish.jersey.internal.inject.Providers;
 import org.glassfish.jersey.model.Parameter;
 
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientExtension.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientExtension.java
index 35537ba..df16da6 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientExtension.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientExtension.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientModel.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientModel.java
index bb30b7f..94c5fa4 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientModel.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientModel.java
@@ -20,9 +20,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import jakarta.enterprise.inject.spi.BeanManager;
 import jakarta.ws.rs.client.WebTarget;
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
index f2b3b9e..8a5fe0d 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
@@ -55,7 +55,6 @@
 import org.eclipse.microprofile.config.Config;
 import org.eclipse.microprofile.config.ConfigProvider;
 import org.eclipse.microprofile.rest.client.RestClientBuilder;
-import org.eclipse.microprofile.rest.client.ext.QueryParamStyle;
 import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
 import org.eclipse.microprofile.rest.client.inject.RestClient;
 import org.glassfish.jersey.internal.util.ReflectionHelper;
@@ -139,26 +138,11 @@
         getConfigOption(Long.class, CONFIG_READ_TIMEOUT)
                 .ifPresent(aLong -> restClientBuilder.readTimeout(aLong, TimeUnit.MILLISECONDS));
         getConfigOption(Boolean.class, CONFIG_FOLLOW_REDIRECTS)
-                .ifPresent(restClientBuilder::followRedirects);
+                .ifPresent(follow -> VersionSupport.followRedirects(restClientBuilder, follow));
         getConfigOption(String.class, CONFIG_QUERY_PARAM_STYLE)
-                .ifPresent(value -> restClientBuilder.queryParamStyle(QueryParamStyle.valueOf(value)));
+                .ifPresent(value -> VersionSupport.queryParamStyle(restClientBuilder, value));
         getConfigOption(String.class, CONFIG_PROXY_ADDRESS)
-                .ifPresent(proxy -> {
-                    int index = proxy.lastIndexOf(':');
-                    //If : was not found at all or it is the last character of the proxy string
-                    if (index < 0 || proxy.length() - 1 == index) {
-                        throw new IllegalArgumentException("Invalid proxy URI: " + proxy);
-                    }
-                    String proxyHost = proxy.substring(0, index);
-                    int proxyPort;
-                    String proxyPortStr = proxy.substring(index + 1);
-                    try {
-                        proxyPort = Integer.parseInt(proxyPortStr);
-                    } catch (NumberFormatException nfe) {
-                        throw new IllegalArgumentException("Invalid proxy port: " + proxyPortStr, nfe);
-                    }
-                    restClientBuilder.proxyAddress(proxyHost, proxyPort);
-                });
+                .ifPresent(proxy -> VersionSupport.proxyAddress(restClientBuilder, proxy));
 
         // Providers from configuration
         addConfiguredProviders(restClientBuilder);
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/VersionSupport.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/VersionSupport.java
new file mode 100644
index 0000000..c3d8da0
--- /dev/null
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/VersionSupport.java
@@ -0,0 +1,109 @@
+/*
+ * 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.microprofile.restclient;
+
+import org.eclipse.microprofile.rest.client.RestClientBuilder;
+import org.glassfish.jersey.microprofile.restclient.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;
+
+import java.util.logging.Logger;
+
+/**
+ * Backward compatibility support not to throw an exception when an old API is used.
+ */
+abstract class VersionSupport {
+
+    protected abstract RestClientBuilder _followRedirects(RestClientBuilder restClientBuilder, boolean follow);
+    protected abstract RestClientBuilder _proxyAddress(RestClientBuilder restClientBuilder, String proxy);
+    protected abstract RestClientBuilder _queryParamStyle(RestClientBuilder restClientBuilder, String style);
+
+    private static final Logger logger = Logger.getLogger(VersionSupport.class.getName());
+
+    // determine the version only once per jvm
+    private static LazyValue<VersionSupport> currentVersion = Values.lazy((Value<VersionSupport>) () -> {
+        final Class<?> restClientBuilderClass = RestClientBuilder.class;
+        try {
+            if (null != restClientBuilderClass.getMethod("followRedirects", boolean.class)) {
+                return new Version20Support();
+            }
+        } catch (NoSuchMethodException e) {
+            // VERSION 1.4
+        }
+        return new Version14Support();
+    });
+
+    static RestClientBuilder followRedirects(RestClientBuilder restClientBuilder, boolean follow) {
+        return currentVersion.get()._followRedirects(restClientBuilder, follow);
+    }
+
+    static RestClientBuilder proxyAddress(RestClientBuilder restClientBuilder, String proxy) {
+        return currentVersion.get()._proxyAddress(restClientBuilder, proxy);
+    }
+
+    static RestClientBuilder queryParamStyle(RestClientBuilder restClientBuilder, String style) {
+        return currentVersion.get()._queryParamStyle(restClientBuilder, style);
+    }
+
+    private static class Version14Support extends VersionSupport {
+        protected RestClientBuilder _followRedirects(RestClientBuilder restClientBuilder, boolean follow) {
+            logger.warning(LocalizationMessages.WARN_VERSION_14_FOLLOWREDIRECT());
+            return restClientBuilder;
+        }
+
+        protected RestClientBuilder _proxyAddress(RestClientBuilder restClientBuilder, String proxy) {
+            logger.warning(LocalizationMessages.WARN_VERSION_14_PROXY());
+            return restClientBuilder;
+        }
+
+        protected RestClientBuilder _queryParamStyle(RestClientBuilder restClientBuilder, String style) {
+            logger.warning(LocalizationMessages.WARN_VERSION_14_QUERYPARAMSTYLE());
+            return restClientBuilder;
+        }
+    }
+
+    private static class Version20Support extends VersionSupport {
+        protected RestClientBuilder _followRedirects(RestClientBuilder restClientBuilder, boolean follow) {
+            return restClientBuilder.followRedirects(follow);
+        }
+
+        protected RestClientBuilder _proxyAddress(RestClientBuilder restClientBuilder, String proxy) {
+            int index = proxy.lastIndexOf(':');
+            //If : was not found at all or it is the last character of the proxy string
+            if (index < 0 || proxy.length() - 1 == index) {
+                throw new IllegalArgumentException(LocalizationMessages.ERR_INVALID_PROXY_URI(proxy));
+            }
+            String proxyHost = proxy.substring(0, index);
+            int proxyPort;
+            String proxyPortStr = proxy.substring(index + 1);
+            try {
+                proxyPort = Integer.parseInt(proxyPortStr);
+            } catch (NumberFormatException nfe) {
+                throw new IllegalArgumentException(LocalizationMessages.ERR_INVALID_PROXY_PORT(proxyPortStr), nfe);
+            }
+            return restClientBuilder.proxyAddress(proxyHost, proxyPort);
+        }
+
+        protected RestClientBuilder _queryParamStyle(RestClientBuilder restClientBuilder, String style) {
+            // do not import for compatibility with 1.4
+            org.eclipse.microprofile.rest.client.ext.QueryParamStyle queryParamStyle =
+                    org.eclipse.microprofile.rest.client.ext.QueryParamStyle.valueOf(style);
+            return restClientBuilder.queryParamStyle(queryParamStyle);
+        }
+    }
+}
diff --git a/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties b/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties
new file mode 100644
index 0000000..71f05e0
--- /dev/null
+++ b/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties
@@ -0,0 +1,22 @@
+#
+# 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
+#
+
+err.invalid.proxy.uri=Invalid proxy URI: {0}.
+err.invalid.proxy.port=Invalid proxy port: {0}.
+warn.version14.followredirect=MP Rest Client Version 1.4 does not support RestClientBuilder#followRedirect and it is ignored.
+warn.version14.proxy=MP Rest Client Version 1.4 does not support RestClientBuilder#proxy and it is ignored.
+warn.version14.queryparamstyle=MP Rest Client Version 1.4 does not support RestClientBuilder#queryParamStyle and it is ignored.
+
diff --git a/pom.xml b/pom.xml
index 29b8a77..04285e9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -773,7 +773,7 @@
                         <dependency>
                             <groupId>org.apache.ant</groupId>
                             <artifactId>ant</artifactId>
-                            <version>1.10.9</version>
+                            <version>1.10.11</version>
                         </dependency>
                     </dependencies>
                 </plugin>
diff --git a/tests/integration/cdi-integration/cdi-singleton/pom.xml b/tests/integration/cdi-integration/cdi-singleton/pom.xml
index 83b16d7..6aef2a0 100644
--- a/tests/integration/cdi-integration/cdi-singleton/pom.xml
+++ b/tests/integration/cdi-integration/cdi-singleton/pom.xml
@@ -23,11 +23,11 @@
     <parent>
         <artifactId>cdi-integration-project</artifactId>
         <groupId>org.glassfish.jersey.tests.integration.cdi</groupId>
-        <version>2.35-SNAPSHOT</version>
+        <version>3.1.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>cdi-sigleton</artifactId>
+    <artifactId>cdi-singleton</artifactId>
 
     <dependencies>
         <dependency>
@@ -41,7 +41,6 @@
         <dependency>
             <groupId>jakarta.enterprise</groupId>
             <artifactId>jakarta.enterprise.cdi-api</artifactId>
-            <version>2.0.2</version>
         </dependency>
         <dependency>
             <groupId>org.glassfish.jersey.ext.cdi</groupId>
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonResource.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonResource.java
index 2f95a80..46f5e28 100644
--- a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonResource.java
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonResource.java
@@ -16,9 +16,9 @@
 
 package org.glassfish.jersey.tests.cdi.singleton;
 
-import javax.inject.Singleton;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
 
 @Path("/")
 @Singleton
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestApp.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestApp.java
index 59aa774..3578328 100644
--- a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestApp.java
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestApp.java
@@ -16,7 +16,7 @@
 
 package org.glassfish.jersey.tests.cdi.singleton;
 
-import javax.ws.rs.core.Application;
+import jakarta.ws.rs.core.Application;
 import java.util.HashSet;
 import java.util.Set;
 
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerRequestFilter.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerRequestFilter.java
index 34a1f2c..68f7a63 100644
--- a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerRequestFilter.java
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerRequestFilter.java
@@ -16,9 +16,9 @@
 
 package org.glassfish.jersey.tests.cdi.singleton;
 
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.core.Context;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.core.Context;
 import java.io.IOException;
 
 public class SingletonTestContainerRequestFilter implements ContainerRequestFilter {
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerResponseFilter.java b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerResponseFilter.java
index 6e853d3..a76c64f 100644
--- a/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerResponseFilter.java
+++ b/tests/integration/cdi-integration/cdi-singleton/src/main/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTestContainerResponseFilter.java
@@ -16,10 +16,10 @@
 
 package org.glassfish.jersey.tests.cdi.singleton;
 
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerResponseContext;
-import javax.ws.rs.container.ContainerResponseFilter;
-import javax.ws.rs.core.Context;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerResponseContext;
+import jakarta.ws.rs.container.ContainerResponseFilter;
+import jakarta.ws.rs.core.Context;
 import java.io.IOException;
 
 public class SingletonTestContainerResponseFilter implements ContainerResponseFilter {
diff --git a/tests/integration/cdi-integration/cdi-singleton/src/test/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTest.java b/tests/integration/cdi-integration/cdi-singleton/src/test/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTest.java
index eb5e9c6..5fe5070 100644
--- a/tests/integration/cdi-integration/cdi-singleton/src/test/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTest.java
+++ b/tests/integration/cdi-integration/cdi-singleton/src/test/java/org/glassfish/jersey/tests/cdi/singleton/SingletonTest.java
@@ -25,8 +25,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import javax.ws.rs.core.Application;
-import javax.ws.rs.core.Response;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
 
 public class SingletonTest extends JerseyTest {
     private Weld weld;
diff --git a/tests/integration/cdi-integration/pom.xml b/tests/integration/cdi-integration/pom.xml
index a16adb6..c4ed648 100644
--- a/tests/integration/cdi-integration/pom.xml
+++ b/tests/integration/cdi-integration/pom.xml
@@ -42,6 +42,7 @@
         <module>cdi-multimodule</module>
         <module>cdi-multipart-webapp</module>
         <module>cdi-resource-with-at-context</module>
+        <module>cdi-singleton</module>
         <module>cdi-test-webapp</module>
         <module>cdi-with-jersey-injection-custom-cfg-webapp</module>
         <module>cdi-with-jersey-injection-custom-hk2-banned-webapp</module>
diff --git a/tests/integration/microprofile/pom.xml b/tests/integration/microprofile/pom.xml
index 76be6eb..e41fdae 100644
--- a/tests/integration/microprofile/pom.xml
+++ b/tests/integration/microprofile/pom.xml
@@ -33,6 +33,7 @@
     <modules>
         <module>config</module>
 <!--        <module>rest-client</module>-->
+<!--        <module>rest-client14-compatibility</module>-->
     </modules>
 
     <build>
diff --git a/tests/integration/microprofile/rest-client14-compatibility/pom.xml b/tests/integration/microprofile/rest-client14-compatibility/pom.xml
new file mode 100644
index 0000000..567c6f4
--- /dev/null
+++ b/tests/integration/microprofile/rest-client14-compatibility/pom.xml
@@ -0,0 +1,115 @@
+<?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">
+    <parent>
+        <artifactId>microprofile-integration-project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
+        <version>3.1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>jersey-rest-client14-compatibility</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.microprofile</groupId>
+            <artifactId>jersey-mp-rest-client</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>jakarta.enterprise</groupId>
+                    <artifactId>jakarta.enterprise.cdi-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>javax.enterprise</groupId>
+                    <artifactId>cdi-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.microprofile.rest.client</groupId>
+                    <artifactId>microprofile-rest-client-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- Overrides CDI from parent pom -->
+        <dependency>
+            <groupId>jakarta.enterprise</groupId>
+            <artifactId>jakarta.enterprise.cdi-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.rest.client</groupId>
+            <artifactId>microprofile-rest-client-api</artifactId>
+            <!-- specifically this version we check with the backward compatibility -->
+            <version>1.4.1</version>
+            <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>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.smallrye.config</groupId>
+            <artifactId>smallrye-config</artifactId>
+            <version>1.8.4</version> <!-- Workswith CQ 22471 -->
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>javax.enterprise</groupId>
+                    <artifactId>cdi-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-bundle</artifactId>
+            <type>pom</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-weld2-se</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tests/integration/microprofile/rest-client14-compatibility/src/test/java/org/glassfish/jersey/tests/restclient/compatibility/Compatibility14Test.java b/tests/integration/microprofile/rest-client14-compatibility/src/test/java/org/glassfish/jersey/tests/restclient/compatibility/Compatibility14Test.java
new file mode 100644
index 0000000..8507722
--- /dev/null
+++ b/tests/integration/microprofile/rest-client14-compatibility/src/test/java/org/glassfish/jersey/tests/restclient/compatibility/Compatibility14Test.java
@@ -0,0 +1,119 @@
+/*
+ * 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.restclient.compatibility;
+
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.jboss.weld.environment.se.Weld;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Response;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+public class Compatibility14Test 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();
+        }
+    }
+
+    @RegisterRestClient
+    public static interface CompatibilityClient {
+        @GET
+        public String get();
+    }
+
+    @Path("/resource")
+    @RequestScoped
+    public static class CompatibilityResource {
+
+        @Inject
+        @RestClient
+        CompatibilityClient client;
+
+        @GET
+        public String get() {
+            return client.get();
+        }
+    }
+
+    @Path("/inner")
+    public static class InnerResource implements CompatibilityClient {
+
+        public String get() {
+            return "INNER";
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        set(TestProperties.RECORD_LOG_LEVEL, Level.WARNING.intValue());
+        return new ResourceConfig(InnerResource.class, CompatibilityResource.class)
+                .property(ServerProperties.WADL_FEATURE_DISABLE, true);
+    }
+
+    @Test
+    public void testCompatibility() {
+        final String loggerName = "org.glassfish.jersey.microprofile.restclient.VersionSupport";
+
+        try (Response r = target("/resource").request().get()) {
+            String entity = r.readEntity(String.class);
+            Assert.assertEquals(new InnerResource().get(), entity);
+        }
+
+        int warningCounts = 0;
+        for (final LogRecord logRecord : getLoggedRecords()) {
+            if (loggerName.equals(logRecord.getLoggerName()) && logRecord.getLevel() == Level.WARNING) {
+                warningCounts++;
+            }
+        }
+
+        Assert.assertEquals(3, warningCounts);
+    }
+}
diff --git a/tests/integration/microprofile/rest-client14-compatibility/src/test/resources/META-INF/beans.xml b/tests/integration/microprofile/rest-client14-compatibility/src/test/resources/META-INF/beans.xml
new file mode 100644
index 0000000..70897bd
--- /dev/null
+++ b/tests/integration/microprofile/rest-client14-compatibility/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,25 @@
+<?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="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
+	   http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+       bean-discovery-mode="annotated">
+</beans>
diff --git a/tests/integration/microprofile/rest-client14-compatibility/src/test/resources/META-INF/microprofile-config.properties b/tests/integration/microprofile/rest-client14-compatibility/src/test/resources/META-INF/microprofile-config.properties
new file mode 100644
index 0000000..616d545
--- /dev/null
+++ b/tests/integration/microprofile/rest-client14-compatibility/src/test/resources/META-INF/microprofile-config.properties
@@ -0,0 +1,19 @@
+#
+# 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.tests.restclient.compatibility.Compatibility14Test$CompatibilityClient/mp-rest/uri=http://localhost:9998/inner
+org.glassfish.jersey.tests.restclient.compatibility.Compatibility14Test$CompatibilityClient/mp-rest/followRedirects=true
+org.glassfish.jersey.tests.restclient.compatibility.Compatibility14Test$CompatibilityClient/mp-rest/queryParamStyle=COMMA_SEPARATED
+org.glassfish.jersey.tests.restclient.compatibility.Compatibility14Test$CompatibilityClient/mp-rest/proxyAddress=http://localhost:1010/nowehere
\ No newline at end of file