以下bean急切地加载,例如
@ManagedBean(eager=true)
@ApplicationScoped
public class EnumConfig {
@PostConstruct
public void init() {
System.out.println("Testing 123...");
FacesContext.getCurrentInstance().getApplication().addELContextListener(
new ELContextListener() {
@Override
public void contextCreated(ELContextEvent event) {
System.out.println("Testing 456...");
event.getELContext().getImportHandler().importClass(
"foo.bar.business.model.enumeration.YesOrNo");
//importHandler.importPackage(
// "foo.bar.business.model.enumeration.preference");
Class<?> clazz = importHandler.resolveClass("YesOrNo");
System.out.println("clazz = " + clazz);
}
}
);
}
}
21:26:48,703 INFO [stdout](MSC服务主题1-4)测试123 ...
21:39:11,976 INFO [stdout](默认任务-9)测试456 ......
我设置了一个断点,我可以看到&#34; foo.bar.business.model.enumeration.YesOrNo&#34;已正确输入classNameMap
。但是,在notAClass
中进行了第二次输入,表示找不到YesOrNo
,这是不好的。
importHandler = {javax.el.ImportHandler@15909}
classNameMap = {java.util.HashMap@15910} size = 1
[0] = {java.util.HashMap$Node@15923}"YesOrNo" -> "foo.bar.business.model.enumeration.YesOrNo"
classMap = {java.util.HashMap@15911} size = 0
staticNameMap = {java.util.HashMap@15912} size = 0
notAClass = {java.util.HashSet@15913} size = 1
[0] = {java.lang.String@15030}"foo.bar.business.model.enumeration.YesOrNo"
packages = {java.util.ArrayList@15914} size = 1
[0] = {java.lang.String@15926}"java.lang"
21:39:11,976 INFO [stdout](默认任务-18)clazz = null
这里是ImportHandler#resolveClass()
的JavaDoc,这似乎表明我正确使用它(没有包名):
public Class resolveClass(String name)
解析班级名称。
参数:
name
- 要解析的类名(没有包名)。返回:
If the class has been imported previously, with importClass(java.lang.String) or importPackage(java.lang.String), then its Class instance. Otherwise null.
抛出:
ELException - if the class is abstract or is an interface, or not public.
参考EL 3.0规范:
1.22.2包,类和静态字段的导入
可以将类或包显式导入EL评估环境。导入包导入包中的所有类。可以导入的类仅限于当前类加载器可以加载的类。
默认情况下,EL环境会导入以下包。
java.lang.*
静态字段也可以静态导入。静态导入的静态字段可以由字段名称引用,不带类名。
包,类和静态字段的导入由ELContext中的ImportHandler处理。
这里是ImportHandler相关代码(see GitHub):
private Class<?> getClassFor(String className) {
if (!notAClass.contains(className)) {
try {
return Class.forName(className, false, getClass().getClassLoader());
} catch (ClassNotFoundException ex) {
notAClass.add(className);
}
}
return null;
}
使用<o:importConstants>
OmniFaces可以正常工作:
<o:importConstants type="foo.bar.business.model.enumeration.YesOrNo"/>
这是OmniFaces方法,使用TagHandler (see GitHub):
/**
* Convert the given type, which should represent a fully qualified name, to a concrete {@link Class} instance.
* @param type The fully qualified name of the class.
* @return The concrete {@link Class} instance.
* @throws IllegalArgumentException When it is missing in the classpath.
*/
static Class<?> toClass(String type) { // Package-private so that ImportFunctions can also use it.
try {
return Class.forName(type, true, Thread.currentThread().getContextClassLoader());
}
catch (ClassNotFoundException e) {
// Perhaps it's an inner enum which is specified as com.example.SomeClass.SomeEnum.
// Let's be lenient on that although the proper type notation should be com.example.SomeClass$SomeEnum.
int i = type.lastIndexOf('.');
if (i > 0) {
try {
return toClass(
new StringBuilder(type.substring(0, i)).append('$').append(type.substring(i + 1)).toString());
}
catch (IllegalArgumentException ignore) {
// Just continue to the IllegalArgumentException on the original ClassNotFoundException.
}
}
throw new IllegalArgumentException(String.format(ERROR_MISSING_CLASS, type), e);
}
}
因此javax.el.ImportHandler
调用getClass().getClassLoader()
而org.omnifaces.taghandler.ImportConstants
调用Thread.currentThread().getContextClassLoader()
。
不应该javax.el.ImportHandler
使用当前的线程类加载器,以便它可以在WEB-INF / classes中加载类吗? javax.el.ImportHandler
是否满足EL规范。要求可导入的类仅限于当前类加载器可以加载的类?我不知道当前的类加载器是否意味着与当前线程关联的线程上下文类加载器。