Ognl的扩展

OGNL提供的扩展方式,见官网:http://commons.apache.org/proper/commons-ognl/developer-guide.html

 

一、PropertyAccessor:提供了对属性赋值和提取属性值的方法。

                             因为不同的类的获取属性值和赋值方式不同,如Map、List、javabean,因此有多个子类,第一个子类对应一种类型。

 

 
Ognl的扩展_第1张图片
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,....)

 


Ognl的扩展_第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.{ ... }表达式语法

 


Ognl的扩展_第3张图片

   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 )


Ognl的扩展_第4张图片

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时将获取的对象转换为需要的类型

 


Ognl的扩展_第5张图片

 

 

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

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

 

  
MemberAccess 定义了对于private 、protected、默认包的Memeber(Constructor、Method、Field)是否可以访问。  它的默认实现 DefaultMemeberAccess 是不能访问 private 、protected、默认包的Memeber。

Ognl的扩展_第6张图片
 
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的扩展_第7张图片
 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);
        }
    }
 

你可能感兴趣的:(Ognl)