前几天说过想造一个大轮子,今天有点时间就开始写了一点代码。和上次不同的是,原来打算使用的OGNL打算放弃了,决定尽可能的使用JDK带的API和自己写的代码完成,尽可能少的使用第三方的代码,这样更好把握一些。进度可能会非常的慢,因为我会写完整的单元测试代码,并且因为公司加班的原因也没有多少时间投入这个,不过反正是我自己用,也不急。
今天的工作成果就是OGNL的简化版本:BeanAccessExpress。
语法比较简单,就是xxx.yyy[index].zzz[key]
只支持对象属性、数组、List和Map,长度不限。数组和List使用[index]访问,Map的元素使用[key]访问,key必须是字母开头的单词。
代码如下:
package com.jiehoo.core;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.jiehoo.util.MethodUtil;
import com.jiehoo.util.StringUtil;
public class BeanAccessExpress {
private static final String FIELD_EXPRESS = "([a-zA-Z_]\\w*)(?:\\[(?:(\\d+)|([a-zA-Z_]\\w*))\\])?";
protected static final Pattern expressPattern = Pattern.compile(FIELD_EXPRESS
+ "(\\." + FIELD_EXPRESS + ")*");
private static final Pattern fieldPattern = Pattern.compile(FIELD_EXPRESS);
public static Object get(Object bean, String express) throws Exception {
Object result = bean;
List fields = parseFields(express);
for (int i = 0; i < fields.size(); i++) {
BeanAccessField field = (BeanAccessField) fields.get(i);
int type = field.getType();
switch (type) {
case BeanAccessField.NORMAL:
result = MethodUtil.getGetter(result, field.getField()).invoke(result,
null);
break;
case BeanAccessField.MAP:
result = MethodUtil.getGetter(result, field.getField()).invoke(result,
null);
result = ((Map) result).get(field.getKey());
break;
case BeanAccessField.LIST:
result = MethodUtil.getGetter(result, field.getField()).invoke(result,
null);
if (result instanceof List) {
result = ((List) result).get(field.getIndex());
} else {
result = ((Object[]) result)[field.getIndex()];
}
break;
}
}
return result;
}
public static Object getSilent(Object bean, String express) {
if (bean == null) {
return null;
}
Object result = bean;
try {
List fields = parseFields(express);
for (int i = 0; i < fields.size(); i++) {
BeanAccessField field = (BeanAccessField) fields.get(i);
int type = field.getType();
switch (type) {
case BeanAccessField.NORMAL:
result = MethodUtil.getGetter(result, field.getField()).invoke(
result, null);
break;
case BeanAccessField.MAP:
result = MethodUtil.getGetter(result, field.getField()).invoke(
result, null);
result = ((Map) result).get(field.getKey());
break;
case BeanAccessField.LIST:
result = MethodUtil.getGetter(result, field.getField()).invoke(
result, null);
if (result instanceof List) {
result = ((List) result).get(field.getIndex());
} else {
result = ((Object[]) result)[field.getIndex()];
}
break;
}
}
} catch (Exception e) {
return null;
}
return result;
}
private static List parseFields(String express) {
List result = new ArrayList();
if (!expressPattern.matcher(express).matches()) {
throw new ExpressError();
}
Matcher matcher = fieldPattern.matcher(express);
int start = 0;
while (matcher.find(start)) {
String field = matcher.group(1);
String index = matcher.group(2);
String key = matcher.group(3);
start = matcher.end();
if (index == null && key == null) {
result.add(new BeanAccessField(StringUtil.uppercaseFirst(field)));
} else if (index != null) {
result.add(new BeanAccessField(StringUtil.uppercaseFirst(field),
Integer.parseInt(index)));
} else if (key != null) {
result.add(new BeanAccessField(StringUtil.uppercaseFirst(field), key));
}
}
return result;
}
}
package com.jiehoo.core;
public class BeanAccessField {
public static final int NORMAL = 0;
public static final int LIST = 1;
public static final int MAP = 2;
private String field;
private int type;
private int index;
private String key;
public BeanAccessField(String field) {
this.field = field;
type = NORMAL;
}
public BeanAccessField(String field, int index) {
this.field = field;
this.index = index;
type = LIST;
}
public BeanAccessField(String field, String key) {
this.field = field;
this.key = key;
type = MAP;
}
public String getField() {
return field;
}
public int getIndex() {
return index;
}
public String getKey() {
return key;
}
public int getType() {
return type;
}
}
测试用例:
package com.jiehoo.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
public class TestBeanAccessExpress extends TestCase {
class TestBean {
String string;
Object[] arrays;
List list;
Map map;
public TestBean() {
string = "testbean";
arrays = new Object[3];
arrays[0] = "array0";
arrays[1] = "array1";
arrays[2] = new Object();
list = new ArrayList();
list.add("list0");
list.add("list1");
list.add(new Object());
map = new HashMap();
map.put("key0", "value0");
map.put("key1", "value1");
map.put("key2", new Object());
}
public Object[] getArrays() {
return arrays;
}
public List getList() {
return list;
}
public Map getMap() {
return map;
}
public String getString() {
return string;
}
}
public void testErrorExpress() throws Exception {
boolean exception = false;
try {
BeanAccessExpress.get(new TestBean(), "123");
} catch (ExpressError e) {
exception = true;
}
if (!exception) {
fail("Should throw ExpressError.");
}
try {
BeanAccessExpress.get(new TestBean(), "xx123.xedd.");
} catch (ExpressError e) {
exception = true;
}
if (!exception) {
fail("Should throw ExpressError.");
}
try {
BeanAccessExpress.get(new TestBean(), "xx123.xedd.1");
} catch (ExpressError e) {
exception = true;
}
if (!exception) {
fail("Should throw ExpressError.");
}
}
public void testSimleExpress() throws Exception {
assertEquals("testbean", BeanAccessExpress.get(new TestBean(), "string"));
assertEquals(String.class, BeanAccessExpress.get(new TestBean(),
"string.class"));
}
public void testArrayExpress() throws Exception {
assertEquals("array0", BeanAccessExpress.get(new TestBean(), "arrays[0]"));
assertEquals("array1", BeanAccessExpress.get(new TestBean(), "arrays[1]"));
assertEquals(Object.class, BeanAccessExpress.get(new TestBean(),
"arrays[2].class"));
}
public void testListExpress() throws Exception {
assertEquals("list0", BeanAccessExpress.get(new TestBean(), "list[0]"));
assertEquals("list1", BeanAccessExpress.get(new TestBean(), "list[1]"));
assertEquals(Object.class, BeanAccessExpress.get(new TestBean(),
"list[2].class"));
}
public void testMapExpress() throws Exception {
assertEquals("value0", BeanAccessExpress.get(new TestBean(), "map[key0]"));
assertEquals("value1", BeanAccessExpress.get(new TestBean(), "map[key1]"));
assertEquals(Object.class, BeanAccessExpress.get(new TestBean(),
"map[key2].class"));
}
}
有时间会把代码上传到服务器。
0 Comments
4 Pingbacks