Ognl的扩展

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 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查

 booleanisAccessible()
          获取此对象的 accessible 标志的值。
 void

setAccessible(boolean flag)
          将此对象的 accessible 标志设置为指示的布尔值。

  

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;


    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值