1.简介
OGNL:Object Graph Navigation Language,是一种功能强大的表达式语言,可以存取对象的属性,调用对象的方法等。
著名的Struts2使用它来实现UI和Action之间的数据绑定。
2.两个重要的API
Ognl.getValue(String expression, Object root);
从root对象中获取expression对应的值
Ognl.getValue(String expression, Map<String, Object> context, Object root);
从根对象为root的上下文context中获取expression对应的值
我们可以从下面一段代码中看出context和root的区别
User user = new User();
user.setId("001");
Map<String, String> ognlCtxt = new HashMap<String, String>();
ognlCtxt.put("id", "007");
assertEquals("001", Ognl.getValue("id", ognlCtxt, user));
assertEquals("001", Ognl.getValue("#root.id", ognlCtxt, user));
assertEquals("007", Ognl.getValue("#id", ognlCtxt, user));
assertEquals("007", Ognl.getValue("#context.id", ognlCtxt, user));
当expression以#开头时,将从context中取值
当expression直接以property名字开头时,将从root中取值
并且context中有两个属性#root指向root对象,#context指向本身
具体原因请参考OGNL源代码
3.主要使用
1)常量
--String:用'或"包围
--char:用'包围
--数字:数字格式,或者添加后缀b(B,表示BigDecimals),后缀h(H,表示BigIntegers)
--Boolean:保留字true/false
--null:保留字null
// String
assertEquals("id", Ognl.getValue("\"id\"", null));
assertEquals("id", Ognl.getValue("'id'", null));
// char
assertEquals('i', Ognl.getValue("'i'", null));
// Number
assertEquals(22, Ognl.getValue("22", null));
// boolean
assertTrue((Boolean) Ognl.getValue("true", null));
// null
assertNull(Ognl.getValue("null", null));
2)new新建对象
--java.lang包中的类对象:new
new String()
--其它包中的类对象:new,但要使用类全名
new java.util.ArrayList()
--List:用大括号包围,元素之间用","分隔
{"badminton", "CS"}
--数组:和Java类似
new int[]{1, 2, 3}
new int[5]
--Map:以#开头,用大括号包围,类似于Json格式,Key和Value之间用":"分隔,Entry之间使用"," 分隔
可以同构在#之后用"@"包围的类全名来指定
#{"name" : "007", "age" : 45}
#@java.util.LinkedHashMap@{"name" : "007", "age" : 45}
// object in java.lang.*
assertTrue(Ognl.getValue("new String()", null) instanceof String);
// object not in java.lang.*
assertTrue(Ognl.getValue("new java.util.ArrayList()", null) instanceof List);
/* Collection */
// List
assertTrue(Ognl.getValue("{0, 1, 2}", null) instanceof List);
// Array
assertTrue(Ognl.getValue("new int[]{0, 1, 2}", null) instanceof int[]);
assertTrue(Ognl.getValue("new int[5]", null) instanceof int[]);
// Map
assertTrue(Ognl.getValue("#{'name' : 'man', 'age' : 25}", null) instanceof Map);
assertTrue(Ognl.getValue("#@java.util.HashMap@{'name' : 'man', 'age' : 25}", null) instanceof HashMap);
3)获取对象属性
通过.或者[]访问,以下内容均可视为对象的属性
--JaveBean中的属性
--List或者Array对象的index
--Map对象的key
--[]还支持对一下成对出现方法的index的直接访问(必须成对出现)
public PropertyType getPropertyName(int index);
public void setPropertyName(int index, PropertyType value);
public PropertyType getPropertyName(IndexType index);
public void setPropertyName(IndexType index, PropertyType value);
--除此之外为了OGNL还为Collection对象提供了一些伪属性
Collection : size/isEmpty
List : iterator
Map : keys, values(注:假如Map中有一key的名字为size,则必须通过[]方式获取,.方式将返回Map的大小值)
Set : iterator
Iterator : next/hasNext
Enumeration : next/hasNext/nextElement/hasMoreElements
--.和[]的区别:[]支持表达式
User user = new User();
user.setId("001");
user.setName("man1");
user.setAge(22);
List<String> hobbies = new ArrayList<String>();
hobbies.add("badminton");
hobbies.add("name");
user.setHobbies(hobbies);
Map<String, List<String>> relations = new HashMap<String, List<String>>();
List<String> friends = new ArrayList<String>();
friends.add("002");
relations.put("friends", friends);
user.setRelations(relations);
//property
assertEquals("001", Ognl.getValue("id", user));
/*index*/
// List
assertEquals("badminton", Ognl.getValue("hobbies[0]", user));
// Map
assertEquals("002", Ognl.getValue("relations['friends'][0]", user));
// getHobby(...)/setHobby(...)
assertEquals("badminton", Ognl.getValue("hobby[0]", user));
// getRelation(...)/setRelation(...)
assertEquals("002", Ognl.getValue("relation['friends'][0]", user));
//difference between . and []
assertEquals("man1", Ognl.getValue("[hobbies[1]]", user));
// pseudo property
assertEquals(2, Ognl.getValue("hobbies.size", user));
4)调用方法
直接通过.method(param1, ..., paramN)的方式访问
注意:当方法重载,并且参数符合多个方法要求时,OGNL会选择任意一个进行执行。
所以当方法存在重载,并且参数中有null值时需特别注意,因为null符合任何参数类型要求
assertEquals(2, Ognl.getValue("{0, 1}.size()", null));
5)Static属性和方法
--static属性@class@field
--static方法@class@method(param1, ..., paramN)
// static method
assertEquals("User", Ognl.getValue("@com.siyuan.ognltest.entity.User@getEntityName()", null));
// static field
assertEquals("User", Ognl.getValue("@com.siyuan.ognltest.entity.User@ENTITY_NAME", null));
6)变量
以#开头的属性名均作为context中的变量,并且可通过=对其进行赋值,假如不存在,则新建并保存在context中
#this为一特殊变量,指示前一段表达式的值
assertEquals(120, Ognl.getValue("#count = 100, #count + 20", null));
assertEquals(120, Ognl.getValue("(#count=100).(#this>100 ? 2*#this : 20+#this)", null));
OgnlContext ognlCtxt = new OgnlContext();
assertEquals(120, Ognl.getValue("#count = 100, #count + 20", ognlCtxt, ""));
assertEquals(100, Ognl.getValue("count", ognlCtxt));
7)运算符
除了Java中的运算符,OGNL添加了下列特殊的运算符
--in/not in
返回boolean值,表示元素是否存在list或array中
--projection
collection.{ognlExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后的值
--match
collection.{? ognlBooleanExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后为true的元素
--first match
collection.{^ ognlBooleanExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后第一个为true的元素
--last match
collection.{$ ognlBooleanExpression}
返回一个新的集合,集合的元素为遍历collection,并使用ognlExpression求值后最后一个为true的元素
// in & not in
assertTrue((Boolean) Ognl.getValue("'badminton' in {'badminton', 'CS'}", null));
assertTrue((Boolean) Ognl.getValue("4 not in new int[]{1, 2, 3}", null));
User user = new User();
user.setId("000");
User user1 = new User();
user1.setId("001");
User user2 = new User();
user2.setId("002");
List<User> users = new ArrayList<User>();
users.add(user);
users.add(user1);
users.add(user2);
// projection
List<String> ids = (List<String>) Ognl.getValue("#root.{id}", users);
assertEquals("000", ids.get(0));
assertEquals("001", ids.get(1));
assertEquals("002", ids.get(2));
// selection
List<User> filteredUsers = (List<User>) Ognl.getValue("#root.{? #this.id instanceof String}", users);
assertEquals(user, Ognl.getValue("#root[0]", filteredUsers));
// first match
List<User> filteredUsers1 = (List<User>) Ognl.getValue("#root.{^ #this.id instanceof String}", users);
assertEquals(user, Ognl.getValue("#root[0]", filteredUsers1));
List<User> filteredUsers2 = (List<User>) Ognl.getValue("#root.{$ #this.id instanceof String}", users);
assertEquals(user2, Ognl.getValue("#root[0]", filteredUsers2));
4.参考资料
http://commons.apache.org/ognl/