enjoy 3.3 release ^_^

This commit is contained in:
James
2017-11-21 22:43:34 +08:00
parent 28eb105ffa
commit 61aa1d2082
70 changed files with 3378 additions and 299 deletions

View File

@@ -94,9 +94,11 @@ public class Compare extends Expr {
case Arith.FLOAT:
// 此法仅适用于两个对象类型相同的情况,升级为 BigDecimal 后精度会再高几个数量级
// return Float.floatToIntBits(l.floatValue()) == Float.floatToIntBits(r.floatValue());
return l.floatValue() == r.floatValue();
case Arith.DOUBLE:
// 此法仅适用于两个对象类型相同的情况,升级为 BigDecimal 后精度会再高几个数量级
// return Double.doubleToLongBits(l.doubleValue()) == Double.doubleToLongBits(r.doubleValue());
return l.doubleValue() == r.doubleValue();
case Arith.BIGDECIMAL:
BigDecimal[] bd = toBigDecimals(l, r);
return (bd[0]).compareTo(bd[1]) == 0;
@@ -120,8 +122,10 @@ public class Compare extends Expr {
return l.longValue() > r.longValue();
case Arith.FLOAT:
// return Float.floatToIntBits(l.floatValue()) > Float.floatToIntBits(r.floatValue());
return l.floatValue() > r.floatValue();
case Arith.DOUBLE:
// return Double.doubleToLongBits(l.doubleValue()) > Double.doubleToLongBits(r.doubleValue());
return l.doubleValue() > r.doubleValue();
case Arith.BIGDECIMAL:
BigDecimal[] bd = toBigDecimals(l, r);
return (bd[0]).compareTo(bd[1]) > 0;
@@ -150,8 +154,10 @@ public class Compare extends Expr {
return l.longValue() >= r.longValue();
case Arith.FLOAT:
// return Float.floatToIntBits(l.floatValue()) >= Float.floatToIntBits(r.floatValue());
return l.floatValue() >= r.floatValue();
case Arith.DOUBLE:
// return Double.doubleToLongBits(l.doubleValue()) >= Double.doubleToLongBits(r.doubleValue());
return l.doubleValue() >= r.doubleValue();
case Arith.BIGDECIMAL:
BigDecimal[] bd = toBigDecimals(l, r);
return (bd[0]).compareTo(bd[1]) >= 0;
@@ -180,8 +186,10 @@ public class Compare extends Expr {
return l.longValue() < r.longValue();
case Arith.FLOAT:
// return Float.floatToIntBits(l.floatValue()) < Float.floatToIntBits(r.floatValue());
return l.floatValue() < r.floatValue();
case Arith.DOUBLE:
// return Double.doubleToLongBits(l.doubleValue()) < Double.doubleToLongBits(r.doubleValue());
return l.doubleValue() < r.doubleValue();
case Arith.BIGDECIMAL:
BigDecimal[] bd = toBigDecimals(l, r);
return (bd[0]).compareTo(bd[1]) < 0;
@@ -210,8 +218,10 @@ public class Compare extends Expr {
return l.longValue() <= r.longValue();
case Arith.FLOAT:
// return Float.floatToIntBits(l.floatValue()) <= Float.floatToIntBits(r.floatValue());
return l.floatValue() <= r.floatValue();
case Arith.DOUBLE:
// return Double.doubleToLongBits(l.doubleValue()) <= Double.doubleToLongBits(r.doubleValue());
return l.doubleValue() <= r.doubleValue();
case Arith.BIGDECIMAL:
BigDecimal[] bd = toBigDecimals(l, r);
return (bd[0]).compareTo(bd[1]) <= 0;

View File

@@ -72,10 +72,6 @@ public class Const extends Expr {
return value;
}
public String toString() {
return value.toString();
}
public boolean isStr() {
return type == Sym.STR;
}
@@ -139,6 +135,10 @@ public class Const extends Expr {
public Double getDouble() {
return (Double)value;
}
public String toString() {
return value != null ? value.toString() : "null";
}
}

View File

@@ -16,6 +16,7 @@
package com.jfinal.template.expr.ast;
import java.util.ArrayList;
import java.util.List;
import com.jfinal.template.TemplateException;
import com.jfinal.template.stat.Scope;
@@ -25,24 +26,40 @@ import com.jfinal.template.stat.Scope;
*/
public class ExprList extends Expr {
public static final Expr NULL_EXPR = NullExpr.me;
public static final Expr[] NULL_EXPR_ARRAY = new Expr[0];
public static final ExprList NULL_EXPR_LIST = new ExprList(new ArrayList<Expr>(0));
public static final Object[] NULL_OBJECT_ARRAY = new Object[0];
public static final ExprList NULL_EXPR_LIST = new ExprList();
private Expr[] exprArray;
private ExprList() {
this.exprArray = NULL_EXPR_ARRAY;
}
public ExprList(List<Expr> exprList) {
if (exprList != null && exprList.size() > 0) {
if (exprList.size() > 0) {
exprArray = exprList.toArray(new Expr[exprList.size()]);
} else {
exprArray = NULL_EXPR_ARRAY;
}
}
/**
* 持有 ExprList 的指令可以通过此方法提升 AST 执行性能
* 1当 exprArray.length == 1 时返回 exprArray[0]
* 2当 exprArray.length == 0 时返回 NullExpr
* 3其它情况返回 ExprList 自身
*
* 意义在于,当满足前面两个条件时,避免掉了 ExprList.eval(...) 方法中的判断与循环
*/
public Expr getActualExpr() {
if (exprArray.length == 1) {
return exprArray[0];
} else if (exprArray.length == 0) {
return NULL_EXPR;
} else {
return this;
}
}
public Expr[] getExprArray() {
return exprArray;
}
@@ -54,6 +71,14 @@ public class ExprList extends Expr {
return exprArray[index];
}
public Expr getFirstExpr() {
return exprArray.length > 0 ? exprArray[0] : null;
}
public Expr getLastExpr() {
return exprArray.length > 0 ? exprArray[exprArray.length - 1] : null;
}
public int length() {
return exprArray.length;
}
@@ -62,11 +87,20 @@ public class ExprList extends Expr {
* 对所有表达式求值,只返回最后一个表达式的值
*/
public Object eval(Scope scope) {
Object ret = null;
for (Expr expr : exprArray) {
ret = expr.eval(scope);
// 优化:绝大多数情况下 length 等于 1
if (exprArray.length == 1) {
return exprArray[0].eval(scope);
}
return ret;
if (exprArray.length == 0) {
return null;
}
int end = exprArray.length - 1;
for (int i=0; i<end; i++) {
exprArray[i].eval(scope);
}
return exprArray[end].eval(scope);
}
/**
@@ -87,3 +121,4 @@ public class ExprList extends Expr {

View File

@@ -17,6 +17,7 @@
package com.jfinal.template.expr.ast;
import java.lang.reflect.Array;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.StrKit;
// import com.jfinal.plugin.activerecord.Model;
// import com.jfinal.plugin.activerecord.Record;
@@ -40,6 +41,7 @@ public class Field extends Expr {
private Expr expr;
private String fieldName;
private String getterName;
private long getterNameHash;
public Field(Expr expr, String fieldName, Location location) {
if (expr == null) {
@@ -48,6 +50,8 @@ public class Field extends Expr {
this.expr = expr;
this.fieldName = fieldName;
this.getterName = "get" + StrKit.firstCharToUpperCase(fieldName);
// fnv1a64 hash 到比 String.hashCode() 更大的 long 值范围
this.getterNameHash = HashKit.fnv1a64(getterName);
this.location = location;
}
@@ -65,7 +69,8 @@ public class Field extends Expr {
}
Class<?> targetClass = target.getClass();
String key = FieldKit.getFieldKey(targetClass, getterName);
Long key = buildFieldKey(targetClass);
MethodInfo getter;
try {
getter = MethodKit.getGetterMethod(key, targetClass, getterName);
@@ -112,6 +117,10 @@ public class Field extends Expr {
}
throw new TemplateException("Field not found: \"" + fieldName + "\" and getter method not found: \"" + getterName + "()\"", location);
}
private Long buildFieldKey(Class<?> targetClass) {
return targetClass.getName().hashCode() ^ getterNameHash;
}
}

View File

@@ -17,21 +17,21 @@
package com.jfinal.template.expr.ast;
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
/**
* FieldKit
*/
public class FieldKit {
private static final ConcurrentHashMap<String, Object> fieldCache = new ConcurrentHashMap<String, Object>();
private static final HashMap<Long, Object> fieldCache = new HashMap<Long, Object>();
public static Field getField(String key, Class<?> targetClass, String fieldName) {
public static Field getField(Long key, Class<?> targetClass, String fieldName) {
Object field = fieldCache.get(key);
if (field == null) {
field = doGetField(targetClass, fieldName);
if (field != null) {
fieldCache.putIfAbsent(key, field);
fieldCache.put(key, field);
} else {
// 对于不存在的 Field只进行一次获取操作主要为了支持 null safe未来需要考虑内存泄漏风险
fieldCache.put(key, Boolean.FALSE);
@@ -49,14 +49,6 @@ public class FieldKit {
}
return null;
}
/**
* 获取 Field 用于缓存的 key
*/
public static String getFieldKey(Class<?> targetClass, String getterName) {
return new StringBuilder(64).append(targetClass.getName())
.append('.').append(getterName).toString();
}
}

View File

@@ -58,10 +58,10 @@ public class ForCtrl extends Expr {
/**
* exprList? ';' expr? ';' exprList?
*/
public ForCtrl(Expr init, Expr cond, Expr update, Location location) {
this.init = init;
public ForCtrl(ExprList init, Expr cond, ExprList update, Location location) {
this.init = init.getActualExpr();
this.cond = cond;
this.update = update;
this.update = update.getActualExpr();
this.id = null;
this.expr = null;
this.location = location;

View File

@@ -37,6 +37,16 @@ public class Logic extends Expr {
private Expr left; // ! 运算没有 left 参数
private Expr right;
// 默认为新工作模式
private static boolean newWorkMode = true;
/**
* 设置为旧工作模式,为了兼容 jfinal 3.3 之前的版本
*/
@Deprecated
public static void setToOldWorkMode() {
newWorkMode = false;
}
/**
* 构造 || && 结点
*/
@@ -95,44 +105,55 @@ public class Logic extends Expr {
* 规则:
* 1null 返回 false
* 2boolean 类型,原值返回
* 3Map、Connection(List被包括在内) 返回 size() > 0
* 4数组,返回 length > 0
* 5String、StringBuilder、StringBuffer 等继承自 CharSequence 类的对象,返回 length > 0
* 6Number 类型,返回 value != 0
* 7Iterator 返回 hasNext() 值
* 8其它返回 true
* 3String、StringBuilder 等一切继承自 CharSequence 类的对象,返回 length > 0
* 4其它返回 true
*
* 通过 Logic.setToOldWorkMode() 设置,可支持老版本中的以下四个规则:
* 1Number 类型,返回 value != 0
* 2Map、Collection(List被包括在内) 返回 size() > 0
* 3数组返回 length > 0
* 4Iterator 返回 hasNext() 值
*/
public static boolean isTrue(Object v) {
if (v == null) {
return false;
}
if (v instanceof Boolean) {
return (Boolean)v;
}
if (v instanceof Collection) {
return ((Collection<?>)v).size() > 0;
}
if (v instanceof Map) {
return ((Map<?, ?>)v).size() > 0;
}
if (v.getClass().isArray()) {
return Array.getLength(v) > 0;
}
if (v instanceof CharSequence) {
return ((CharSequence)v).length() > 0;
}
if (v instanceof Number) {
if (v instanceof Double) {
return ((Number)v).doubleValue() != 0;
// 如果不是新工作模式,则对下面类型进行判断
if ( !newWorkMode ) {
if (v instanceof Number) {
if (v instanceof Double) {
return ((Number)v).doubleValue() != 0;
}
if (v instanceof Float) {
return ((Number)v).floatValue() != 0;
}
return ((Number)v).intValue() != 0;
}
if (v instanceof Float) {
return ((Number)v).floatValue() != 0;
// 下面四种类型的判断已提供了 shared method 扩展,用法如下:
// #if(notEmpty(object)) 以及 #if(isEmpty(object))
if (v instanceof Collection) {
return ((Collection<?>)v).size() > 0;
}
if (v instanceof Map) {
return ((Map<?, ?>)v).size() > 0;
}
if (v.getClass().isArray()) {
return Array.getLength(v) > 0;
}
if (v instanceof Iterator) {
return ((Iterator<?>)v).hasNext();
}
return ((Number)v).intValue() != 0;
}
if (v instanceof Iterator) {
return ((Iterator<?>)v).hasNext();
}
return true;
}

View File

@@ -26,14 +26,14 @@ import java.lang.reflect.Modifier;
*/
public class MethodInfo {
protected final String key;
protected final Long key;
protected final Class<?> clazz;
protected final Method method;
protected final boolean isVarArgs;
protected final Class<?>[] paraTypes;
public MethodInfo(String key, Class<?> clazz, Method method) {
public MethodInfo(Long key, Class<?> clazz, Method method) {
this.key = key;
this.clazz = clazz;
this.method = method;
@@ -64,7 +64,7 @@ public class MethodInfo {
return method.invoke(target, finalArgValues);
}
public String getKey() {
public Long getKey() {
return key;
}

View File

@@ -26,7 +26,7 @@ public class MethodInfoExt extends MethodInfo {
protected Object objectOfExtensionClass;
public MethodInfoExt(Object objectOfExtensionClass, String key, Class<?> clazz, Method method) {
public MethodInfoExt(Object objectOfExtensionClass, Long key, Class<?> clazz, Method method) {
super(key, clazz, method);
this.objectOfExtensionClass = objectOfExtensionClass;

View File

@@ -0,0 +1,132 @@
/**
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jfinal.template.expr.ast;
import com.jfinal.kit.HashKit;
/**
* MethodKeyBuilder
*/
public abstract class MethodKeyBuilder {
/**
* 生成指定 class、指定方法名、指定方法形参类型的 key 值,用于缓存
*/
public abstract Long getMethodKey(Class<?> targetClass, String methodName, Class<?>[] argTypes);
// 默认使用 FastMethodKeyBuilder
static MethodKeyBuilder instance = new FastMethodKeyBuilder();
public static MethodKeyBuilder getInstance() {
return instance;
}
/**
* 切换到 StrictMethodKeyBuilder
*
* <pre>
* 特别注意:
* 如果希望将 configEngine(Engine me) 中的 Engine 切换到 StrictMethodKeyBuilder
* 需要在 YourJFinalConfig extends JFinalConfig 中利用如下代码块才能生效:
* static {
* MethodKeyBuilder.useStrictMethodKeyBuilder();
* }
*
* 原因是在 com.jfinal.core.Config 中 new Engine() 时 useStrictMethodKeyBuilder()
* 方法并未生效,所以 extension method 生成 method key 时仍然使用的是 FastMethodKeyBuilder
* 以至于在运行时,使用 StrictMethodKeyBuilder 生成的 key 找不到 extension method
*
* </pre>
*/
public static void useStrictMethodKeyBuilder() {
MethodKeyBuilder.instance = new StrictMethodKeyBuilder();
}
/**
* 切换到用户自定义 MethodKeyBuilder
*/
public static void setMethodKeyBuilder(MethodKeyBuilder methodKeyBuilder) {
if (methodKeyBuilder == null) {
throw new IllegalArgumentException("methodKeyBuilder can not be null");
}
MethodKeyBuilder.instance = methodKeyBuilder;
}
/**
* FastMethodKeyBuilder
*
* targetClass、methodName、argTypes 的 hash 直接使用 String.hashCode()
* String.hashCode() 会被缓存,性能更好
*/
public static class FastMethodKeyBuilder extends MethodKeyBuilder {
public Long getMethodKey(Class<?> targetClass, String methodName, Class<?>[] argTypes) {
long hash = HashKit.FNV_OFFSET_BASIS_64;
hash ^= targetClass.getName().hashCode();
hash *= HashKit.FNV_PRIME_64;
hash ^= methodName.hashCode();
hash *= HashKit.FNV_PRIME_64;
if (argTypes != null) {
for (int i=0; i<argTypes.length; i++) {
Class<?> type = argTypes[i];
if (type != null) {
hash ^= type.getName().hashCode();
hash *= HashKit.FNV_PRIME_64;
}
}
}
return hash;
}
}
/**
* StrictMethodKeyBuilder
*
* targetClass、methodName、argTypes 三部分全部使用 fnv1a64 算法计算 hash
*/
public static class StrictMethodKeyBuilder extends MethodKeyBuilder {
public Long getMethodKey(Class<?> targetClass, String methodName, Class<?>[] argTypes) {
long hash = HashKit.FNV_OFFSET_BASIS_64;
hash = fnv1a64(hash, targetClass.getName());
hash = fnv1a64(hash, methodName);
if (argTypes != null) {
for (int i=0; i<argTypes.length; i++) {
Class<?> type = argTypes[i];
if (type != null) {
hash = fnv1a64(hash, type.getName());
}
}
}
return hash;
}
private long fnv1a64(long offsetBasis, String key) {
long hash = offsetBasis;
for(int i=0, size=key.length(); i<size; i++) {
hash ^= key.charAt(i);
hash *= HashKit.FNV_PRIME_64;
}
return hash;
}
}
}

View File

@@ -22,8 +22,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.ReflectKit;
import com.jfinal.template.ext.extensionmethod.ByteExt;
import com.jfinal.template.ext.extensionmethod.DoubleExt;
@@ -42,7 +40,7 @@ public class MethodKit {
private static final Set<String> forbiddenMethods = new HashSet<String>();
private static final Set<Class<?>> forbiddenClasses = new HashSet<Class<?>>();
private static final Map<Class<?>, Class<?>> primitiveMap = new HashMap<Class<?>, Class<?>>();
private static final ConcurrentHashMap<String, Object> methodCache = new ConcurrentHashMap<String, Object>();
private static final HashMap<Long, Object> methodCache = new HashMap<Long, Object>();
// 初始化在模板中调用 method 时所在的被禁止使用类
static {
@@ -105,12 +103,12 @@ public class MethodKit {
public static MethodInfo getMethod(Class<?> targetClass, String methodName, Object[] argValues) {
Class<?>[] argTypes = getArgTypes(argValues);
String key = getMethodKey(targetClass, methodName, argTypes);
Long key = getMethodKey(targetClass, methodName, argTypes);
Object method = methodCache.get(key);
if (method == null) {
method = doGetMethod(key, targetClass, methodName, argTypes);
if (method != null) {
methodCache.putIfAbsent(key, method);
methodCache.put(key, method);
} else {
// 对于不存在的 Method只进行一次获取操作主要为了支持 null safe未来需要考虑内存泄漏风险
methodCache.put(key, Boolean.FALSE);
@@ -123,12 +121,12 @@ public class MethodKit {
* 获取 getter 方法
* 使用与 Field 相同的 key避免生成两次 key值
*/
public static MethodInfo getGetterMethod(String key, Class<?> targetClass, String methodName) {
public static MethodInfo getGetterMethod(Long key, Class<?> targetClass, String methodName) {
Object getterMethod = methodCache.get(key);
if (getterMethod == null) {
getterMethod = doGetMethod(key, targetClass, methodName, NULL_ARG_TYPES);
if (getterMethod != null) {
methodCache.putIfAbsent(key, getterMethod);
methodCache.put(key, getterMethod);
} else {
methodCache.put(key, Boolean.FALSE);
}
@@ -147,7 +145,7 @@ public class MethodKit {
return argTypes;
}
private static MethodInfo doGetMethod(String key, Class<?> targetClass, String methodName, Class<?>[] argTypes) {
private static MethodInfo doGetMethod(Long key, Class<?> targetClass, String methodName, Class<?>[] argTypes) {
if (forbiddenClasses.contains(targetClass)) {
throw new RuntimeException("Forbidden class: " + targetClass.getName());
}
@@ -229,23 +227,8 @@ public class MethodKit {
/**
* 获取方法用于缓存的 key
*/
private static String getMethodKey(Class<?> targetClass, String methodName, Class<?>[] argTypes) {
StringBuilder key = new StringBuilder(96);
key.append(targetClass.getName());
key.append('.').append(methodName);
if (argTypes != null && argTypes.length > 0) {
createArgTypesDigest(argTypes, key);
}
return key.toString();
}
static void createArgTypesDigest(Class<?>[] argTypes, StringBuilder key) {
StringBuilder argTypesDigest = new StringBuilder(64);
for (int i=0; i<argTypes.length; i++) {
Class<?> type = argTypes[i];
argTypesDigest.append(type != null ? type.getName() : "null");
}
key.append(HashKit.md5(argTypesDigest.toString()));
private static Long getMethodKey(Class<?> targetClass, String methodName, Class<?>[] argTypes) {
return MethodKeyBuilder.instance.getMethodKey(targetClass, methodName, argTypes);
}
// 以下代码实现 extension method 功能 --------------------
@@ -290,7 +273,7 @@ public class MethodKit {
throw new RuntimeException("Extension method \"" + methodName + "\" is already exists in class \"" + targetClass.getName() + "\"");
}
} catch (NoSuchMethodException e) { // Method 找不到才能添加该扩展方法
String key = MethodKit.getMethodKey(targetClass, methodName, toBoxedType(targetParaTypes));
Long key = MethodKit.getMethodKey(targetClass, methodName, toBoxedType(targetParaTypes));
if (methodCache.containsKey(key)) {
throw new RuntimeException(buildMethodSignatureForException("The extension method is already exists: " + extensionClass.getName() + ".", methodName, targetParaTypes));
}
@@ -319,7 +302,7 @@ public class MethodKit {
Class<?>[] targetParaTypes = new Class<?>[extensionMethodParaTypes.length - 1];
System.arraycopy(extensionMethodParaTypes, 1, targetParaTypes, 0, targetParaTypes.length);
String key = MethodKit.getMethodKey(targetClass, methodName, toBoxedType(targetParaTypes));
Long key = MethodKit.getMethodKey(targetClass, methodName, toBoxedType(targetParaTypes));
methodCache.remove(key);
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jfinal.template.expr.ast;
import com.jfinal.template.stat.Scope;
/**
* NullExpr
*/
public class NullExpr extends Expr {
public static final NullExpr me = new NullExpr();
private NullExpr() {}
public Object eval(Scope scope) {
return null;
}
}

View File

@@ -49,15 +49,18 @@ public class NullSafe extends Expr {
Ctrl ctrl = scope.getCtrl();
boolean oldNullSafeValue = ctrl.isNullSafe();
Object ret;
try {
ctrl.setNullSafe(true);
ret = left.eval(scope);
Object ret = left.eval(scope);
if (ret != null) {
return ret;
}
} finally {
ctrl.setNullSafe(oldNullSafeValue);
}
return ret == null && right != null ? right.eval(scope) : ret;
// right 表达式处于 null safe 区域之外
return right != null ? right.eval(scope) : null;
}
}
@@ -66,3 +69,4 @@ public class NullSafe extends Expr {

View File

@@ -21,10 +21,11 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.ReflectKit;
/**
@@ -32,27 +33,27 @@ import com.jfinal.kit.ReflectKit;
*/
public class SharedMethodKit {
private static final Set<String> excludedMethodKey = new HashSet<String>();
private static final Set<Long> excludedMethodKey = new HashSet<Long>();
static {
Method[] methods = Object.class.getMethods();
for (Method method : methods) {
String key = getSharedMethodKey(method.getName(), method.getParameterTypes());
Long key = getSharedMethodKey(method.getName(), method.getParameterTypes());
excludedMethodKey.add(key);
}
}
private final List<SharedMethodInfo> sharedMethodList = new ArrayList<SharedMethodInfo>();
private final ConcurrentHashMap<String, SharedMethodInfo> methodCache = new ConcurrentHashMap<String, SharedMethodInfo>();
private final HashMap<Long, SharedMethodInfo> methodCache = new HashMap<Long, SharedMethodInfo>();
public SharedMethodInfo getSharedMethodInfo(String methodName, Object[] argValues) {
Class<?>[] argTypes = MethodKit.getArgTypes(argValues);
String key = getSharedMethodKey(methodName, argTypes);
Long key = getSharedMethodKey(methodName, argTypes);
SharedMethodInfo method = methodCache.get(key);
if (method == null) {
method = doGetSharedMethodInfo(methodName, argTypes);
if (method != null) {
methodCache.putIfAbsent(key, method);
methodCache.put(key, method);
}
// shared method 不支持 null safe不缓存: methodCache.put(key, Boolean.FALSE)
}
@@ -110,7 +111,7 @@ public class SharedMethodKit {
SharedMethodInfo current = it.next();
String methodName = method.getName();
if (current.getName().equals(methodName)) {
String key = getSharedMethodKey(methodName, method.getParameterTypes());
Long key = getSharedMethodKey(methodName, method.getParameterTypes());
if (current.getKey().equals(key)) {
it.remove();
}
@@ -125,7 +126,7 @@ public class SharedMethodKit {
Method[] methods = sharedClass.getMethods();
for (Method method : methods) {
String key = getSharedMethodKey(method.getName(), method.getParameterTypes());
Long key = getSharedMethodKey(method.getName(), method.getParameterTypes());
if (excludedMethodKey.contains(key)) {
continue ;
}
@@ -144,19 +145,27 @@ public class SharedMethodKit {
}
}
private static String getSharedMethodKey(String methodName, Class<?>[] argTypes) {
StringBuilder key = new StringBuilder(64);
key.append(methodName);
if (argTypes != null && argTypes.length > 0) {
MethodKit.createArgTypesDigest(argTypes, key);
private static Long getSharedMethodKey(String methodName, Class<?>[] argTypes) {
long hash = HashKit.FNV_OFFSET_BASIS_64;
hash ^= methodName.hashCode();
hash *= HashKit.FNV_PRIME_64;
if (argTypes != null) {
for (int i=0; i<argTypes.length; i++) {
Class<?> type = argTypes[i];
if (type != null) {
hash ^= type.getName().hashCode();
hash *= HashKit.FNV_PRIME_64;
}
}
}
return key.toString();
}
return hash;
}
static class SharedMethodInfo extends MethodInfo {
final Object target;
private SharedMethodInfo(String key, Class<?> clazz, Method method, Object target) {
private SharedMethodInfo(Long key, Class<?> clazz, Method method, Object target) {
super(key, clazz, method);
this.target = target;
}