您可以使用 OGNL 访问私有变量吗?

Can you access private variables using OGNL?

是否有使用 OGNL 访问未作为 bean 属性 公开的私有变量(即没有 get/set 方法对)?我想将 OGNL 用作单元测试中使用的更快、更清晰的反射方法。

这是我的代码:

@Test
public void shouldSetup() throws OgnlException{
    class A{
        private Object b = "foo";
        private Object c = "bar";
        public Object getB(){ return b; }
    }
    A a = new A();

    System.out.println( "This'll work..." );
    Ognl.getValue( "b", a );

    System.out.println( "...and this'll fail..." );
    Ognl.getValue( "c", a );

    System.out.println( "...and we'll never get here." );
}

我能做的最好的事情就是直接使用反射:

static Object getValue( final String ognlPath, final Object o ){
    final StringTokenizer st = new StringTokenizer( ognlPath, "." );

    Object currentO = o;
    String nextFieldName = null;
    try{
        while( st.hasMoreTokens() ){
            nextFieldName = st.nextToken();

            if( currentO == null ){
                throw new IllegalStateException( "Cannot find field '" + nextFieldName + "' on null object." );
            }

            Field f = currentO.getClass().getDeclaredField( nextFieldName );
            f.setAccessible( true );
            currentO = f.get( currentO );
        }

        return currentO;

    }catch( NoSuchFieldException e ){
        throw new RuntimeException( "Could not find field '" + nextFieldName + "' on " + currentO.getClass().getCanonicalName(), e );

    }catch( IllegalAccessException e ){
        throw new RuntimeException( "Failed to get from path '" + ognlPath + "' on object: " + o, e );
    }
}

其实你可以。您需要在 OgnlContext 中设置 MemberAccess 以允许访问非 public 字段并使用 getValue(ExpressionAccessor expression, OgnlContext context, Object root) 方法检索值。

@Test
public void shouldSetup() throws OgnlException {
    class A {
        private Object b = "foo";
        private Object c = "bar";
        public Object getB() { return b; }
    }
    A a = new A();

    // set DefaultMemberAccess with allowed access into the context
    OgnlContext context = new OgnlContext();
    context.setMemberAccess(new DefaultMemberAccess(true));

    System.out.println( "This'll work..." );
    // use context in getValue method
    Ognl.getValue( "b", context, a );

    System.out.println( "...and this'll work..." );
    // use context in getValue method
    Ognl.getValue( "c", context, a );

    System.out.println( "...and we'll get here." );
}