OGNL提供的扩展方式,见官网:http://commons.apache.org/proper/commons-ognl/developer-guide.html
一、PropertyAccessor:提供了对属性赋值和提取属性值的方法。
因为不同的类的获取属性值和赋值方式不同,如Map、List、javabean,因此有多个子类,第一个子类对应一种类型。
PropertyAccessor 类何时加载的:
OgnlRunTime类中静态代码块,在类加载时调用
static {
PropertyAccessor p = new ArrayPropertyAccessor();
setPropertyAccessor(Object.class, new ObjectPropertyAccessor());
setPropertyAccessor(byte[].class, p);
setPropertyAccessor(short[].class, p);
setPropertyAccessor(char[].class, p);
setPropertyAccessor(int[].class, p);
setPropertyAccessor(long[].class, p);
setPropertyAccessor(float[].class, p);
setPropertyAccessor(double[].class, p);
setPropertyAccessor(Object[].class, p);
setPropertyAccessor(List.class, new ListPropertyAccessor());
setPropertyAccessor(Map.class, new MapPropertyAccessor());
setPropertyAccessor(Set.class, new SetPropertyAccessor());
setPropertyAccessor(Iterator.class, new IteratorPropertyAccessor());
setPropertyAccessor(Enumeration.class, new EnumerationPropertyAccessor());
}
自定义PropertyAccessor 如何让Ognl加载上? 调用OgnlRunTime类中的静态方法:
public static void setPropertyAccessor(Class cls, PropertyAccessor accessor) {
synchronized (_propertyAccessors) {
_propertyAccessors.put(cls, accessor);
}
}
二、 MethodAccessor
用于调用对象的方法,用于支持ognl表达式方法的调用:对象.方法名(参数1,参数2,....)
MethodAccessor 类何时加载的:
OgnlRunTime类中静态代码块,在类加载时调用:
static {
MethodAccessor ma = new ObjectMethodAccessor();
setMethodAccessor(Object.class, ma);
setMethodAccessor(byte[].class, ma);
setMethodAccessor(short[].class, ma);
setMethodAccessor(char[].class, ma);
setMethodAccessor(int[].class, ma);
setMethodAccessor(long[].class, ma);
setMethodAccessor(float[].class, ma);
setMethodAccessor(double[].class, ma);
setMethodAccessor(Object[].class, ma);
}
自定义MethodAccessor 如何让Ognl加载上?
调用OgnlRunTime类中的静态方法:(对Ognl的扩展或覆盖某个Class对应的默认的MethodAccessor)
public static void setMethodAccessor(Class cls, MethodAccessor accessor) {
synchronized (_methodAccessors) {
_methodAccessors.put(cls, accessor);
}
}
三、 ElementsAccessor
对象的遍历,用于支持object.{ ... }表达式语法
ElementsAccessor 是何时加载的?
OgnlRuntime的静态代码块,在类加载时调用:
static{
ElementsAccessor e = new ArrayElementsAccessor();
setElementsAccessor(Object.class, new ObjectElementsAccessor());
setElementsAccessor(byte[].class, e);
setElementsAccessor(short[].class, e);
setElementsAccessor(char[].class, e);
setElementsAccessor(int[].class, e);
setElementsAccessor(long[].class, e);
setElementsAccessor(float[].class, e);
setElementsAccessor(double[].class, e);
setElementsAccessor(Object[].class, e);
setElementsAccessor(Collection.class, new CollectionElementsAccessor());
setElementsAccessor(Map.class, new MapElementsAccessor());
setElementsAccessor(Iterator.class, new IteratorElementsAccessor());
setElementsAccessor(Enumeration.class, new EnumerationElementsAccessor());
setElementsAccessor(Number.class, new NumberElementsAccessor());
}
自定义TypeConverter 如何让Ognl加载上?
调用OgnlRuntime的静态方法:(对Ognl的扩展或覆盖某个Class对应的默认的ElementsAccessor实现)
public static void setElementsAccessor(Class cls, ElementsAccessor accessor) {
synchronized (_elementsAccessors) {
_elementsAccessors.put(cls, accessor);
}
}
四、 ClassResolver
用于类的加载,用于支持静态属性或方法的调用,(@class@method(args)、@class@field )
ClassResolver 类何时加载的:
OgnlContext 类中定义默认的DefaultClassResolver:
public static final ClassResolver DEFAULT_CLASS_RESOLVER = new DefaultClassResolver();
private ClassResolver _classResolver = DEFAULT_CLASS_RESOLVER;
自定义ClassResolver 如何让Ognl加载上?
调用 OgnlContext 类中的方法(替换了Ognl的默认实现DefaultClassResolver):
public void setClassResolver(ClassResolver value) {
if (value == null) {
throw new IllegalArgumentException("cannot set ClassResolver to null");
}
_classResolver = value;
}
五、 TypeConverter
类型转换,setValue时将值转换为实际的类型,或getValue时将获取的对象转换为需要的类型
TypeConverter 类何时加载的:
OgnlContext类中默认的TypeConverter:
public static final TypeConverter DEFAULT_TYPE_CONVERTER = new DefaultTypeConverter();
private TypeConverter _typeConverter = DEFAULT_TYPE_CONVERTER;
自定义TypeConverter 如何让Ognl加载上?
调用 OgnlContext类中的方法:(替换了Ognl的默认实现DefaultTypeConverter):
public void setTypeConverter(TypeConverter value) {
if (value == null) {
throw new IllegalArgumentException("cannot set TypeConverter to null");
}
_typeConverter = value;
}
六、MemberAccess
java中的java.lang.reflect.Member 是Constructor、Method、Filed的接口,java.lang.reflect.AccessibleObject 是 Constructor、Method、Filed的父类。
AccessibleObject提供setAccessable(true)方法,实现了对非public的Constructor、Method、Filed的访问能力。
API:
AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查
boolean | isAccessible() 获取此对象的 accessible 标志的值。 |
void |
|
MemberAccess 定义了对于private 、protected、默认包的Memeber(Constructor、Method、Field)是否可以访问。 它的默认实现 DefaultMemeberAccess 是不能访问private 、protected、默认包的Memeber。
ognl中对于MemberAccess的调用:
public static Object getFieldValue(OgnlContext context, Object target, String propertyName, boolean checkAccessAndExistence) throws NoSuchFieldException {
Object result = null;
Field f = getField((target == null) ? null : target.getClass(), propertyName);
if (checkAccessAndExistence) {
if ((f == null) || !context.getMemberAccess().isAccessible(context, target, f, propertyName)) {//不可访问就返回NotFound
result = NotFound;
}
}
if (result == null) {
if (f == null) {
throw new NoSuchFieldException(propertyName);
} else {
try {
Object state = null;
if (!Modifier.isStatic(f.getModifiers())) {
state = context.getMemberAccess().setup(context, target, f, propertyName);//设置可以访问,并返回状态
result = f.get(target);//进行访问
context.getMemberAccess().restore(context, target, f, propertyName, state);//恢复访问状态
} else
throw new NoSuchFieldException(propertyName);
} catch (IllegalAccessException ex) {
throw new NoSuchFieldException(propertyName);
}
}
}
return result;
}
MemberAccess 类何时加载的:
OgnlContext类中默认的MemberAccess :
public static final MemberAccess DEFAULT_MEMBER_ACCESS = new DefaultMemberAccess(false);
private MemberAccess _memberAccess = DEFAULT_MEMBER_ACCESS;
自定义MemberAccess如何让Ognl加载上?
调用 OgnlContext类中的方法:(替换了Ognl的默认实现DefaultMemberAccess):
public void setMemberAccess(MemberAccess value) {
if (value == null) {
throw new IllegalArgumentException("cannot set MemberAccess to null");
}
_memberAccess = value;
}
七、NullHandler
Ognl表达式链中,获取中间的对象为null,遭成之后的属性或方法调用不了,如user.name,如获取的user为null,那么就无法获取或设置它的name属性,
NullHandler 提供了一种方式,对于表达式链中间的对象为null时,允许生成一个对象。
常见的情况是mvc框架中从页面传来的数据user.name值,而当前对象中user为null,这时需要创建一个user对象,才能赋值。
Ognl的默认实现是ObjectNullHandler,它不做任何处理只是返回null,即不创建对象。
Ognl对NullHandler的调用:
protected Object getValueBody(OgnlContext context, Object source) throws OgnlException {
Object property = getProperty(context, source);
Object result = OgnlRuntime.getProperty(context, source, property);
if (result == null) {
result = OgnlRuntime.getNullHandler(OgnlRuntime.getTargetClass(source)).nullPropertyValue(context, source, property);
}
return result;
}
NullHandler是何时被加载的:
在OgnlRuntime类中静态代码块:(在OgnlRuntime类加载时调用)
NullHandler nh = new ObjectNullHandler();
setNullHandler(Object.class, nh);
setNullHandler(byte[].class, nh);
setNullHandler(short[].class, nh);
setNullHandler(char[].class, nh);
setNullHandler(int[].class, nh);
setNullHandler(long[].class, nh);
setNullHandler(float[].class, nh);
setNullHandler(double[].class, nh);
setNullHandler(Object[].class, nh);
自定义NullHandler如何让Ognl加载:
public static void setNullHandler(Class cls, NullHandler handler) {
synchronized (_nullHandlers) {
_nullHandlers.put(cls, handler);
}
}
<!-- https://mvnrepository.com/artifact/ognl/ognl -->
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.3.2</version>
</dependency>
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import ognl.Ognl;
import ognl.OgnlException;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
public class OgnlTest {
@Test
public void getProperty() throws OgnlException {
Student student = new Student();
student.setId(1);
student.setAge(20);
student.setGrade(4);
student.setName("韩梅梅");
student.setSchool("县高中");
Object tree = Ognl.parseExpression("name");
Object value = Ognl.getValue(tree, student);
System.out.println(value);
}
@Test
public void getJsonProperty() throws OgnlException {
String str = "{\n" +
"\t\"age\":20,\n" +
"\t\"grade\":4,\n" +
"\t\"id\":1,\n" +
"\t\"name\":\"韩梅梅\",\n" +
"\t\"school\":\"县高中\"\n" +
"}";
JSONObject jsonObject = JSONObject.parseObject(str);
Object tree = Ognl.parseExpression("name");
Object value = Ognl.getValue(tree, jsonObject);
System.out.println(value);
}
@Test
public void getMapProperty() throws OgnlException {
String str = "{\n" +
"\t\"age\":20,\n" +
"\t\"grade\":4,\n" +
"\t\"id\":1,\n" +
"\t\"name\":\"韩梅梅\",\n" +
"\t\"school\":\"县高中\"\n" +
"}";
Map<String , Object> map = JSONObject.parseObject(str , new TypeReference<Map<String , Object>>(){});
Object tree = Ognl.parseExpression("name");
Object value = Ognl.getValue(tree, map);
System.out.println(value);
}
/**
* expression :Strig对象,
* 表达式 指明对root或context中的哪个属性或方法操作 (set or get or call)
* Object root :任意一个java对象
* 从中取值或赋值,不以#开头的表达式,是对root取值或赋值
* context :一个Map对象,
* 1.可以从中取值 以#开头的表达式是从context取值
* 2. 含Ognl的上下文对象(见addDefaultContext方法)
* tree:一个Node对象
* 是Ognl.parseExpression(expression) 而生成的对象,即对表达式解析之后的对象
* resultType:一个Class对象
* 期望的返回值类型,需要对获取的结果类型转换,
* @throws OgnlException
*/
@Test
public void setProperty() throws OgnlException {
Student student = new Student();
student.setId(1);
student.setAge(20);
student.setGrade(4);
student.setName("韩梅梅");
student.setSchool("县高中");
Object tree = Ognl.parseExpression("name");
//Ognl.setValue(tree , student , "李雷");
Ognl.setValue("name" , student , "李雷");
Object value1 = Ognl.getValue("name.length",student);
System.out.println(value1);
Object value = Ognl.getValue(tree, student);
System.out.println(value);
}
@Test
public void context() throws OgnlException {
Student student = new Student();
student.setId(1);
student.setAge(20);
student.setGrade(4);
student.setName("韩梅梅");
student.setSchool("县高中");
Map map = new HashMap<>();
Ognl.setValue("name" , map ,student , "李雷");
Object root = Ognl.getRoot(map);
System.out.println(root);
Object value = Ognl.getValue("name", student);
System.out.println(value);
}
@Test
public void context1() throws OgnlException {
Student student = new Student();
student.setId(1);
student.setAge(20);
student.setGrade(4);
student.setName("韩梅梅");
student.setSchool("县高中");
Map map1 = new HashMap<>();
map1.put("name" , "zhangsan");
map1.put("age" , 20);
//Ognl.setRoot(map1 , student);
Ognl.setValue("name" , map1 ,student , "李雷");
Ognl.setValue("#age" , map1 ,student , 100);
Object root1 = Ognl.getRoot(map1);
System.out.println(root1);
Object age = Ognl.getValue("age", map1 , student);
System.out.println(age);
Object age1 = Ognl.getValue("#age" , map1 , student);
System.out.println(age1);
Object value = Ognl.getValue("name", map1 , student);
System.out.println(value);
Object value1 = Ognl.getValue("#name" , map1 , student);
System.out.println(value1);
Object value2 = Ognl.getValue("#root.name" , map1 , student);
System.out.println(value2);
Object value3 = Ognl.getValue("root.name" , map1 , student);
//ognl.NoSuchPropertyException: com.fll.test.ognl.Student.root
//意思是 Student 中没有 root 这个属性
System.out.println(value3);
}
@Test
public void typeConverter() throws OgnlException {
Company company = new Company();
company.setAsset(120000L);
Double asset = (Double) Ognl.getValue("asset", company, Double.TYPE);
System.out.println(asset);
Ognl.setValue("asset" , company , 12.11);
Object asset1 = Ognl.getValue("asset", company);
System.out.println(asset1);
}
@Test
public void mapObject() throws OgnlException {
Company company = new Company();
company.setAsset(120000L);
company.setId(1);
company.setCompanyName("china");
Map map = new HashMap();
map.put("money" , 10000);
map.put("address" , "北京");
map.put("company" , company);
company.setMap(map);
Object value = Ognl.getValue("map.address", map, company);
System.out.println(value);
//Object value1 = Ognl.getValue("#map.address", map, company);
//ognl.OgnlException: source is null for getProperty(null, "address")
//System.out.println(value1);
Object value2 = Ognl.getValue("#company.companyName", map, company);
System.out.println(value2);
Ognl.setValue("#company.companyName", map, company , "shanxi");
Object value3 = Ognl.getValue("#company.companyName", map, company);
System.out.println(value3);
}
@Test
public void callMethod() throws OgnlException {
ClassModel classModel = new ClassModel();
classModel.setClassName("编成设计班");
classModel.setGrade(1);
classModel.setTeacherName("变成老师");
for(int i = 0 ; i < 10 ;i++){
Student student = new Student();
student.setSchool("编程学校");
student.setGrade(classModel.getGrade());
student.setName("student" + i);
student.setAge(i);
student.setId(i);
classModel.getStudents().add(student);
}
Ognl.getValue("printStudent()", classModel);
Ognl.getValue("addStudent(students[2])", classModel);
Ognl.getValue("printStudent()", classModel);
Object value1 = Ognl.getValue("hello('中国')", classModel);
System.out.println(value1);
Student student = new Student();
student.setSchool("编程学校");
student.setGrade(classModel.getGrade());
student.setName("student10");
student.setAge(10);
student.setId(10);
Map context = new HashMap();
context.put("student" , student);
Ognl.getValue("addStudent(#student)", context , classModel);
Ognl.getValue("printStudent()", classModel);
}
@Test
public void list() throws OgnlException {
ClassModel classModel = new ClassModel();
classModel.setClassName("编成设计班");
classModel.setGrade(1);
classModel.setTeacherName("变成老师");
for(int i = 0 ; i < 10 ;i++){
Student student = new Student();
student.setSchool("编程学校");
student.setGrade(classModel.getGrade());
student.setName("student" + i);
student.setAge(i);
student.setId(i);
classModel.getStudents().add(student);
}
Ognl.getValue("printStudent()", classModel);
Object size = Ognl.getValue("students.size()", classModel);
System.out.println("size:" + size);
Ognl.getValue("students.remove(0)" , classModel);
System.out.println();
size = Ognl.getValue("students.size()", classModel);
System.out.println("size:" + size);
Ognl.getValue("printStudent()", classModel);
Map context = new HashMap();
context.put("contextStudents" , classModel.getStudents());
Ognl.getValue("#contextStudents.remove(0)" , context , classModel);
System.out.println();
Ognl.getValue("printStudent()", classModel);
}
@Test
public void collection() throws OgnlException {
List list = new ArrayList();
Set set = new HashSet();
Student[] array = new Student[10];
Map root = new HashMap();
root.put("list" , list);
root.put("set" , set);
root.put("array" , array);
for(int i = 0 ; i < 10 ;i++){
Student student = new Student();
student.setSchool("编程学校");
student.setGrade(i);
student.setName("student" + i);
student.setAge(i);
student.setId(i);
list.add(student);
set.add(student);
array[i] = student;
}
//提取List中所有元素的某个公用属性值,而生成新的集合ArrayList
Object listName = Ognl.getValue("list.{name}", root);
System.out.println("collectClass:" + listName.getClass() +" listName:" + listName);
//提取SET中所有元素的某个公用属性值,而生成新的集合ArrayList
Object setAge = Ognl.getValue("set.{age}", root);
System.out.println("collectClass:" + setAge.getClass() +" setName:" + setAge);
//提取数组中所有元素的某个公用属性值,而生成新的集合ArrayList
Object arrayName = Ognl.getValue("array.{name}", root);
System.out.println("collectClass:" + arrayName.getClass() +" arrayName:" + arrayName);
//提取List中所有元素的age>20的所有元素,而生成新的集合ArrayList,再调用ArrayList.size
int size = (Integer)Ognl.getValue("list.{? #this.age>5}.size()" , root);
System.out.println("年龄大于5人数:" + size);
//提取List中所有元素的age>20的第一个元素生成ArrayList,再获取它中唯一元素的name属性
String name = (String)Ognl.getValue("list.{^ #this.age>5}[0].name" , root);
System.out.println("年龄大于5第一个人的名字:" + name);
//提取List中所有元素的age>20的最后一个元素生成ArrayList,再获取它中唯一元素的name属性
name = (String)Ognl.getValue("list.{$ #this.age>5}[0].name" , root);
System.out.println("年龄大于5最后一个人的名字:" + name);
}
@Test
public void testLogic() throws OgnlException {
Map root = new HashMap();
root.put("asset",1232);
root.put("companyName" , "k company");
root.put("employeeNum" , 200);
Object obj = Ognl.getValue("(asset % 10 )== 2", root);
Assert.assertEquals(true, obj);
obj = Ognl.getValue("(asset % 10 )== 2", root);
Assert.assertEquals(true, obj);
obj = Ognl.getValue("asset > 100? 1:2", root);
Assert.assertEquals(1, obj);
obj = Ognl.getValue("asset = 1000", root);
Assert.assertEquals(1000, obj);
obj = Ognl.getValue("asset == 1000? 'success':'fail'", root);
Assert.assertEquals("success", obj);
obj = Ognl.getValue("asset > 1000 && employeeNum>100", root);
Assert.assertEquals(false, obj);
obj = Ognl.getValue("asset >= 1000 || employeeNum>=100", root);
Assert.assertEquals(true, obj);
obj = Ognl.getValue("8 & 0xE ", root);
Assert.assertEquals(8, obj);
obj = Ognl.getValue("8 | 0xE ", root);
Assert.assertEquals(14, obj);
obj = Ognl.getValue("8 ^ 0xE ", root);
Assert.assertEquals(6, obj);
obj = Ognl.getValue("~8", root);
Assert.assertEquals(-9, obj);
obj = Ognl.getValue("companyName=null", root);
Assert.assertEquals(null, obj);
obj = Ognl.getValue("companyName", root);
Assert.assertEquals(null, obj);
obj = Ognl.getValue("companyName != null", root);
Assert.assertEquals(false, obj);
obj = Ognl.getValue("companyName == null", root);
Assert.assertEquals(true, obj);
obj = Ognl.getValue("!(companyName == null)", root);
Assert.assertEquals(false, obj);
int m = 0xf;
}
}