问题描述:
当用velocity,需要在同一个页面调用两个不同java枚举类的静态方法时,如果有两个枚举类的静态方法同名,则页面上的第二个静态方法调用始终是访问的第一个枚举类方法。
以下是国外朋友详细的问题陈述:
I am using Apache Velocity where I'm calling static Methods on Enums. Now I have two Enums which both have the same static Method-Name. When I call the static Method on the first Enum all works fine. When I call the Method on the second Enum, I get the result of the first Enum.
Example:
public enum A{
VALUE_A1(1), VALUE_A2(2);
private int id;
private A(int id){
this.id = id;
}
public static A getById(int id){
for (A a : values()){
if (a.id==id){
return a;
}
}
return null;
}
}
public enum B{
VALUE_B1(1), VALUE_B2(2);
private int id;
private B(int id){
this.id = id;
}
public static B getById(int id){
...
}
}
I initialized both in Velocity the same way:
VelocityContext context = new VelocityContext();
context.put("A", A.class);
context.put("B", B.class);
context.put("value1", 1);
context.put("value2", 2);
When I now call these Methods in my template, there are some issues. Calling the Method getById() on Enum A works fine. Calling it on Enum B gives me the value of enum A as a result.
$A.getById($value1)
$B.getById($value1)
results in
VALUE_A1
VALUE_A1
and not in
VALUE_A1
VALUE_B1
as expected
When I rename the Method in B and change the template properly, all works fine, but thats not what I want. Am I missing something? Or is it a bug in Apache Velocity?
解决方案:
context.put("A", A.values()[0]);
context.put("B", B.values()[0]);
深入分析:
velocity解析静态类时,会调用静态类的 staticClass.getClass()去缓存静态方法调用,staticClass.getClass()始终是java.lang.Class, 所以velocity内部缓存的所有静态类,只要静态方法签名相同,都默认走缓存获取第一个具有相同方法签名的类对象,调用该类对象的静态方法。
velocity 1.7 源码:
org.apache.velocity.util.ClassUtils.getMethod(String, Object[], Class[], Object, InternalContextAdapter, SimpleNode, boolean):line 189
/*
* like ASTIdentifier, if we have cache information, and the Class of
* Object o is the same as that in the cache, we are safe.
*/
if (icd != null && (o != null && icd.contextData == o.getClass())) //此处o.getClass() == java.lang.Class
{
/*
* get the method from the cache
*/
method = (VelMethod) icd.thingy;
}
org.apache.velocity.util.ClassUtils.getMethod(String, Object[], Class[], Object, InternalContextAdapter, SimpleNode, boolean):line 208
if ((method != null) && (o != null))
{
icd = new IntrospectionCacheData();
icd.contextData = o.getClass(); //此处任何静态类(eg:context.put("A", A.class);)的A.class.getClass() 都相同
icd.thingy = method;
context.icachePut(mck, icd);
}