package com.example.demo;
import org.apache.ibatis.ognl.MemberAccess;
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlContext;
import org.apache.ibatis.parsing.PropertyParser;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Properties;
public class ParserDemo {
public static void main(String[] args) throws Exception{
Properties variables = new Properties();
variables.setProperty("id", "123123");
String parse = PropertyParser.parse("select * from tb where id = ${id}", variables);
System.out.println(parse);
User user = new User("1", "zhangsan", "23");
// 创建一个上下文,root为user
OgnlContext context = (OgnlContext) Ognl.createDefaultContext(user, new DefaultMemberAccess(true));
// 上下文中添加userCount属性
context.put("userCount", 11);
// 获取userCount,上下文中的属性使用#访问
Object ans = Ognl.getValue(Ognl.parseExpression("#userCount"), context, context.getRoot());
System.out.println("userCount = " + ans);
// 获取root中的age,root中的属性不使用#
ans = Ognl.getValue(Ognl.parseExpression("age"), context, context.getRoot());
System.out.println("age = " + ans);
// 指定值,会调用setName方法
ans = Ognl.getValue(Ognl.parseExpression("name=\"lisi\""), context, context.getRoot());
System.out.println("name = " + user.getName());
}
}
class DefaultMemberAccess implements MemberAccess
{
public boolean allowPrivateAccess = false;
public boolean allowProtectedAccess = false;
public boolean allowPackageProtectedAccess = false;
/*===================================================================
Constructors
===================================================================*/
public DefaultMemberAccess(boolean allowAllAccess)
{
this(allowAllAccess, allowAllAccess, allowAllAccess);
}
public DefaultMemberAccess(boolean allowPrivateAccess, boolean allowProtectedAccess, boolean allowPackageProtectedAccess)
{
super();
this.allowPrivateAccess = allowPrivateAccess;
this.allowProtectedAccess = allowProtectedAccess;
this.allowPackageProtectedAccess = allowPackageProtectedAccess;
}
/*===================================================================
Public methods
===================================================================*/
public boolean getAllowPrivateAccess()
{
return allowPrivateAccess;
}
public void setAllowPrivateAccess(boolean value)
{
allowPrivateAccess = value;
}
public boolean getAllowProtectedAccess()
{
return allowProtectedAccess;
}
public void setAllowProtectedAccess(boolean value)
{
allowProtectedAccess = value;
}
public boolean getAllowPackageProtectedAccess()
{
return allowPackageProtectedAccess;
}
public void setAllowPackageProtectedAccess(boolean value)
{
allowPackageProtectedAccess = value;
}
/*===================================================================
MemberAccess interface
===================================================================*/
public Object setup(Map context, Object target, Member member, String propertyName)
{
Object result = null;
if (isAccessible(context, target, member, propertyName)) {
AccessibleObject accessible = (AccessibleObject)member;
if (!accessible.isAccessible()) {
result = Boolean.FALSE;
accessible.setAccessible(true);
}
}
return result;
}
public void restore(Map context, Object target, Member member, String propertyName, Object state)
{
if (state != null) {
((AccessibleObject)member).setAccessible(((Boolean)state).booleanValue());
}
}
/**
Returns true if the given member is accessible or can be made accessible
by this object.
*/
public boolean isAccessible(Map context, Object target, Member member, String propertyName)
{
int modifiers = member.getModifiers();
boolean result = Modifier.isPublic(modifiers);
if (!result) {
if (Modifier.isPrivate(modifiers)) {
result = getAllowPrivateAccess();
} else {
if (Modifier.isProtected(modifiers)) {
result = getAllowProtectedAccess();
} else {
result = getAllowPackageProtectedAccess();
}
}
}
return result;
}
}
class User {
private String id;
private String name;
private String age;
public User(String id, String name, String age) {
this.id = id;
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ognl 可以写很多自定义表达式,比如像 JSP 里面的对象属性和 Java 静态方法,像 MyBatis 的 XML 里头的 if test 判断。
MyBatis 实现的 ognl 逻辑:
ognl 获取数据的时候,需要一个 ognl 表达式,一个上下文 map,和一个 root 对象
通过 ognl 表达式来判断使用具体哪一个解析器,选择解析器的代码相当复杂,看不懂。
解析器也有很多种,简单的就是获取一个 value 值,有的需要运算,有的需要运行方法
struts 实现的 ognl 逻辑:
值栈是放在上下文中的。每个请求创建一个值栈。
request.setAttribute("struts.valueStack",valuestack)
值栈的实现可以参考 Struts2 里的 OgnlValueStack.java 来实现,
值栈的 set 方法就是往栈顶放一个 map
值栈先从根栈中寻找,然后到 context 中寻找