一个简单的el表达式实现
实现还在完善种,现在只能处理引用类型的的属性字段和函数,不支持容器类数组!不支持子类型
线来个测试用例
package com.isnowfox.oel;
import java.util.Date;
import com.isnowfox.core.junit.BaseTest;
import com.isnowfox.util.RandomUtils;
/**
* el 测试用例
* @author zuoge85
*
*/
public class OelTest extends BaseTest{
public void testBasObject() throws UnknownKeyException{
OelEngine oel = OelEngine.getInstance();
TestObject obj = new TestObject();
Date date = new Date();
int number = RandomUtils.randInt();
String string = "测试用例";
obj.dateField =date;
obj.setDateProperty(date);
obj.intField =number;
obj.setIntProperty(number);
obj.stringField = string;
obj.setStringProperty(string);
obj.dateMethod(date);
assertEquals(date, oel.el(obj, "dateProperty"));
assertEquals(date.getTime(), oel.el(obj, "dateProperty.time"));
assertEquals(date, oel.el(obj, "dateField"));
assertEquals(date.getTime(), oel.el(obj, "dateField.time"));
assertEquals(date, oel.el(obj, "dateMethod()"));
assertEquals(date.getTime(), oel.el(obj, "dateMethod().time"));
assertEquals(number, oel.el(obj, "intField"));
assertEquals(number, oel.el(obj, "intProperty"));
assertEquals(string, oel.el(obj, "stringField"));
assertEquals(string, oel.el(obj, "stringProperty"));
}
}
package com.isnowfox.oel;
import java.util.Date;
public class TestObject {
public int intField;
public String stringField;
public Date dateField;
private int intProperty;
private String StringProperty;
private Date dateProperty;
private Date dateMethod;
public int getIntProperty() {
return intProperty;
}
public void setIntProperty(int intProperty) {
this.intProperty = intProperty;
}
public String getStringProperty() {
return StringProperty;
}
public void setStringProperty(String stringProperty) {
StringProperty = stringProperty;
}
public Date getDateProperty() {
return dateProperty;
}
public void setDateProperty(Date dateProperty) {
this.dateProperty = dateProperty;
}
public Date dateMethod(){
return dateMethod;
}
public void dateMethod(Date dateMethod){
this.dateMethod = dateMethod;
}
@Override
public String toString() {
return "TestObject [intField=" + intField + ", StringField="
+ stringField + ", dataField=" + dateField + ", intProperty="
+ intProperty + ", StringProperty=" + StringProperty
+ ", dataProperty=" + dateProperty + "]";
}
}
下面是实现
package com.isnowfox.oel;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
import com.isnowfox.oel.KeyInfo.Type;
/**
* oel引擎
* @author zuoge85
*
*/
public class OelEngine {
private static final boolean DEBUG = true;
private static final String PACKAGE_NAME = OelEngine.class.getPackage().getName();
private static Map<Class<?>, Class<?>> primitivesWrapMap = new HashMap<Class<?>, Class<?>>(16);
static{
primitivesWrapMap.put(boolean.class, Boolean.class);
primitivesWrapMap.put(byte.class, Byte.class);
primitivesWrapMap.put(char.class, Character.class);
primitivesWrapMap.put(double.class, Double.class);
primitivesWrapMap.put(float.class, Float.class);
primitivesWrapMap.put(int.class, Integer.class);
primitivesWrapMap.put(long.class, Long.class);
primitivesWrapMap.put(short.class, Short.class);
primitivesWrapMap.put( void.class, Void.class);
}
public static final OelEngine getInstance(){
return Inner.instance;
}
private Map<String,OelProxy> cacheMap = new HashMap<>();
private AtomicInteger itemSeed = new AtomicInteger();
public Object el(Object obj,String el) throws UnknownKeyException{
if(obj == null){
throw new NullPointerException("null");
}
try {
Class<?> cls = obj.getClass();
String cacheKey = cls.getName() + el;
OelProxy p =cacheMap.get(cacheKey);
if(p==null){
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(PACKAGE_NAME + ".MyOelProxy" + itemSeed.incrementAndGet());
cc.addInterface(pool.get(PACKAGE_NAME +".OelProxy"));
CtMethod method = CtNewMethod.make("public Object el(Object obj);", cc);
method.setBody(makeMethod(cls, obj, el));
cc.addMethod(method);
if(DEBUG){
cc.debugWriteFile("debug");
}
p = (OelProxy) cc.toClass().newInstance();
cacheMap.put(cacheKey, p);
}
return p.el(obj);
} catch (NotFoundException|CannotCompileException|InstantiationException|IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private String makeMethod(Class<?> cls, Object obj, String el) throws UnknownKeyException{
int varSeed = 0;
StringBuilder sb = new StringBuilder("{\n");
String[] keys = el.split("\\.");
sb.append(cls.getCanonicalName() + " var_" + (++varSeed) + " = (" +cls.getCanonicalName() + ")$1;\n" );
for(String key:keys){
KeyInfo info =analyse(cls,key);
int nextVar = varSeed++ ;
switch (info.getType()) {
case FIELD:
sb.append(info.getCls().getCanonicalName() +" var_" + varSeed + " = var_"+ nextVar +"." + key + ";\n");
break;
case PROPERTY:
sb.append(info.getCls().getCanonicalName() +" var_" + varSeed + " = var_"+ nextVar +"." + info.getMethodName() + "();\n");
break;
case METHOD:
sb.append(info.getCls().getCanonicalName() +" var_" + varSeed + " = var_"+ nextVar +"." + key + ";\n");
break;
default:
break;
}
cls = info.getCls();
}
if(cls.isPrimitive()){
cls = wrap(cls);
sb.append("return "+cls.getCanonicalName()+".valueOf(var_" + varSeed + ");}");
}else{
sb.append("return var_" + varSeed + ";}");
}
return sb.toString();
}
private KeyInfo analyse(Class<?> cls,String key) throws UnknownKeyException{
try {
if(key.endsWith("()")){
try {
Method method = cls.getMethod(key.substring(0, key.length()-2));
return new KeyInfo(Type.METHOD, method.getReturnType());
} catch (Exception e2) {
}
}
PropertyDescriptor prop = new PropertyDescriptor(key, cls);
return new KeyInfo(Type.PROPERTY, prop.getPropertyType(), prop.getReadMethod().getName());
} catch (IntrospectionException e) {
//属性没找到那么可能是field
Field field;
try {
field = cls.getField(key);
return new KeyInfo(Type.FIELD, field.getType());
} catch (Exception e1) {
}
}
throw new UnknownKeyException("未知的 key:"+key +",cls:"+ cls);
}
private Class<?> wrap(Class<?> cls){
return primitivesWrapMap.get(cls);
}
public Object part(Object Obj,String name){
return null;
}
private static class Inner{
private static final OelEngine instance = new OelEngine();
}
}