blob: 39d52e991403eb9113fdce1b9fc7611c7627c24b [file] [log] [blame]
package org.apache.commons.ognl;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.commons.ognl.enhance.ExpressionCompiler;
import org.apache.commons.ognl.enhance.OgnlExpressionCompiler;
import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
import java.beans.IntrospectionException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
/**
* Implementation of PropertyAccessor that uses reflection on the target object's class to find a field or a pair of
* set/get methods with the given property name.
*/
public class ObjectPropertyAccessor
implements PropertyAccessor
{
/**
* Returns OgnlRuntime.NotFound if the property does not exist.
*/
public Object getPossibleProperty( Map<String, Object> context, Object target, String name )
throws OgnlException
{
Object result;
OgnlContext ognlContext = (OgnlContext) context;
try
{
result = OgnlRuntime.getMethodValue( ognlContext, target, name, true );
if ( result == OgnlRuntime.NotFound )
{
result = OgnlRuntime.getFieldValue( ognlContext, target, name, true );
}
}
catch ( IntrospectionException ex )
{
throw new OgnlException( name, ex );
}
catch ( OgnlException ex )
{
throw ex;
}
catch ( Exception ex )
{
throw new OgnlException( name, ex );
}
return result;
}
/**
* Returns OgnlRuntime.NotFound if the property does not exist.
*/
public Object setPossibleProperty( Map<String, Object> context, Object target, String name, Object value )
throws OgnlException
{
Object result = null;
OgnlContext ognlContext = (OgnlContext) context;
try
{
if ( !OgnlRuntime.setMethodValue( ognlContext, target, name, value, true ) )
{
result = OgnlRuntime.setFieldValue( ognlContext, target, name, value ) ? null : OgnlRuntime.NotFound;
}
if ( result == OgnlRuntime.NotFound )
{
Method m = OgnlRuntime.getWriteMethod( target.getClass(), name );
if ( m != null )
{
result = m.invoke( target, value );
}
}
}
catch ( IntrospectionException ex )
{
throw new OgnlException( name, ex );
}
catch ( OgnlException ex )
{
throw ex;
}
catch ( Exception ex )
{
throw new OgnlException( name, ex );
}
return result;
}
public boolean hasGetProperty( OgnlContext context, Object target, Object oname )
throws OgnlException
{
try
{
return OgnlRuntime.hasGetProperty( context, target, oname );
}
catch ( IntrospectionException ex )
{
throw new OgnlException( "checking if " + target + " has gettable property " + oname, ex );
}
}
public boolean hasGetProperty( Map<String, Object> context, Object target, Object oname )
throws OgnlException
{
return hasGetProperty( (OgnlContext) context, target, oname );
}
public boolean hasSetProperty( OgnlContext context, Object target, Object oname )
throws OgnlException
{
try
{
return OgnlRuntime.hasSetProperty( context, target, oname );
}
catch ( IntrospectionException ex )
{
throw new OgnlException( "checking if " + target + " has settable property " + oname, ex );
}
}
public boolean hasSetProperty( Map<String, Object> context, Object target, Object oname )
throws OgnlException
{
return hasSetProperty( (OgnlContext) context, target, oname );
}
public Object getProperty( Map<String, Object> context, Object target, Object oname )
throws OgnlException
{
String name = oname.toString();
Object result = getPossibleProperty( context, target, name );
if ( result == OgnlRuntime.NotFound )
{
throw new NoSuchPropertyException( target, name );
}
return result;
}
public void setProperty( Map<String, Object> context, Object target, Object oname, Object value )
throws OgnlException
{
String name = oname.toString();
Object result = setPossibleProperty( context, target, name, value );
if ( result == OgnlRuntime.NotFound )
{
throw new NoSuchPropertyException( target, name );
}
}
public Class<?> getPropertyClass( OgnlContext context, Object target, Object index )
{
try
{
Method m = OgnlRuntime.getReadMethod( target.getClass(), index.toString() );
if ( m == null )
{
if ( String.class.isAssignableFrom( index.getClass() ) && !target.getClass().isArray() )
{
String key = ( (String) index ).replace( "\"", "" );
try
{
Field f = target.getClass().getField( key );
if ( f != null )
{
return f.getType();
}
}
catch ( NoSuchFieldException e )
{
return null;
}
}
return null;
}
return m.getReturnType();
}
catch ( Throwable t )
{
throw OgnlOps.castToRuntime( t );
}
}
public String getSourceAccessor( OgnlContext context, Object target, Object index )
{
try
{
String methodName = index.toString().replace( "\"", "" );
Method m = OgnlRuntime.getReadMethod( target.getClass(), methodName );
// try last ditch effort of checking if they were trying to do reflection via a return method value
if ( m == null && context.getCurrentObject() != null )
{
m =
OgnlRuntime.getReadMethod( target.getClass(),
context.getCurrentObject().toString().replace( "\"", "" ) );
}
// System.out.println("tried to get read method from target: " + target.getClass() + " with methodName:" +
// methodName + " result: " + m);
// try to get field if no method could be found
if ( m == null )
{
try
{
if ( String.class.isAssignableFrom( index.getClass() ) && !target.getClass().isArray() )
{
Field f = target.getClass().getField( methodName );
if ( f != null )
{
context.setCurrentType( f.getType() );
context.setCurrentAccessor( f.getDeclaringClass() );
return "." + f.getName();
}
}
}
catch ( NoSuchFieldException e )
{
// ignore
}
return "";
}
context.setCurrentType( m.getReturnType() );
final OgnlExpressionCompiler compiler = OgnlRuntime.getCompiler( context );
context.setCurrentAccessor( compiler.getSuperOrInterfaceClass( m, m.getDeclaringClass() ) );
return "." + m.getName() + "()";
}
catch ( Throwable t )
{
throw OgnlOps.castToRuntime( t );
}
}
public String getSourceSetter( OgnlContext context, Object target, Object index )
{
try
{
String methodName = index.toString().replace( "\"", "" );
Method m = OgnlRuntime.getWriteMethod( target.getClass(), methodName );
if ( m == null && context.getCurrentObject() != null && context.getCurrentObject().toString() != null )
{
m =
OgnlRuntime.getWriteMethod( target.getClass(),
context.getCurrentObject().toString().replace( "\"", "" ) );
}
if ( m == null || m.getParameterTypes() == null || m.getParameterTypes().length <= 0 )
{
throw new UnsupportedCompilationException( "Unable to determine setting expression on "
+ context.getCurrentObject() + " with index of " + index );
}
Class<?> parm = m.getParameterTypes()[0];
String conversion;
if ( m.getParameterTypes().length > 1 )
{
throw new UnsupportedCompilationException(
"Object property accessors can only support single parameter setters." );
}
final OgnlExpressionCompiler compiler = OgnlRuntime.getCompiler( context );
if ( parm.isPrimitive() )
{
Class<?> wrapClass = OgnlRuntime.getPrimitiveWrapperClass( parm );
conversion = compiler.createLocalReference( context, "((" + wrapClass.getName()
+ ")org.apache.commons.ognl.OgnlOps#convertValue($3," + wrapClass.getName() + ".class, true))."
+ OgnlRuntime.getNumericValueGetter( wrapClass ), parm );
}
else if ( parm.isArray() )
{
conversion = compiler.createLocalReference( context, "(" + ExpressionCompiler.getCastString( parm )
+ ")org.apache.commons.ognl.OgnlOps#toArray($3," + parm.getComponentType().getName() + ".class)",
parm );
}
else
{
conversion = compiler.createLocalReference( context, "(" + parm.getName()
+ ")org.apache.commons.ognl.OgnlOps#convertValue($3," + parm.getName() + ".class)", parm );
}
context.setCurrentType( m.getReturnType() );
context.setCurrentAccessor(
compiler.getSuperOrInterfaceClass( m, m.getDeclaringClass() ) );
return "." + m.getName() + "(" + conversion + ")";
}
catch ( Throwable t )
{
throw OgnlOps.castToRuntime( t );
}
}
}