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
Answering my own question, an improved version of @JeffE's answer. The basic problem is:
Tomcat6InjectionProvider
was provided with JSF 2.0 but was removed at some point.WebContainerInjectionProvider
doesn't process @Resource annotations, as JeffE points out.You can overcome this without web.xml
context-entries as follows:
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.
Compile the following class.
This version contains numerous improvements over JeffE's version. Specifically:
@Resource
and @Resources
Javadoc@Resource
and @Resources
annotations at the class level@Resource
, as required by the @Resource
Javadocname
attributes of @Resource
s correctly, as required by the @Resource
JavadocField
's original accessAdjust 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