com.jfinal.template.expr.ast.FastFieldGetter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of enjoy Show documentation
Show all versions of enjoy Show documentation
Enjoy is a simple, light, rapid, independent, extensible Java Template Engine.
The newest version!
/**
* Copyright (c) 2011-2023, James Zhan 詹波 ([email protected]).
*
* 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 java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.jfinal.kit.StrKit;
import com.jfinal.proxy.ProxyClassLoader;
/**
* 使用 jfinal proxy 机制消除 java.lang.reflect.Method.invoke(...)
* 提升性能,并且同时支持动态类型的 field 表达式取值
*/
public class FastFieldGetter extends FieldGetter {
protected static ProxyGenerator generator = new ProxyGenerator();
protected static ProxyCompiler compiler = new ProxyCompiler();
protected static ProxyClassLoader classLoader = new ProxyClassLoader();
protected static Map, Proxy> cache = new ConcurrentHashMap<>(512, 0.25F);
protected static boolean outputCompileError = false;
protected Proxy proxy;
protected java.lang.reflect.Method getterMethod;
public FastFieldGetter(Proxy proxy, java.lang.reflect.Method getterMethod) {
this.proxy = proxy;
this.getterMethod = getterMethod;
}
/**
* 仅用于配置 Engine.addFieldGetter(0, new FastFieldGetter());
*/
public FastFieldGetter() {
this(null, null);
}
public FieldGetter takeOver(Class> targetClass, String fieldName) {
if (MethodKit.isForbiddenClass(targetClass)) {
throw new RuntimeException("Forbidden class: " + targetClass.getName());
}
String getterName = "get" + StrKit.firstCharToUpperCase(fieldName);
java.lang.reflect.Method[] methodArray = targetClass.getMethods();
for (java.lang.reflect.Method method : methodArray) {
if (method.getName().equals(getterName) && method.getParameterCount() == 0) {
Proxy proxy = cache.computeIfAbsent(targetClass, key -> {
try {
return createProxy(key, fieldName);
} catch (Throwable e) {
return null;
}
});
return proxy != null ? new FastFieldGetter(proxy, method) : null;
}
}
return null;
}
public Object get(Object target, String fieldName) throws Exception {
// return getterMethod.invoke(target, ExprList.NULL_OBJECT_ARRAY);
return proxy.getValue(target, fieldName);
}
protected Proxy createProxy(Class> targetClass, String fieldName) {
ProxyClass proxyClass = new ProxyClass(targetClass);
String sourceCode = generator.generate(proxyClass);
// System.out.println(sourceCode);
proxyClass.setSourceCode(sourceCode);
compiler.compile(proxyClass);
Class> retClass = classLoader.loadProxyClass(proxyClass);
proxyClass.setClazz(retClass);
try {
return (Proxy)retClass.newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
public String toString() {
return getterMethod.toString();
}
// ---------
/**
* 代理接口
*/
public static interface Proxy {
public Object getValue(Object target, String fieldName);
}
// ---------
/**
* 代理类
*/
static class ProxyClass extends com.jfinal.proxy.ProxyClass {
private String name; // 类名
public ProxyClass(Class> target) {
super(target);
name = target.getSimpleName() + "$$EnhancerByJFinal_FieldGetter";
}
public String getName() {
return name;
}
}
// ---------
/**
* 代理生成器
*/
static class ProxyGenerator {
String generate(ProxyClass proxyClass) {
StringBuilder ret = new StringBuilder(1024);
Class> targetClass = proxyClass.getTarget();
String className = proxyClass.getName();
ret.append("package ").append(proxyClass.getPkg()).append(";\n\n");
ret.append("import com.jfinal.template.expr.ast.FastFieldGetter.Proxy;\n\n");
ret.append("public class ").append(className).append(" implements Proxy {\n\n");
ret.append("\tpublic Object getValue(Object target, String fieldName) {\n");
ret.append("\t\tint hash = fieldName.hashCode();\n");
ret.append("\t\tswitch (hash) {\n");
java.lang.reflect.Method[] methodArray = targetClass.getMethods();
for (java.lang.reflect.Method method : methodArray) {
String mn = method.getName();
if (method.getParameterCount() == 0 && mn.startsWith("get") && (!mn.equals("getClass"))) {
String fieldName = StrKit.firstCharToLowerCase(mn.substring(3));
ret.append("\t\tcase ").append(fieldName.hashCode()).append(" :\n");
ret.append("\t\t\treturn ((").append(targetClass.getName()).append(")target).").append(mn).append("();\n");
}
}
ret.append("\t\tdefault :\n");
ret.append("\t\t\tthrow new RuntimeException(\"Can not access the field \\\"\" + target.getClass().getName() + \".\" + fieldName + \"\\\"\");\n");
ret.append("\t\t}\n");
ret.append("\t}\n");
ret.append("}\n");
return ret.toString();
}
}
// ---------
public static void setOutputCompileError(boolean outputCompileError) {
FastFieldGetter.outputCompileError = outputCompileError;
}
/**
* 代理编译器
*/
static class ProxyCompiler extends com.jfinal.proxy.ProxyCompiler {
@Override
protected void outputCompileError(Boolean result, javax.tools.DiagnosticCollector collector) {
if (outputCompileError) {
super.outputCompileError(result, collector);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy