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