Tomcat @Resource annotations API annotation stops working in Tomcat 7

后端 未结 4 2042
暗喜
暗喜 2021-01-29 12:44

I have been using Tomcat 6.0.26-6.0.35 for several years with JSF 2 Mojarra, various versions up to 2.1.2 which I have been using for some months. I have several request-scoped

4条回答
  •  醉话见心
    2021-01-29 13:21

    Answering my own question, an improved version of @JeffE's answer. The basic problem is:

    1. A Tomcat6InjectionProvider was provided with JSF 2.0 but was removed at some point.
    2. The default WebContainerInjectionProvider doesn't process @Resource annotations, as JeffE points out.

    You can overcome this without web.xml context-entries as follows:

    1. Create a file called META-INF/services/com.sun.faces.spi.injectionprovider and add the following line to it:

      com.sun.faces.vendor.Tomcat7InjectionProvider:org.apache.catalina.core.DefaultInstanceManager
      

      The meaning of this line is that if the second class is present in the deployment, the first class is used as the injection provider. The second class above is part of Tomcat 7.

    2. Compile the following class.

    This version contains numerous improvements over JeffE's version. Specifically:

    • it processes superclasses, as required by the @Resource and @Resources Javadoc
    • it processes @Resource and @Resources annotations at the class level
    • it processes methods annotated with @Resource, as required by the @Resource Javadoc
    • it handles empty or missing name attributes of @Resources correctly, as required by the @Resource Javadoc
    • it restores the Field's original access
    • it has no dependencies on Tomcat classes.

    Adjust the package name above if you change its package name.

    package com.sun.faces.vendor;
    
    import com.sun.faces.spi.DiscoverableInjectionProvider;
    import com.sun.faces.spi.InjectionProviderException;
    import java.lang.reflect.Field;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.annotation.Resource;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.servlet.ServletContext;
    
    /**
     * @author Jeff E
     * @author Esmond Pitt Improvements named above.
     * 
     * @see javax.annotation.Resource
     *
     * @see This StackOverflow
     * answer, although what org.apache.catalina.util.Introspection may be and where
     * it lives remains a mystery.
     */
    public class Tomcat7InjectionProvider
        extends DiscoverableInjectionProvider
    {
        private Logger logger = Logger.getLogger(this.getClass().getName());
        private ServletContext  servletContext;
    
        private WebContainerInjectionProvider   delegate = new WebContainerInjectionProvider();
    
        public Tomcat7InjectionProvider(ServletContext servletContext)
        {
            logger.config("constructed");
            this.servletContext = servletContext;
        }
    
        @Override
        public void inject(Object managedBean) throws InjectionProviderException
        {
            logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean.getClass().getName()});
            Class clazz = managedBean.getClass();
            do
            {
                List  classResources = new LinkedList<>();
                // Process class-level @Resources and @Resource
                if (clazz.isAnnotationPresent(Resources.class))
                {
                    Resources annotation = clazz.getAnnotation(Resources.class);
                    for (Resource resource : annotation.value())
                    {
                        classResources.add(resource);
                    }
                }
                if (clazz.isAnnotationPresent(Resource.class))
                {
                    Resource    annotation = clazz.getAnnotation(Resource.class);
                    classResources.add(annotation);
                }
                for (Resource annotation : classResources)
                {
                    String  name = annotation.name();
                    // Make sure the resource exists.
                    try
                    {
                        Context ctx = new InitialContext();
                        Object resource = ctx.lookup("java:comp/env/" + name);
                    }
                    catch (NamingException exc)
                    {
                        throw new InjectionProviderException("checking class resource " + annotation.name()+" of "+clazz.getName(), exc);
                    }
                }
                // Process fields with @Resource
                // see org.apache.catalina.core.DefaultInstanceManager
    //            Field[] fields = Introspection.getDeclaredFields(managedBean.getClass());
                Field[] fields = managedBean.getClass().getDeclaredFields();
                for (Field field : fields)
                {
                    if (field.isAnnotationPresent(Resource.class))
                    {
                        Resource annotation = field.getAnnotation(Resource.class);
                        String name = annotation.name();
                        logger.log(Level.CONFIG, "injecting @Resource(name=\"{2}\") into {0}.{1}", new Object[]
                            {
                                managedBean.getClass().getName(), field.getName(), name
                            });
                        try
                        {
                            Context ctx = new InitialContext();
                            Object resource;
                            if (name != null && name.length() > 0)
                            {
                                resource = ctx.lookup("java:comp/env/" + name);
                            }
                            else
                            {
                                resource = ctx.lookup(clazz.getName() + "/" + field.getName());
                            }
                            // field may be private
                            boolean accessibility = field.isAccessible();
                            try
                            {
                                field.setAccessible(true);
                                field.set(managedBean, resource);
                            }
                            finally
                            {
                                field.setAccessible(accessibility);
                            }
                        }
                        catch (NamingException | IllegalAccessException exc)
                        {
                            throw new InjectionProviderException("injecting resource " + annotation.name()+" into "+clazz.getName()+"."+field.getName(), exc);
                        }
                    }
                }
                // Process methods with @Resource
                for (Method method : clazz.getDeclaredMethods())
                {
                    if (method.isAnnotationPresent(Resource.class)
                    && method.getName().startsWith("set")
                    && method.getName().length() > 3
                    && method.getReturnType() == void.class
                    && method.getParameterTypes().length == 1)
                    {
                        // It's a setter with @Resource
                        Resource annotation = method.getAnnotation(Resource.class);
                        String name = annotation.name();
                        logger.log(Level.CONFIG, "injecting @Resource(name=\"{2}\") via {0}.{1}", new Object[]
                            {
                                managedBean.getClass().getName(), method.getName(), name
                            });
                        try
                        {
                            Context ctx = new InitialContext();
                            Object resource;
                            if (name != null && name.length() > 0)
                            {
                                resource = ctx.lookup("java:comp/env/" + name);
                            }
                            else
                            {
                                name = method.getName().substring(3);
                                name = name.substring(0,1).toLowerCase()+name.substring(1);
                                resource = ctx.lookup(clazz.getName() + "/" + name);
                            }
                            // method may be private
                            boolean accessibility = method.isAccessible();
                            try
                            {
                                method.setAccessible(true);
                                method.invoke(managedBean, resource);
                            }
                            finally
                            {
                                method.setAccessible(accessibility);
                            }
                        }
                        catch (NamingException | IllegalAccessException | InvocationTargetException exc)
                        {
                            throw new InjectionProviderException("injecting resource " + annotation.name()+" via "+clazz.getName()+"."+method.getName(), exc);
                        }
                    }
                }
            } while ((clazz = clazz.getSuperclass()) != Object.class);
        }
    
        @Override
        public void invokePostConstruct(Object managedBean) throws InjectionProviderException
        {
            logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean});
            delegate.invokePostConstruct(managedBean);
        }
    
        @Override
        public void invokePreDestroy(Object managedBean) throws InjectionProviderException
        {
            logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean});
            delegate.invokePreDestroy(managedBean);
        }
    }
    

    E&OE

提交回复
热议问题