Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   *
   * Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
   *
   * The contents of this file are subject to the terms of either the GNU
   * General Public License Version 2 only ("GPL") or the Common Development
   * and Distribution License("CDDL") (collectively, the "License").  You
   * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
  * http://glassfish.java.net/public/CDDL+GPL_1_1.html
  * or packager/legal/LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
  * file and include the License file at packager/legal/LICENSE.txt.
  *
  * GPL Classpath Exception:
  * Oracle designates this particular file as subject to the "Classpath"
  * exception as provided by Oracle in the GPL Version 2 section of the License
  * file that accompanied this code.
  *
  * Modifications:
  * If applicable, add the following below the License Header, with the fields
  * enclosed by brackets [] replaced by your own identifying information:
  * "Portions Copyright [year] [name of copyright owner]"
  *
  * Contributor(s):
  * If you wish your version of this file to be governed by only the CDDL or
  * only the GPL Version 2, indicate your decision by adding "[Contributor]
  * elects to include this software in this distribution under the [CDDL or GPL
  * Version 2] license."  If you don't indicate a single choice of license, a
  * recipient has the option to distribute your version of this file under
  * either the CDDL, the GPL Version 2 or to extend the choice of license to
  * its licensees as provided above.  However, if you add GPL Version 2 code
  * and therefore, elected the GPL Version 2 license, then the option applies
  * only if the new code is made subject to such option by the copyright
  * holder.
  */
  
 package com.sun.jersey.server.impl.cdi;
  
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import  javax.enterprise.context.spi.CreationalContext;
 import  javax.enterprise.event.Observes;
 import  javax.enterprise.inject.spi.AfterBeanDiscovery;
 import  javax.enterprise.inject.spi.AnnotatedCallable;
 import  javax.enterprise.inject.spi.AnnotatedConstructor;
 import  javax.enterprise.inject.spi.AnnotatedField;
 import  javax.enterprise.inject.spi.AnnotatedMethod;
 import  javax.enterprise.inject.spi.AnnotatedParameter;
 import  javax.enterprise.inject.spi.AnnotatedType;
 import  javax.enterprise.inject.spi.Bean;
 import  javax.enterprise.inject.spi.BeanManager;
 import  javax.enterprise.inject.spi.BeforeBeanDiscovery;
 import  javax.enterprise.inject.spi.Extension;
 import  javax.enterprise.inject.spi.InjectionPoint;
 import  javax.enterprise.inject.spi.ProcessAnnotatedType;
 import  javax.enterprise.inject.spi.ProcessInjectionTarget;
 import  javax.enterprise.inject.spi.ProcessManagedBean;
 import  javax.enterprise.util.AnnotationLiteral;
 import  javax.inject.Inject;
 import  javax.inject.Provider;

Author(s):
robc
public class CDIExtension implements Extension {
    private static final Logger LOGGER = Logger.getLogger(CDIExtension.class.getName());
    private static class ContextAnnotationLiteral extends AnnotationLiteral<Contextimplements Context {};
    private final Context contextAnnotationLiteral = new ContextAnnotationLiteral();
    private static class InjectAnnotationLiteral extends AnnotationLiteral<Inject> implements Inject {};
    private final Inject injectAnnotationLiteral = new InjectAnnotationLiteral();
    private static class SyntheticQualifierAnnotationImpl extends AnnotationLiteral<SyntheticQualifierimplements SyntheticQualifier {
        private int value;
        public SyntheticQualifierAnnotationImpl(int value) {
            this. = value;
        }
        public int value() {
            return ;
        }
    }
    private Set<Class<? extends Annotation>> knownParameterQualifiers;
    private Map<Class<? extends Annotation>, Parameter.SourceparamQualifiersMap;
    private int nextSyntheticQualifierValue = 0;
    
    private static String JNDI_CDIEXTENSION_NAME = "CDIExtension";
    private static String JNDI_CDIEXTENSION_CTX = "com/sun/jersey/config";
    /*
     * Setting this system property to "true" will force use of the BeanManager to look up the bean for the active CDIExtension,
     * rather than going through a thread local.
     */
    private static final String LOOKUP_EXTENSION_IN_BEAN_MANAGER_SYSTEM_PROPERTY = "com.sun.jersey.server.impl.cdi.lookupExtensionInBeanManager";
    
    public static final boolean lookupExtensionInBeanManager = getLookupExtensionInBeanManager();
    
    private static boolean getLookupExtensionInBeanManager() {
        return Boolean.parseBoolean(System.getProperty("false"));
    }
    /*
     * Returns the instance of CDIExtension that was initialized previously in this same thread, if any.
     */
    public static CDIExtension getInitializedExtension() {
        try {
            InitialContext ic = InitialContextHelper.getInitialContext();
            if (ic == null) {
                throw new RuntimeException();
            }
        } catch (NamingException ex) {
            throw new RuntimeException(ex);
        }
    }
    public CDIExtension() {}
    
    private void initialize(BeanManager manager) {
        // initialize in a separate method because Weld creates a proxy for the extension
        // and we don't want to waste time initializing it
        // workaround for Weld proxy bug
        if (!) {
            try {
                InitialContext ic = InitialContextHelper.getInitialContext();
                if (ic != null) {
                    javax.naming.Context jerseyConfigJNDIContext = createJerseyConfigJNDIContext(ic);
                    jerseyConfigJNDIContext.rebind(this);
                }
            } catch (NamingException ex) {
                throw new RuntimeException(ex);
            }
        }
        
        // annotations to be turned into qualifiers
        Set<Class<? extends Annotation>> set = new HashSet<Class<? extends Annotation>>();
        set.add(CookieParam.class);
        set.add(FormParam.class);
        set.add(HeaderParam.class);
        set.add(MatrixParam.class);
        set.add(PathParam.class);
        set.add(QueryParam.class);
        set.add(Context.class);
         = Collections.unmodifiableSet(set);
        // used to map a qualifier to a Parameter.Source
        Map<Class<? extends Annotation>, Parameter.Sourcemap = new HashMap<Class<? extends Annotation>, Parameter.Source>();
        map.put(CookieParam.class,..);
        map.put(FormParam.class,..);
        map.put(HeaderParam.class,..);
        map.put(MatrixParam.class,..);
        map.put(PathParam.class,..);
        map.put(QueryParam.class,..);
        map.put(Context.class,..);
         = Collections.unmodifiableMap(map);
        
        // pre-defined contextual types
        Set<Class<?>> set3 = new HashSet<Class<?>>();
        // standard types
        set3.add(Application.class);
        set3.add(HttpHeaders.class);
        set3.add(Providers.class);
        set3.add(Request.class);
        set3.add(SecurityContext.class);
        set3.add(UriInfo.class);
        // Jersey extensions
        set3.add(ExceptionMapperContext.class);
        set3.add(ExtendedUriInfo.class);
        set3.add(FeaturesAndProperties.class);
        set3.add(HttpContext.class);
        set3.add(HttpRequestContext.class);
        set3.add(HttpResponseContext.class);
        set3.add(MessageBodyWorkers.class);
        set3.add(ResourceContext.class);
        set3.add(WebApplication.class);
         = Collections.unmodifiableSet(set3);
        // tracks all discovered parameters
        Map<Class<? extends Annotation>, Set<DiscoveredParameter>> map2 = new HashMap<Class<? extends Annotation>, Set<DiscoveredParameter>>();
        for (Class<? extends Annotationqualifier : ) {
            map2.put(qualifiernew HashSet<DiscoveredParameter>());
        }
         = Collections.unmodifiableMap(map2);
        // tracks the synthetic qualifiers we have to create to handle a specific
        // combination of JAX-RS injection annotation + default value + encoded
        // things to do in a second time, i.e. once Jersey has been initialized,
        // as opposed to when CDI delivers the SPI events to its extensions
    }
    private static interface JNDIContextDiver {
        javax.naming.Context stepInto(javax.naming.Context currentContextString currentNamethrows NamingException;
    }
    private static javax.naming.Context diveIntoJNDIContext(javax.naming.Context initialContextJNDIContextDiver diverthrows NamingException {
        Name jerseyConfigCtxName = initialContext.getNameParser("").parse();
        javax.naming.Context currentContext = initialContext;
        for (int i=0; i<jerseyConfigCtxName.size(); i++) {
            currentContext = diver.stepInto(currentContextjerseyConfigCtxName.get(i));
        }
        return currentContext;
    }
    private static javax.naming.Context createJerseyConfigJNDIContext(javax.naming.Context initialContextthrows NamingException {
        return diveIntoJNDIContext(initialContextnew JNDIContextDiver() {
            @Override
            public javax.naming.Context stepInto(javax.naming.Context ctxString namethrows NamingException {
                try {
                    return (javax.naming.Contextctx.lookup(name);
                } catch (NamingException e) {
                    return ctx.createSubcontext(name);
                }
            }
        });
    }
    private static javax.naming.Context lookupJerseyConfigJNDIContext(javax.naming.Context initialContextthrows NamingException {
        return diveIntoJNDIContext(initialContextnew JNDIContextDiver() {
            @Override
            public javax.naming.Context stepInto(javax.naming.Context ctxString namethrows NamingException {
                    return (javax.naming.Contextctx.lookup(name);
            }
        });
    }
    void beforeBeanDiscovery(@Observes BeforeBeanDiscovery event, BeanManager manager) {
        .fine("Handling BeforeBeanDiscovery event");
        initialize(manager);
        // turn JAX-RS injection annotations into CDI qualifiers
        for (Class<? extends Annotationqualifier : ) {
            event.addQualifier(qualifier);
        }
    }
   /*
    *  Holds information on one site (constructor/method argument or field) to be patched.
    */
    private static class PatchInformation {
        private DiscoveredParameter parameter;
        private SyntheticQualifier syntheticQualifier;
        private Annotation annotation;
        private boolean mustAddInject;
        public PatchInformation(DiscoveredParameter parameterSyntheticQualifier syntheticQualifierboolean mustAddInject) {
            this(parametersyntheticQualifiernullmustAddInject);
        }
        public PatchInformation(DiscoveredParameter parameterSyntheticQualifier syntheticQualifierAnnotation annotationboolean mustAddInject) {
            this. = parameter;
            this. = syntheticQualifier;
            this. = annotation;
            this. = mustAddInject;
        }
        public DiscoveredParameter getParameter() {
            return ;
        }
        public SyntheticQualifier getSyntheticQualifier() {
            return ;
        }
        public Annotation getAnnotation() {
            return ;
        }
        
        public boolean mustAddInject() {
            return ;
        }
    }
    <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> event) {
        .fine("Handling ProcessAnnotatedType event for " + event.getAnnotatedType().getJavaClass().getName());
        AnnotatedType<T> type = event.getAnnotatedType();
        /*
        // only scan managed beans
        if (!type.isAnnotationPresent(ManagedBean.class)) {
            return;
        }
        // only scan root resource classes for now
        if (!type.isAnnotationPresent(Path.class)) {
            return;
        }
        */
        // first pass to determine if we need to patch any sites
        // we also record any qualifiers with parameters we encounter
        // so we can create beans for them later
        // TODO - maybe we should detect cases in which the constructor selection
        // rules in CDI and JAX-RS are in conflict -- CDI should win, but
        // the result may surprise the user
        boolean classHasEncodedAnnotation = type.isAnnotationPresent(Encoded.class);
        Set<AnnotatedConstructor<T>> mustPatchConstructors = new HashSet<AnnotatedConstructor<T>>();
        Map<AnnotatedParameter<? super T>, PatchInformationparameterToPatchInfoMap = new HashMap<AnnotatedParameter<? super T>, PatchInformation>();
        for (AnnotatedConstructor<T> constructor : type.getConstructors()) {
            if (processAnnotatedConstructor(constructorclassHasEncodedAnnotationparameterToPatchInfoMap)) {
                mustPatchConstructors.add(constructor);
            }
        }
        Set<AnnotatedField<? super T>> mustPatchFields = new HashSet<AnnotatedField<? super T>>();
        Map<AnnotatedField<? super T>, PatchInformationfieldToPatchInfoMap = new HashMap<AnnotatedField<? super T>, PatchInformation>();
        for (AnnotatedField<? super T> field : type.getFields()) {
            if (processAnnotatedField(fieldtype.getJavaClass(), classHasEncodedAnnotationfieldToPatchInfoMap)) {
                mustPatchFields.add(field);
            }
        }
        Set<AnnotatedMethod<? super T>> mustPatchMethods = new HashSet<AnnotatedMethod<? super T>>();
        Set<AnnotatedMethod<? super T>> setterMethodsWithoutInject = new HashSet<AnnotatedMethod<? super T>>();
        for (AnnotatedMethod<? super T> method : type.getMethods()) {
            if (processAnnotatedMethod(methodtype.getJavaClass(), classHasEncodedAnnotationparameterToPatchInfoMapsetterMethodsWithoutInject)) {
                mustPatchMethods.add(method);
            }
        }
        boolean typeNeedsPatching = !(mustPatchConstructors.isEmpty() && mustPatchFields.isEmpty() && mustPatchMethods.isEmpty());
        // second pass
        if (typeNeedsPatching) {
            AnnotatedTypeImpl<T> newType = new AnnotatedTypeImpl(type);
            Set<AnnotatedConstructor<T>> newConstructors = new HashSet<AnnotatedConstructor<T>>();
            for (AnnotatedConstructor<T> constructor : type.getConstructors()) {
                AnnotatedConstructorImpl<T> newConstructor = new AnnotatedConstructorImpl(constructornewType);
                if (mustPatchConstructors.contains(constructor)) {
                    patchAnnotatedCallable(constructornewConstructorparameterToPatchInfoMap);
                }
                else {
                    copyParametersOfAnnotatedCallable(constructornewConstructor);
                }
                newConstructors.add(newConstructor);
            }
            Set<AnnotatedField<? super T>> newFields = new HashSet<AnnotatedField<? super T>>();
            for (AnnotatedField<? super T> field : type.getFields()) {
                if (mustPatchFields.contains(field)) {
                    PatchInformation patchInfo = fieldToPatchInfoMap.get(field);
                    Set<Annotationannotations = new HashSet<Annotation>();
                    if (patchInfo.mustAddInject()) {
                       annotations.add();
                    }
                    if (patchInfo.getSyntheticQualifier() != null) {
                       annotations.add(patchInfo.getSyntheticQualifier());
                       Annotation skippedQualifier = patchInfo.getParameter().getAnnotation();
                       for (Annotation annotation : field.getAnnotations()) {
                           if (annotation != skippedQualifier) {
                               annotations.add(annotation);
                           }
                       }
                    }
                    else {
                        annotations.addAll(field.getAnnotations());
                    }
                    if (patchInfo.getAnnotation() != null) {
                        annotations.add(patchInfo.getAnnotation());
                    }
                    newFields.add(new AnnotatedFieldImpl<T>(fieldannotationsnewType));
                }
                else {
                    // copy and reparent
                    newFields.add(new AnnotatedFieldImpl<T>(fieldnewType));
                }
            }
            
            Set<AnnotatedMethod<? super T>> newMethods = new HashSet<AnnotatedMethod<? super T>>();
            for (AnnotatedMethod<? super T> method : type.getMethods()) {
                if (mustPatchMethods.contains((AnnotatedMethod<T>)method)) {
                    if (setterMethodsWithoutInject.contains((AnnotatedMethod<T>)method)) {
                        Set<Annotationannotations = new HashSet<Annotation>();
                        annotations.add();
                        for (Annotation annotation : method.getAnnotations()) {
                            if (!.contains(annotation.annotationType())) {
                                annotations.add(annotation);
                            }
                        }
                        AnnotatedMethodImpl<T> newMethod = new AnnotatedMethodImpl<T>(methodannotationsnewType);
                        patchAnnotatedCallable(methodnewMethodparameterToPatchInfoMap);
                        newMethods.add(newMethod);
                    }
                     else {
                        AnnotatedMethodImpl<T> newMethod = new AnnotatedMethodImpl<T>(methodnewType);
                        patchAnnotatedCallable(methodnewMethodparameterToPatchInfoMap);
                        newMethods.add(newMethod);
                    }
                }
                else {
                    AnnotatedMethodImpl<T> newMethod = new AnnotatedMethodImpl<T>(methodnewType);
                    copyParametersOfAnnotatedCallable(methodnewMethod);
                    newMethods.add(newMethod);
                }
            }
            newType.setConstructors(newConstructors);
            newType.setFields(newFields);
            newType.setMethods(newMethods);
            event.setAnnotatedType(newType);
            
            .fine("  replaced annotated type for " + type.getJavaClass());
        }
    }
    private <T> boolean processAnnotatedConstructor(AnnotatedConstructor<T> constructor,
                                                 boolean classHasEncodedAnnotation,
                                                 Map<AnnotatedParameter<? super T>, PatchInformationparameterToPatchInfoMap) {
        boolean mustPatch = false;
        if (constructor.getAnnotation(Inject.class) != null) {
            boolean methodHasEncodedAnnotation = constructor.isAnnotationPresent(Encoded.class);
            for (AnnotatedParameter<T> parameter : constructor.getParameters()) {
                for (Annotation annotation : parameter.getAnnotations()) {
                    Set<DiscoveredParameterdiscovered = .get(annotation.annotationType());
                    if (discovered != null) {
                        if (.contains(annotation.annotationType())) {
                            if (methodHasEncodedAnnotation ||
                                classHasEncodedAnnotation ||
                                parameter.isAnnotationPresent(DefaultValue.class)) {
                                mustPatch = true;
                            }
                            boolean encoded = parameter.isAnnotationPresent(Encoded.class) || methodHasEncodedAnnotation || classHasEncodedAnnotation;
                            DefaultValue defaultValue = parameter.getAnnotation(DefaultValue.class);
                            if (defaultValue != null) {
                                mustPatch = true;
                            }
                            DiscoveredParameter jerseyParameter = new DiscoveredParameter(annotationparameter.getBaseType(), defaultValueencoded);
                            discovered.add(jerseyParameter);
                            .fine("  recorded " + jerseyParameter);
                            parameterToPatchInfoMap.put(parameternew PatchInformation(jerseyParametergetSyntheticQualifierFor(jerseyParameter), false));
                        }
                    }
                }
            }
        }
        
        return mustPatch;
    }
    private <T> boolean processAnnotatedMethod(AnnotatedMethod<? super T> method,
												 Class<T> token,
                                                 boolean classHasEncodedAnnotation,
                                                 Map<AnnotatedParameter<? super T>, PatchInformationparameterToPatchInfoMap,
                                                 Set<AnnotatedMethod<? super T>> setterMethodsWithoutInject) {
        boolean mustPatch = false;
        if (method.getAnnotation(Inject.class) != null) {
            // a method already annotated with @Inject -- we assume the user is
            // aware of CDI and all we need to do is to detect the need for
            // a synthetic qualifier so as to take @DefaultValue and @Encoded into
            // account
            boolean methodHasEncodedAnnotation = method.isAnnotationPresent(Encoded.class);
            for (AnnotatedParameter<? super T> parameter : method.getParameters()) {
                for (Annotation annotation : parameter.getAnnotations()) {
                    Set<DiscoveredParameterdiscovered = .get(annotation.annotationType());
                    if (discovered != null) {
                        if (.contains(annotation.annotationType())) {
                            if (methodHasEncodedAnnotation ||
                                classHasEncodedAnnotation ||
                                parameter.isAnnotationPresent(DefaultValue.class)) {
                                mustPatch = true;
                            }
                            boolean encoded = parameter.isAnnotationPresent(Encoded.class) || methodHasEncodedAnnotation || classHasEncodedAnnotation;
                            DefaultValue defaultValue = parameter.getAnnotation(DefaultValue.class);
                            if (defaultValue != null) {
                                mustPatch = true;
                            }
                            DiscoveredParameter jerseyParameter = new DiscoveredParameter(annotationparameter.getBaseType(), defaultValueencoded);
                            discovered.add(jerseyParameter);
                            .fine("  recorded " + jerseyParameter);
                            parameterToPatchInfoMap.put(parameternew PatchInformation(jerseyParametergetSyntheticQualifierFor(jerseyParameter), false));
                        }
                    }
                }
            }
        }
        else {
            // a method *not* annotated with @Inject -- here we only deal with
            // setter methods with a JAX-RS "qualifier" (Context, QueryParam, etc.)
            // on the method itself
            if (isSetterMethod(method)) {
                boolean methodHasEncodedAnnotation = method.isAnnotationPresent(Encoded.class);
                for (Annotation annotation : method.getAnnotations()) {
                    Set<DiscoveredParameterdiscovered = .get(annotation.annotationType());
                    if (discovered != null) {
                        if (.contains(annotation.annotationType())) {
                            mustPatch = true;
                            setterMethodsWithoutInject.add(method);
                            for (AnnotatedParameter<? super T> parameter : method.getParameters()) {
                                boolean encoded = parameter.isAnnotationPresent(Encoded.class) || methodHasEncodedAnnotation || classHasEncodedAnnotation;
                                DefaultValue defaultValue = parameter.getAnnotation(DefaultValue.class);
                                if (defaultValue == null) {
                                    defaultValue = method.getAnnotation(DefaultValue.class);
                                }
                                DiscoveredParameter jerseyParameter = new DiscoveredParameter(annotationparameter.getBaseType(), defaultValueencoded);
                                discovered.add(jerseyParameter);
                                .fine("  recorded " + jerseyParameter);
                                SyntheticQualifier syntheticQualifier = getSyntheticQualifierFor(jerseyParameter);
                                // if there is no synthetic qualifier, add to the parameter the annotation that was on the method itself
                                Annotation addedAnnotation = syntheticQualifier == null ? annotation : null;
                                parameterToPatchInfoMap.put(parameternew PatchInformation(jerseyParametersyntheticQualifieraddedAnnotationfalse));
                            }
                            break;
                        }
                    }
                }
            }
        }
        return mustPatch;
    }
    private <T> boolean isSetterMethod(AnnotatedMethod<T> method) {
        Method javaMethod = method.getJavaMember();
        if ((javaMethod.getModifiers() & .) != 0 &&
            (javaMethod.getReturnType() == .) &&
            (javaMethod.getName().startsWith("set"))) {
            List<AnnotatedParameter<T>> parameters = method.getParameters();
            if (parameters.size() == 1) {
                return true;
            }
        }
        return false;
    }
    private <T> boolean processAnnotatedField(AnnotatedField<? super T> field,
		 			                          Class<T> token,
                                              boolean classHasEncodedAnnotation,
                                              Map<AnnotatedField<? super T>, PatchInformationfieldToPatchInfoMap) {
        boolean mustPatch = false;
        for (Annotation annotation : field.getAnnotations()) {
            if (.contains(annotation.annotationType())) {
                boolean mustAddInjectAnnotation = !field.isAnnotationPresent(Inject.class);
                if (field.isAnnotationPresent(Encoded.class) ||
                    classHasEncodedAnnotation ||
                    mustAddInjectAnnotation ||
                    field.isAnnotationPresent(DefaultValue.class)) {
                    mustPatch = true;
                }
                Set<DiscoveredParameterdiscovered = .get(annotation.annotationType());
                if (discovered != null) {
                    boolean encoded = field.isAnnotationPresent(Encoded.class) || classHasEncodedAnnotation;
                    DefaultValue defaultValue = field.getAnnotation(DefaultValue.class);
                    DiscoveredParameter parameter = new DiscoveredParameter(annotationfield.getBaseType(), defaultValueencoded);
                    discovered.add(parameter);
                    .fine("  recorded " + parameter);
                    fieldToPatchInfoMap.put(fieldnew PatchInformation(parametergetSyntheticQualifierFor(parameter), mustAddInjectAnnotation));
                }
            }
        }
        
        return mustPatch;
    }
    private <T> void patchAnnotatedCallable(AnnotatedCallable<? super T> callable,
                                            AnnotatedCallableImpl<T> newCallable,
		 			                        Map<AnnotatedParameter<? super T>, PatchInformationparameterToPatchInfoMap) {
        List<AnnotatedParameter<T>> newParams = new ArrayList<AnnotatedParameter<T>>();
        for (AnnotatedParameter<? super T> parameter : callable.getParameters()) {
            PatchInformation patchInfo = parameterToPatchInfoMap.get(parameter);
            if (patchInfo != null) {
                Set<Annotationannotations = new HashSet<Annotation>();
                // in reality, this cannot happen
                if (patchInfo.mustAddInject()) {
                   annotations.add();
                }
                
                if (patchInfo.getSyntheticQualifier() != null) {
                   annotations.add(patchInfo.getSyntheticQualifier());
                   Annotation skippedQualifier = patchInfo.getParameter().getAnnotation();
                   for (Annotation annotation : parameter.getAnnotations()) {
                       if (annotation != skippedQualifier) {
                           annotations.add(annotation);
                       }
                   }
                }
                else {
                    annotations.addAll(parameter.getAnnotations());
                }
                if (patchInfo.getAnnotation() != null) {
                    annotations.add(patchInfo.getAnnotation());
                }
                newParams.add(new AnnotatedParameterImpl<T>(parameterannotationsnewCallable));
            }
            else {
                newParams.add(new AnnotatedParameterImpl<T>(parameternewCallable));
            }
        }
        newCallable.setParameters(newParams);
    }
    private <T> void copyParametersOfAnnotatedCallable(AnnotatedCallable<? super T> callableAnnotatedCallableImpl<T> newCallable) {
        // copy and reparent all the parameters
        List<AnnotatedParameter<T>> newParams = new ArrayList<AnnotatedParameter<T>>();
        for (AnnotatedParameter<? super T> parameter : callable.getParameters()) {
            newParams.add(new AnnotatedParameterImpl<T>(parameternewCallable));
        }
        newCallable.setParameters(newParams);
    }
        SyntheticQualifier result = .get(parameter);
        if (result == null) {
            // only create a synthetic qualifier if we're dealing with @DefaultValue
            // or @Encoded; this way the application can still use vanilla param
            // annotations as qualifiers
            if (parameter.isEncoded() || parameter.getDefaultValue() != null) {
                result = new SyntheticQualifierAnnotationImpl(++);
                .put(parameterresult);
                .fine("  created synthetic qualifier " + result);
            }
        }
        return result;
    }
    
    // taken from ReflectionHelper
    private static Class getClassOfType(Type type) {
        if (type instanceof Class) {
            return (Class)type;
        } else if (type instanceof GenericArrayType) {
            GenericArrayType arrayType = (GenericArrayType)type;
            Type t = arrayType.getGenericComponentType();
            if (t instanceof Class) {
                Class c = (Class)t;
                try {
                    // TODO is there a better way to get the Class object
                    // representing an array
                    Object o = Array.newInstance(c, 0);
                    return o.getClass();
                } catch (Exception e) {
                    throw new IllegalArgumentException(e);
                }
            }
        } else if (type instanceof ParameterizedType) {
            ParameterizedType subType = (ParameterizedType)type;
            Type t = subType.getRawType();
            if (t instanceof Class) {
                return (Class)t;
            }
        }
        return null;
    }
    <T> void processInjectionTarget(@Observes ProcessInjectionTarget<T> event) {
        .fine("Handling ProcessInjectionTarget event for " + event.getAnnotatedType().getJavaClass().getName());
    }
    
    /*
    void processBean(@Observes ProcessBean<?> event) {
        LOGGER.fine("Handling ProcessBean event for " + event.getBean().getBeanClass().getName());
    }
    */
    void processManagedBean(@Observes ProcessManagedBean<?> event) {
        .fine("Handling ProcessManagedBean event for " + event.getBean().getBeanClass().getName());
        // TODO - here we should check that all the rules have been followed
        // and call addDefinitionError for each problem we encountered
        
        Bean<?> bean = event.getBean();
        for (InjectionPoint injectionPoint : bean.getInjectionPoints()) {
            StringBuilder sb = new StringBuilder();
            sb.append("  found injection point ");
            sb.append(injectionPoint.getType());
            for (Annotation annotation : injectionPoint.getQualifiers()) {
                sb.append(" ");
                sb.append(annotation);
            }
            .fine(sb.toString());
        }
    }
    void afterBeanDiscovery(@Observes AfterBeanDiscovery event) {
        .fine("Handling AfterBeanDiscovery event");
        addPredefinedContextBeans(event);
        
        // finally define beans for all qualifiers we discovered
        
        BeanGenerator beanGenerator = new BeanGenerator("com/sun/jersey/server/impl/cdi/generated/Bean");
        for (Map.Entry<Class<? extends Annotation>, Set<DiscoveredParameter>> entry  : .entrySet()) {
            Class<? extends Annotationqualifier = entry.getKey();
            for (DiscoveredParameter parameter : entry.getValue()) {
                Annotation annotation = parameter.getAnnotation();
                Class<?> klass = getClassOfType(parameter.getType());
                if (annotation.annotationType() == Context.class &&
                        .contains(klass) &&
                        !parameter.isEncoded() &&
                        parameter.getDefaultValue() == null) {
                    continue;
                }
                SyntheticQualifier syntheticQualifier = .get(parameter);
                Annotation theQualifier = syntheticQualifier != null ? syntheticQualifier : annotation;
                Set<Annotationannotations = new HashSet<Annotation>();
                annotations.add(theQualifier);
                // TODO - here we pass a single annotation as the second argument,
                // i.e. the qualifier itself, but to be true to Jersey semantics we
                // should pass in all the annotations that were on the original program
                // element.
                // The problem here is that (1) we don't have the original program
                // element any more and (2) a single DiscoveredParameter may have
                // been encountered in multiple places with different annotations
                
                Parameter jerseyParameter = new Parameter(
                                                    new Annotation[]{ annotation },
                                                    annotation,
                                                    .get(annotation.annotationType()),
                                                    parameter.getValue(),
                                                    parameter.getType(),
                                                    klass,
                                                    parameter.isEncoded(),
                                                    (parameter.getDefaultValue() == null ? null : parameter.getDefaultValue().value()));
                Class<?> beanClass = beanGenerator.createBeanClass();
                ParameterBean bean = new ParameterBean(beanClassparameter.getType(), annotationsparameterjerseyParameter);
                .add(bean);
                event.addBean(bean);
                .fine("Added bean for parameter " + parameter + " and qualifier " + theQualifier);
            }
        }
    }
    /*
     * Adds a CDI bean for each @Context type we support out of the box
     */
    private void addPredefinedContextBeans(AfterBeanDiscovery event) {
        // all standard types first
        // @Context Application
        event.addBean(new PredefinedBean<Application>(Application.class));
        // @Context HttpHeaders
        event.addBean(new PredefinedBean<HttpHeaders>(HttpHeaders.class));
        // @Context Providers
        event.addBean(new PredefinedBean<Providers>(Providers.class));
        // @Context Request
        event.addBean(new PredefinedBean<Request>(Request.class));
        // @Context SecurityContext
        event.addBean(new PredefinedBean<SecurityContext>(SecurityContext.class));
        // @Context UriInfo
        event.addBean(new PredefinedBean<UriInfo>(UriInfo.class));
        
        // now the Jersey extensions
        // @Context ExceptionMapperContext
        // @Context ExtendedUriInfo
        event.addBean(new PredefinedBean<ExtendedUriInfo>(ExtendedUriInfo.class));
        
        // @Context FeaturesAndProperties
        // @Context HttpContext
        event.addBean(new PredefinedBean<HttpContext>(HttpContext.class));
        // @Context HttpRequestContext
        // @Context HttpResponseContext
        // @Context MessageBodyWorkers
        // @Context ResourceContext
        event.addBean(new PredefinedBean<ResourceContext>(ResourceContext.class));
        // @Context WebApplication
        event.addBean(new ProviderBasedBean<WebApplication>(WebApplication.classnew Provider<WebApplication>() {
            public WebApplication get() {
                return ;
            }
        }, ));
    }
    
    void setWebApplication(WebApplication wa) {
         = wa;
    }
    
        return ;
    }
    
    void setResourceConfig(ResourceConfig rc) {
         = rc;
    }
    
        return ;
    }
    /*
     * Called after the WebApplication and ResourceConfig have been set,
     * i.e. when Jersey is in a somewhat initialized state.
     * 
     * By contrast, all the CDI driven code earlier in this source file
     * runs before Jersey gets a chance to initialize itself.
     */
    void lateInitialize() {
        try {
            for (InitializedLater object : ) {
                object.later();
            }
        }
        finally {
            // clear the JNDI reference as soon as possible
            if (!) {
                try {
                    InitialContext ic = InitialContextHelper.getInitialContext();
                    if (ic != null) {
                        lookupJerseyConfigJNDIContext(ic).unbind();
                    }
                } catch (NamingException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }
    
    /*
     * Constructs an object by delegating to the ServerInjectableProviderFactory of the WebApplication
     */
    class PredefinedBean<T> extends AbstractBean<T> {
        private Annotation qualifier;
        public PredefinedBean(Class<T> klassAnnotation qualifier) {
            super(klassqualifier);
            this. = qualifier;
        }
        @Override
        public T create(CreationalContext<T> creationalContext) {
            Injectable<T> injectable = .getServerInjectableProviderFactory().
                    getInjectable(.annotationType(), nullgetBeanClass(), .);
            if (injectable == null) {
                Errors.error("No injectable for " + getBeanClass().getName());
                return null;
            }
            return injectable.getValue();
        }
    }
    /*
     * Constructs an object by delegating to the Injectable for a Jersey parameter
     */
    class ParameterBean<T> extends AbstractBean<T> implements InitializedLater {
        private DiscoveredParameter discoveredParameter;
        private Parameter parameter;
        private Injectable<T> injectable;
        private boolean processed = false;
        public ParameterBean(Class<?> klassType typeSet<Annotationqualifiers,
                DiscoveredParameter discoveredParameterParameter parameter) {
            super(klasstypequalifiers);
            this. = discoveredParameter;
            this. = parameter;
        }
        public void later() {
            if ( != null) {
                return;
            }
            if ()
                return;
            
             = true;
            boolean registered = .getServerInjectableProviderFactory().
                    isParameterTypeRegistered();
            if (!registered) {
                Errors.error("Parameter type not registered " + );
            }
            // TODO - here it just doesn't seem possible to remove the cast
                    getInjectable(.);
            if ( == null) {
                Errors.error("No injectable for parameter " + );
            }
        }
        @Override
        public T create(CreationalContext<T> creationalContext) {
            if ( == null) {
                later();
                if ( == null) {
                    return null;
                }
            }
            try {
                return .getValue();
            } catch (IllegalStateException e) {
                if ( instanceof AbstractHttpContextInjectable) {
                    return (T)((AbstractHttpContextInjectable)).getValue(.getThreadLocalHttpContext());
                }
                else {
                    throw e;
                }
            }
        }
    }