You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by jo...@apache.org on 2018/01/14 15:37:38 UTC

[cxf] branch master updated: [CXF-7571] Adding support for CDI injection of @Context objects. (#351)

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

johndament pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/master by this push:
     new 189f943  [CXF-7571] Adding support for CDI injection of @Context objects. (#351)
189f943 is described below

commit 189f943bb34ee05494d1c142b9c7c9662261a0eb
Author: John Ament <jo...@gmail.com>
AuthorDate: Sun Jan 14 10:37:35 2018 -0500

    [CXF-7571] Adding support for CDI injection of @Context objects. (#351)
---
 .../java/org/apache/cxf/cdi/AbstractCXFBean.java   |  31 +++-
 .../org/apache/cxf/cdi/ContextProducerBean.java    | 100 +++++++++++
 .../java/org/apache/cxf/cdi/ContextResolved.java   |  52 ++++++
 .../org/apache/cxf/cdi/DefaultApplicationBean.java |  13 --
 .../cxf/cdi/DelegateContextAnnotatedType.java      | 184 +++++++++++++++++++++
 .../apache/cxf/cdi/JAXRSCdiResourceExtension.java  |  54 ++++++
 .../jaxrs/BraveTracerContextClassProvider.java     |  29 ++++
 .../org.apache.cxf.jaxrs.ext.ContextClassProvider  |   1 +
 .../jaxrs/HTraceTracerContextClassProvider.java    |  29 ++++
 .../org.apache.cxf.jaxrs.ext.ContextClassProvider  |   1 +
 .../OpenTracingTracerContextClassProvider.java     |  29 ++++
 .../org.apache.cxf.jaxrs.ext.ContextClassProvider  |   1 +
 .../apache/cxf/jaxrs/ext/ContextClassProvider.java |  26 +++
 .../apache/cxf/jaxrs/impl/ResourceContextImpl.java |   7 +-
 .../client/ClientTokenContextClassProvider.java    |  28 ++++
 .../org.apache.cxf.jaxrs.ext.ContextClassProvider  |   1 +
 .../oidc/rp/IdTokenContextClassProvider.java       |  28 ++++
 .../oidc/rp/UserInfoContextClassProvider.java      |  28 ++++
 .../org.apache.cxf.jaxrs.ext.ContextClassProvider  |   2 +
 .../cdi/base/AbstractCdiSingleAppTest.java         |   5 +
 .../apache/cxf/systests/cdi/base/BookStore.java    |  25 ++-
 .../cxf/systests/cdi/base/BookStoreVersion.java    |  53 ++++++
 .../systests/cdi/base/context/CustomContext.java   |  25 +++
 .../cdi/base/context/CustomContextFeature.java     |  39 +++++
 .../cdi/base/context/CustomContextImpl.java        |  34 ++++
 .../cdi/base/context/CustomContextProvider.java    |  29 ++++
 .../cdi/base/src/main/resources/META-INF/beans.xml |  11 +-
 .../org.apache.cxf.jaxrs.ext.ContextClassProvider  |   1 +
 systests/cdi/pom.xml                               |   2 +-
 29 files changed, 831 insertions(+), 37 deletions(-)

diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/AbstractCXFBean.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/AbstractCXFBean.java
index dea25bf..687f3a8 100644
--- a/integration/cdi/src/main/java/org/apache/cxf/cdi/AbstractCXFBean.java
+++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/AbstractCXFBean.java
@@ -25,21 +25,21 @@ import java.util.HashSet;
 import java.util.Set;
 
 import javax.enterprise.context.ApplicationScoped;
+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.util.AnnotationLiteral;
 
 abstract class AbstractCXFBean<T> implements Bean<T> {
+    static final Any ANY = new AnyLiteral();
+    static final Default DEFAULT = new DefaultLiteral();
     @Override
     public Set<Annotation> getQualifiers() {
         Set<Annotation> qualifiers = new HashSet<>();
-        qualifiers.add(new AnnotationLiteral<Default>() {
-            private static final long serialVersionUID = 1L;
-        });
-        qualifiers.add(new AnnotationLiteral<Any>() {
-            private static final long serialVersionUID = 1L;
-        });
+        qualifiers.add(ANY);
+        qualifiers.add(DEFAULT);
         return qualifiers;
     }
 
@@ -66,7 +66,26 @@ abstract class AbstractCXFBean<T> implements Bean<T> {
     }
 
     @Override
+    public Set<InjectionPoint> getInjectionPoints() {
+        return Collections.emptySet();
+    }
+
+
+    @Override
+    public void destroy(T instance, CreationalContext<T> creationalContext) {
+        creationalContext.release();
+    }
+
+    @Override
     public Set< Class< ? extends Annotation > > getStereotypes() {
         return Collections.emptySet();
     }
+
+    private static class DefaultLiteral extends AnnotationLiteral<Default> implements Default {
+        private static final long serialVersionUID = 1L;
+    }
+
+    private static class AnyLiteral extends AnnotationLiteral<Any> implements Any {
+        private static final long serialVersionUID = 1L;
+    }
 }
diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/ContextProducerBean.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/ContextProducerBean.java
new file mode 100644
index 0000000..7fab977
--- /dev/null
+++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/ContextProducerBean.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.PassivationCapable;
+
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+
+public class ContextProducerBean extends AbstractCXFBean<Object> implements PassivationCapable {
+    private final Type type;
+
+    ContextProducerBean(Type type) {
+        this.type = type;
+    }
+
+    @Override
+    public Set<Annotation> getQualifiers() {
+        Set<Annotation> qualifiers = new HashSet<>(2);
+        qualifiers.add(ContextResolved.LITERAL);
+        qualifiers.add(DEFAULT);
+        return qualifiers;
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope() {
+        return RequestScoped.class;
+    }
+
+    @Override
+    public Class<?> getBeanClass() {
+        return (Class<?>)type;
+    }
+
+    @Override
+    public Object create(CreationalContext<Object> creationalContext) {
+        return createContextValue();
+    }
+
+    @Override
+    public boolean isNullable() {
+        return true;
+    }
+
+    @Override
+    public Set<Type> getTypes() {
+        Set<Type> types = super.getTypes();
+        types.add(type);
+        return types;
+    }
+
+    @Override
+    public String getName() {
+        return "CxfContextProducer" + type;
+    }
+
+    private Object createContextValue() {
+        Message currentMessage = PhaseInterceptorChain.getCurrentMessage();
+        Type genericType = null;
+        Class<?> contextType;
+        if (type instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType)type;
+            genericType = parameterizedType.getActualTypeArguments()[0];
+            contextType = (Class<?>)parameterizedType.getRawType();
+        } else {
+            contextType = (Class<?>)type;
+        }
+        return JAXRSUtils.createContextValue(currentMessage, genericType, contextType);
+    }
+
+    @Override
+    public String getId() {
+        return getName();
+    }
+}
diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/ContextResolved.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/ContextResolved.java
new file mode 100644
index 0000000..932467e
--- /dev/null
+++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/ContextResolved.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.cdi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Qualifier;
+
+import org.apache.cxf.jaxrs.ext.ContextProvider;
+
+/**
+ * ContextResolved is an internal qualifier used by CXF to differentiate the beans it will manage from
+ * beans a user may have provided.  A user should not use this qualifier, but all beans that CXF provides
+ * that are from {@link javax.ws.rs.core.Context} objects.
+ *
+ * Likewise, for any field level injections, as well as constructor injections, the CDI instance of the
+ * Context object will be used.  Methods annotated {@link javax.inject.Inject} will also delegate to CDI.
+ * Any method parameter that takes a Context object will still be resolved from non-CDI semantics.
+ *
+ * For all built in context objects (as defined by the JAX-RS specification), the thread local aware instance
+ * is used.  For any custom context objects (implemented via {@link ContextProvider}) you must ensure that
+ * they are implemented in a thread safe manner.  All context objects are backed by a
+ * {@link javax.enterprise.context.RequestScoped} bean.
+ */
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ContextResolved {
+
+    ContextResolved LITERAL = new ContextResolvedLiteral();
+
+    final class ContextResolvedLiteral extends AnnotationLiteral<ContextResolved> implements ContextResolved {
+
+    }
+}
diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/DefaultApplicationBean.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/DefaultApplicationBean.java
index ed5afa6..fd9b3d6 100644
--- a/integration/cdi/src/main/java/org/apache/cxf/cdi/DefaultApplicationBean.java
+++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/DefaultApplicationBean.java
@@ -19,12 +19,10 @@
 package org.apache.cxf.cdi;
 
 import java.lang.reflect.Type;
-import java.util.Collections;
 import java.util.Set;
 
 import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.inject.Vetoed;
-import javax.enterprise.inject.spi.InjectionPoint;
 import javax.ws.rs.core.Application;
 
 @Vetoed
@@ -37,22 +35,11 @@ class DefaultApplicationBean extends AbstractCXFBean<DefaultApplication> {
     }
 
     @Override
-    public Set<InjectionPoint> getInjectionPoints() {
-        return Collections.emptySet();
-    }
-
-    @Override
     public DefaultApplication create(CreationalContext<DefaultApplication> creationalContext) {
         return application;
     }
 
     @Override
-    public void destroy(DefaultApplication defaultApplication,
-                        CreationalContext<DefaultApplication> creationalContext) {
-        creationalContext.release();
-    }
-
-    @Override
     public Set<Type> getTypes() {
         final Set<Type> types = super.getTypes();
         types.add(DefaultApplication.class);
diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/DelegateContextAnnotatedType.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/DelegateContextAnnotatedType.java
new file mode 100644
index 0000000..437a39f
--- /dev/null
+++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/DelegateContextAnnotatedType.java
@@ -0,0 +1,184 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Inject;
+import javax.ws.rs.core.Context;
+
+import static java.util.stream.Collectors.toSet;
+
+final class DelegateContextAnnotatedType<X> implements AnnotatedType<X> {
+    private static final Inject INJECT = new InjectLiteral();
+    private static final ContextResolved CONTEXT_RESOLVED = ContextResolved.LITERAL;
+    private final AnnotatedType<X> original;
+    private final Set<AnnotatedField<? super X>> replacedFields;
+
+    DelegateContextAnnotatedType(AnnotatedType<X> original) {
+        this.original = original;
+        this.replacedFields = replaceFields(original);
+    }
+
+    private Set<AnnotatedField<? super X>> replaceFields(AnnotatedType<? super X> delegate) {
+        return delegate.getFields().stream().map(this::wrap).collect(toSet());
+    }
+
+    Set<Type> getContextFieldTypes() {
+        return replacedFields.stream()
+                .filter(f -> f.isAnnotationPresent(Context.class) || f.isAnnotationPresent(ContextResolved.class))
+                .map(f -> f.getJavaMember().getAnnotatedType().getType())
+                .collect(toSet());
+    }
+
+    @Override
+    public Class<X> getJavaClass() {
+        return original.getJavaClass();
+    }
+
+    @Override
+    public Set<AnnotatedConstructor<X>> getConstructors() {
+        return original.getConstructors();
+    }
+
+    @Override
+    public Set<AnnotatedMethod<? super X>> getMethods() {
+        return original.getMethods();
+    }
+
+    @Override
+    public Set<AnnotatedField<? super X>> getFields() {
+        return replacedFields;
+    }
+
+    @Override
+    public Type getBaseType() {
+        return original.getBaseType();
+    }
+
+    @Override
+    public Set<Type> getTypeClosure() {
+        return original.getTypeClosure();
+    }
+
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+        return original.getAnnotation(annotationType);
+    }
+
+    @Override
+    public Set<Annotation> getAnnotations() {
+        return original.getAnnotations();
+    }
+
+    @Override
+    public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        return original.isAnnotationPresent(annotationType);
+    }
+
+    private AnnotatedField<? super X> wrap(AnnotatedField<? super X> af) {
+        if (af.isAnnotationPresent(Context.class)) {
+            return new DelegateAnnotatedField<>(af);
+        } else {
+            return af;
+        }
+    }
+
+    private final class DelegateAnnotatedField<Y> implements AnnotatedField<Y> {
+        private final AnnotatedField<Y> original;
+        private final Set<Annotation> annotationSet;
+
+        private DelegateAnnotatedField(AnnotatedField<Y> delegate) {
+            this.original = delegate;
+            this.annotationSet = processAnnotations(delegate.getAnnotations());
+        }
+
+        private Set<Annotation> processAnnotations(Set<Annotation> annotations) {
+            Set<Annotation> resultAnnotations = new LinkedHashSet<>();
+            for (Annotation a : annotations) {
+                if (a instanceof Context) {
+                    resultAnnotations.add(INJECT);
+                    resultAnnotations.add(CONTEXT_RESOLVED);
+                }
+                resultAnnotations.add(a);
+            }
+            return Collections.unmodifiableSet(resultAnnotations);
+        }
+
+        @Override
+        public Field getJavaMember() {
+            return original.getJavaMember();
+        }
+
+        @Override
+        public boolean isStatic() {
+            return original.isStatic();
+        }
+
+        @Override
+        public AnnotatedType<Y> getDeclaringType() {
+            return original.getDeclaringType();
+        }
+
+        @Override
+        public Type getBaseType() {
+            return original.getBaseType();
+        }
+
+        @Override
+        public Set<Type> getTypeClosure() {
+            return original.getTypeClosure();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+            for (Annotation a : annotationSet) {
+                if (annotationType == a.annotationType()) {
+                    return (T)a;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public Set<Annotation> getAnnotations() {
+            return annotationSet;
+        }
+
+        @Override
+        public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+            return getAnnotation(annotationType) != null;
+        }
+    }
+
+    private static final class InjectLiteral extends AnnotationLiteral<Inject> implements Inject {
+
+    }
+}
diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java
index ce23e1a..25c4525 100644
--- a/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java
+++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java
@@ -24,6 +24,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.ServiceLoader;
 import java.util.Set;
 
@@ -37,12 +38,15 @@ import javax.enterprise.inject.spi.BeanManager;
 import javax.enterprise.inject.spi.BeforeShutdown;
 import javax.enterprise.inject.spi.Extension;
 import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.inject.spi.ProcessAnnotatedType;
 import javax.enterprise.inject.spi.ProcessBean;
 import javax.enterprise.inject.spi.ProcessProducerField;
 import javax.enterprise.inject.spi.ProcessProducerMethod;
+import javax.enterprise.inject.spi.WithAnnotations;
 import javax.ws.rs.ApplicationPath;
 import javax.ws.rs.Path;
 import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
 import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
@@ -53,7 +57,9 @@ import org.apache.cxf.cdi.event.DisposableCreationalContext;
 import org.apache.cxf.cdi.extension.JAXRSServerFactoryCustomizationExtension;
 import org.apache.cxf.feature.Feature;
 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
 import org.apache.cxf.jaxrs.provider.ServerConfigurableFactory;
+import org.apache.cxf.jaxrs.utils.InjectionUtils;
 import org.apache.cxf.jaxrs.utils.ResourceUtils;
 
 /**
@@ -69,6 +75,7 @@ public class JAXRSCdiResourceExtension implements Extension {
     private final List< Bean< ? extends Feature > > featureBeans = new ArrayList< Bean< ? extends Feature > >();
     private final List< CreationalContext< ? > > disposableCreationalContexts =
         new ArrayList< CreationalContext< ? > >();
+    private final Set< Type > contextTypes = new LinkedHashSet<>();
 
     /**
      * Holder of the classified resource classes, converted to appropriate instance
@@ -104,6 +111,28 @@ public class JAXRSCdiResourceExtension implements Extension {
         }
     }
 
+    /**
+     * For any {@link AnnotatedType} that includes a {@link Context} injection point, this method replaces
+     * the field with the following code:
+     * <pre>
+     *     @Inject @ContextResolved T field;
+     * </pre>
+     * For any usage of T that is a valid context object in JAX-RS.
+     *
+     * It also has a side effect of capturing the context object type, in case no
+     * {@link org.apache.cxf.jaxrs.ext.ContextClassProvider} was registered for the type.
+     *
+     * @param processAnnotatedType the annotated type being investigated
+     * @param <X> the generic type of that processAnnotatedType
+     */
+    public <X> void convertContextsToCdi(@Observes @WithAnnotations({Context.class})
+                                             ProcessAnnotatedType<X> processAnnotatedType) {
+        AnnotatedType<X> annotatedType = processAnnotatedType.getAnnotatedType();
+        DelegateContextAnnotatedType<X> type = new DelegateContextAnnotatedType<>(annotatedType);
+        contextTypes.addAll(type.getContextFieldTypes());
+        processAnnotatedType.setAnnotatedType(type);
+    }
+
     @SuppressWarnings("unchecked")
     public <T> void collect(@Observes final ProcessBean< T > event) {
         if (event.getAnnotated().isAnnotationPresent(ApplicationPath.class)) {
@@ -186,6 +215,15 @@ public class JAXRSCdiResourceExtension implements Extension {
             applicationBeans.add(applicationBean);
             event.addBean(applicationBean);
         }
+        // always add the standard context classes
+        InjectionUtils.STANDARD_CONTEXT_CLASSES.stream()
+                .map(this::toClass)
+                .filter(Objects::nonNull)
+                .forEach(contextTypes::add);
+        // add custom contexts
+        contextTypes.addAll(getCustomContextClasses());
+        // register all of the context types
+        contextTypes.forEach(t -> event.addBean(new ContextProducerBean(t)));
     }
 
     /**
@@ -208,6 +246,14 @@ public class JAXRSCdiResourceExtension implements Extension {
         }
     }
 
+    private Class<?> toClass(String name) {
+        try {
+            return Class.forName(name);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     /**
      * Create the JAXRSServerFactoryBean from the application and all discovered service and provider instances.
      * @param application application instance
@@ -421,4 +467,12 @@ public class JAXRSCdiResourceExtension implements Extension {
         }
     }
 
+    public static Set<Class<?>> getCustomContextClasses() {
+        ServiceLoader<ContextClassProvider> classProviders = ServiceLoader.load(ContextClassProvider.class);
+        Set<Class<?>> customContextClasses = new LinkedHashSet<>();
+        for (ContextClassProvider classProvider : classProviders) {
+            customContextClasses.add(classProvider.getContextClass());
+        }
+        return Collections.unmodifiableSet(customContextClasses);
+    }
 }
diff --git a/integration/tracing/tracing-brave/src/main/java/org/apache/cxf/tracing/brave/jaxrs/BraveTracerContextClassProvider.java b/integration/tracing/tracing-brave/src/main/java/org/apache/cxf/tracing/brave/jaxrs/BraveTracerContextClassProvider.java
new file mode 100644
index 0000000..23b1d15
--- /dev/null
+++ b/integration/tracing/tracing-brave/src/main/java/org/apache/cxf/tracing/brave/jaxrs/BraveTracerContextClassProvider.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.tracing.brave.jaxrs;
+
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
+import org.apache.cxf.tracing.TracerContext;
+
+public class BraveTracerContextClassProvider implements ContextClassProvider {
+    @Override
+    public Class<?> getContextClass() {
+        return TracerContext.class;
+    }
+}
diff --git a/integration/tracing/tracing-brave/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider b/integration/tracing/tracing-brave/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
new file mode 100644
index 0000000..c95466d
--- /dev/null
+++ b/integration/tracing/tracing-brave/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
@@ -0,0 +1 @@
+org.apache.cxf.tracing.brave.jaxrs.BraveTracerContextClassProvider
\ No newline at end of file
diff --git a/integration/tracing/tracing-htrace/src/main/java/org/apache/cxf/tracing/htrace/jaxrs/HTraceTracerContextClassProvider.java b/integration/tracing/tracing-htrace/src/main/java/org/apache/cxf/tracing/htrace/jaxrs/HTraceTracerContextClassProvider.java
new file mode 100644
index 0000000..2e6ba5b
--- /dev/null
+++ b/integration/tracing/tracing-htrace/src/main/java/org/apache/cxf/tracing/htrace/jaxrs/HTraceTracerContextClassProvider.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.tracing.htrace.jaxrs;
+
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
+import org.apache.cxf.tracing.TracerContext;
+
+public class HTraceTracerContextClassProvider implements ContextClassProvider {
+    @Override
+    public Class<?> getContextClass() {
+        return TracerContext.class;
+    }
+}
diff --git a/integration/tracing/tracing-htrace/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider b/integration/tracing/tracing-htrace/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
new file mode 100644
index 0000000..9d6fa01
--- /dev/null
+++ b/integration/tracing/tracing-htrace/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
@@ -0,0 +1 @@
+org.apache.cxf.tracing.htrace.jaxrs.HTraceTracerContextClassProvider
\ No newline at end of file
diff --git a/integration/tracing/tracing-opentracing/src/main/java/org/apache/cxf/tracing/opentracing/jaxrs/OpenTracingTracerContextClassProvider.java b/integration/tracing/tracing-opentracing/src/main/java/org/apache/cxf/tracing/opentracing/jaxrs/OpenTracingTracerContextClassProvider.java
new file mode 100644
index 0000000..f37ac0d
--- /dev/null
+++ b/integration/tracing/tracing-opentracing/src/main/java/org/apache/cxf/tracing/opentracing/jaxrs/OpenTracingTracerContextClassProvider.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.tracing.opentracing.jaxrs;
+
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
+import org.apache.cxf.tracing.TracerContext;
+
+public class OpenTracingTracerContextClassProvider implements ContextClassProvider {
+    @Override
+    public Class<?> getContextClass() {
+        return TracerContext.class;
+    }
+}
diff --git a/integration/tracing/tracing-opentracing/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider b/integration/tracing/tracing-opentracing/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
new file mode 100644
index 0000000..4b44ddd
--- /dev/null
+++ b/integration/tracing/tracing-opentracing/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
@@ -0,0 +1 @@
+org.apache.cxf.tracing.opentracing.jaxrs.OpenTracingTracerContextClassProvider
\ No newline at end of file
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/ContextClassProvider.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/ContextClassProvider.java
new file mode 100644
index 0000000..09884f7
--- /dev/null
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/ContextClassProvider.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.ext;
+
+/**
+ * Marker interface that can return the class of a custom context type to be resolved
+ */
+public interface ContextClassProvider {
+    Class<?> getContextClass();
+}
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceContextImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceContextImpl.java
index e6ad96c..af5de2a 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceContextImpl.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceContextImpl.java
@@ -30,9 +30,9 @@ import org.apache.cxf.message.Message;
 
 public class ResourceContextImpl implements ResourceContext {
     private static final String CONTEXT_PROVIDER_PROP = "org.apache.cxf.jaxrs.resource.context.provider";
-    private ClassResourceInfo cri;
-    private Class<?> subClass;
-    private Message m;
+    private final ClassResourceInfo cri;
+    private final Class<?> subClass;
+    private final Message m;
     public ResourceContextImpl(Message m, OperationResourceInfo ori) {
         this.m = m;
         this.cri = ori.getClassResourceInfo();
@@ -53,6 +53,7 @@ public class ResourceContextImpl implements ResourceContext {
         return doInitResource(cls, resource);
     }
 
+    @Override
     public <T> T initResource(T resource) {
         return doInitResource(resource.getClass(), resource);
     }
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientTokenContextClassProvider.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientTokenContextClassProvider.java
new file mode 100644
index 0000000..594355f
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientTokenContextClassProvider.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.oauth2.client;
+
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
+
+public class ClientTokenContextClassProvider implements ContextClassProvider {
+    @Override
+    public Class<?> getContextClass() {
+        return ClientTokenContext.class;
+    }
+}
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider b/rt/rs/security/oauth-parent/oauth2/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
new file mode 100644
index 0000000..612d249
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
@@ -0,0 +1 @@
+org.apache.cxf.rs.security.oauth2.client.ClientTokenContextClassProvider
\ No newline at end of file
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenContextClassProvider.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenContextClassProvider.java
new file mode 100644
index 0000000..e816d19
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/IdTokenContextClassProvider.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.oidc.rp;
+
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
+
+public class IdTokenContextClassProvider implements ContextClassProvider {
+    @Override
+    public Class<?> getContextClass() {
+        return IdTokenContext.class;
+    }
+}
diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoContextClassProvider.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoContextClassProvider.java
new file mode 100644
index 0000000..1f24287
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/UserInfoContextClassProvider.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.oidc.rp;
+
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
+
+public class UserInfoContextClassProvider implements ContextClassProvider {
+    @Override
+    public Class<?> getContextClass() {
+        return UserInfoContext.class;
+    }
+}
diff --git a/rt/rs/security/sso/oidc/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider b/rt/rs/security/sso/oidc/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
new file mode 100644
index 0000000..e85b59b
--- /dev/null
+++ b/rt/rs/security/sso/oidc/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
@@ -0,0 +1,2 @@
+org.apache.cxf.rs.security.oidc.rp.IdTokenContextClassProvider
+org.apache.cxf.rs.security.oidc.rp.UserInfoContextClassProvider
\ No newline at end of file
diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/AbstractCdiSingleAppTest.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/AbstractCdiSingleAppTest.java
index 7a8f914..36eb0dc 100644
--- a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/AbstractCdiSingleAppTest.java
+++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/AbstractCdiSingleAppTest.java
@@ -29,6 +29,7 @@ import javax.ws.rs.core.Response;
 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
 
 import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.message.Message;
 import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
 
 import org.junit.Test;
@@ -37,8 +38,12 @@ public abstract class AbstractCdiSingleAppTest extends AbstractBusClientServerTe
     @Test
     public void testInjectedVersionIsProperlyReturned() {
         Response r = createWebClient(getBasePath() + "/version", MediaType.TEXT_PLAIN).get();
+        String pathInfo = r.getHeaderString(Message.PATH_INFO);
+        String httpMethod = r.getHeaderString(Message.HTTP_REQUEST_METHOD);
         assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
         assertEquals("1.0", r.readEntity(String.class));
+        assertTrue(pathInfo.endsWith("/bookstore/version"));
+        assertEquals("GET", httpMethod);
     }
 
     @Test
diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStore.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStore.java
index 81b113a..bb458af 100644
--- a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStore.java
+++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStore.java
@@ -30,21 +30,29 @@ import javax.ws.rs.POST;
 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.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
 @Path("/bookstore/")
 public class BookStore {
-    @Inject private BookStoreService service;
-    @Inject private String version;
+    private BookStoreService service;
+    private BookStoreVersion bookStoreVersion;
+    private UriInfo uriInfo;
+
+    public BookStore() {
+    }
+
+    @Inject
+    public BookStore(BookStoreService service, BookStoreVersion bookStoreVersion, UriInfo uriInfo) {
+        this.service = service;
+        this.bookStoreVersion = bookStoreVersion;
+        this.uriInfo = uriInfo;
+    }
 
-    @GET
     @Path("/version")
-    @Produces(MediaType.TEXT_PLAIN)
-    public String getVersion() {
-        return version;
+    public BookStoreVersion getVersion() {
+        return bookStoreVersion;
     }
 
     @GET
@@ -66,8 +74,7 @@ public class BookStore {
     @POST
     @Path("/books")
     @Produces(MediaType.APPLICATION_JSON)
-    public Response addBook(@Context final UriInfo uriInfo,
-                            @NotNull @Size(min = 1, max = 50) @FormParam("id") String id,
+    public Response addBook(@NotNull @Size(min = 1, max = 50) @FormParam("id") String id,
                             @NotNull @FormParam("name") String name) {
         final Book book = service.store(id, name);
         return Response.created(uriInfo.getRequestUriBuilder().path(id).build()).entity(book).build();
diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreVersion.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreVersion.java
new file mode 100644
index 0000000..df11897
--- /dev/null
+++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreVersion.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systests.cdi.base;
+
+import java.util.List;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.message.Message;
+import org.apache.cxf.systests.cdi.base.context.CustomContext;
+
+@RequestScoped
+public class BookStoreVersion {
+    @Inject
+    private String version;
+    @Inject
+    private HttpHeaders httpHeaders;
+    @Inject
+    private CustomContext customContext;
+    @GET
+    public Response getVersion() {
+        List<MediaType> mediaTypeList = httpHeaders.getAcceptableMediaTypes();
+
+        String requestMethod = (String)customContext.getMessage().get(Message.HTTP_REQUEST_METHOD);
+        String pathInfo = (String)customContext.getMessage().get(Message.PATH_INFO);
+
+        return Response.ok(version, mediaTypeList.get(0))
+                .header(Message.HTTP_REQUEST_METHOD, requestMethod)
+                .header(Message.PATH_INFO, pathInfo)
+                .build();
+    }
+}
diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContext.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContext.java
new file mode 100644
index 0000000..ecd2663
--- /dev/null
+++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContext.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systests.cdi.base.context;
+
+import org.apache.cxf.message.Message;
+
+public interface CustomContext {
+    Message getMessage();
+}
diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextFeature.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextFeature.java
new file mode 100644
index 0000000..65ce9f4
--- /dev/null
+++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextFeature.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systests.cdi.base.context;
+
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.cxf.jaxrs.ext.ContextClassProvider;
+
+@Provider
+public class CustomContextFeature implements Feature, ContextClassProvider {
+    @Override
+    public boolean configure(FeatureContext context) {
+        context.register(new CustomContextProvider());
+        return true;
+    }
+
+    @Override
+    public Class<?> getContextClass() {
+        return CustomContext.class;
+    }
+}
diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextImpl.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextImpl.java
new file mode 100644
index 0000000..8a07f33
--- /dev/null
+++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextImpl.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systests.cdi.base.context;
+
+import org.apache.cxf.message.Message;
+
+public class CustomContextImpl implements CustomContext {
+    private final Message message;
+
+    public CustomContextImpl(Message message) {
+        this.message = message;
+    }
+
+    @Override
+    public Message getMessage() {
+        return message;
+    }
+}
diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextProvider.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextProvider.java
new file mode 100644
index 0000000..bf955e2
--- /dev/null
+++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/context/CustomContextProvider.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systests.cdi.base.context;
+
+import org.apache.cxf.jaxrs.ext.ContextProvider;
+import org.apache.cxf.message.Message;
+
+public class CustomContextProvider implements ContextProvider<CustomContext> {
+    @Override
+    public CustomContext createContext(Message message) {
+        return new CustomContextImpl(message);
+    }
+}
diff --git a/systests/cdi/base/src/main/resources/META-INF/beans.xml b/systests/cdi/base/src/main/resources/META-INF/beans.xml
index 5446495..fa75404 100644
--- a/systests/cdi/base/src/main/resources/META-INF/beans.xml
+++ b/systests/cdi/base/src/main/resources/META-INF/beans.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0"?>
-<beans xmlns="http://java.sun.com/xml/ns/javaee"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
-		
-</beans>
+<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="all">
+</beans>
\ No newline at end of file
diff --git a/systests/cdi/base/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider b/systests/cdi/base/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
new file mode 100644
index 0000000..6a27659
--- /dev/null
+++ b/systests/cdi/base/src/main/resources/META-INF/services/org.apache.cxf.jaxrs.ext.ContextClassProvider
@@ -0,0 +1 @@
+org.apache.cxf.systests.cdi.base.context.CustomContextFeature
\ No newline at end of file
diff --git a/systests/cdi/pom.xml b/systests/cdi/pom.xml
index 161daf5..74c8524 100644
--- a/systests/cdi/pom.xml
+++ b/systests/cdi/pom.xml
@@ -35,7 +35,7 @@
         <cxf.el.api.version>3.0-b02</cxf.el.api.version>
         <cxf.glassfish.el.version>3.0-b01</cxf.glassfish.el.version>
         <cxf.tomcat.version>8.0.32</cxf.tomcat.version>
-        <cxf.openwebbeans.version>1.7.0</cxf.openwebbeans.version>
+        <cxf.openwebbeans.version>1.7.4</cxf.openwebbeans.version>
     </properties>
     <modules>
         <module>base</module>

-- 
To stop receiving notification emails like this one, please contact
['"commits@cxf.apache.org" <co...@cxf.apache.org>'].