回答我自己的问题,@JeffE 答案的改进版本。基本问题是:
- A
Tomcat6InjectionProvider
由 JSF 2.0 提供,但在某些时候被删除。
- 正如 JeffE 指出的那样,默认
WebContainerInjectionProvider
不处理 @Resource 注释。
您可以在没有上下文条目的情况下克服此问题web.xml
,如下所示:
创建一个名为的文件META-INF/services/com.sun.faces.spi.injectionprovider
并向其中添加以下行:
com.sun.faces.vendor.Tomcat7InjectionProvider:org.apache.catalina.core.DefaultInstanceManager
这一行的意思是,如果部署中存在第二个类,则将第一个类用作注入提供程序。上面的第二个类是 Tomcat 7 的一部分。
编译以下类。
此版本包含对 JeffE 版本的许多改进。具体来说:
- 它根据
@Resource
和@Resources
Javadoc的要求处理超类
- 它在类级别处理
@Resource
和注释@Resources
- 它根据Javadoc
@Resource
的要求处理带有 注释的方法@Resource
- 它按照Javadoc的要求正确处理 s 的空属性或缺失
name
属性@Resource
@Resource
- 它恢复了
Field
的原始访问权限
- 它不依赖于 Tomcat 类。
如果更改包名称,请调整上面的包名称。
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 <a href="http://stackoverflow.com/a/21978577/207421">This StackOverflow
* answer, although what org.apache.catalina.util.Introspection may be and where
* it lives remains a mystery.</a>
*/
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<Resource> 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