View Javadoc

1   package org.apache.commons.ognl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.ognl.enhance.ExpressionCompiler;
23  import org.apache.commons.ognl.enhance.OgnlExpressionCompiler;
24  import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
25  
26  import java.beans.IntrospectionException;
27  import java.lang.reflect.Field;
28  import java.lang.reflect.Method;
29  import java.util.Map;
30  
31  /**
32   * Implementation of PropertyAccessor that uses reflection on the target object's class to find a field or a pair of
33   * set/get methods with the given property name.
34   * 
35   * @author Luke Blanshard (blanshlu@netscape.net)
36   * @author Drew Davidson (drew@ognl.org)
37   */
38  public class ObjectPropertyAccessor
39      implements PropertyAccessor
40  {
41  
42      /**
43       * Returns OgnlRuntime.NotFound if the property does not exist.
44       */
45      public Object getPossibleProperty( Map<String, Object> context, Object target, String name )
46          throws OgnlException
47      {
48          Object result;
49          OgnlContext ognlContext = (OgnlContext) context;
50  
51          try
52          {
53              result = OgnlRuntime.getMethodValue( ognlContext, target, name, true );
54              if ( result == OgnlRuntime.NotFound )
55              {
56                  result = OgnlRuntime.getFieldValue( ognlContext, target, name, true );
57              }
58          }
59          catch ( IntrospectionException ex )
60          {
61              throw new OgnlException( name, ex );
62          }
63          catch ( OgnlException ex )
64          {
65              throw ex;
66          }
67          catch ( Exception ex )
68          {
69              throw new OgnlException( name, ex );
70          }
71  
72          return result;
73      }
74  
75      /**
76       * Returns OgnlRuntime.NotFound if the property does not exist.
77       */
78      public Object setPossibleProperty( Map<String, Object> context, Object target, String name, Object value )
79          throws OgnlException
80      {
81          Object result = null;
82          OgnlContext ognlContext = (OgnlContext) context;
83  
84          try
85          {
86              if ( !OgnlRuntime.setMethodValue( ognlContext, target, name, value, true ) )
87              {
88                  result = OgnlRuntime.setFieldValue( ognlContext, target, name, value ) ? null : OgnlRuntime.NotFound;
89              }
90  
91              if ( result == OgnlRuntime.NotFound )
92              {
93                  Method m = OgnlRuntime.getWriteMethod( target.getClass(), name );
94                  if ( m != null )
95                  {
96                      result = m.invoke( target, new Object[] { value } );
97                  }
98              }
99          }
100         catch ( IntrospectionException ex )
101         {
102             throw new OgnlException( name, ex );
103         }
104         catch ( OgnlException ex )
105         {
106             throw ex;
107         }
108         catch ( Exception ex )
109         {
110             throw new OgnlException( name, ex );
111         }
112 
113         return result;
114     }
115 
116     public boolean hasGetProperty( OgnlContext context, Object target, Object oname )
117         throws OgnlException
118     {
119         try
120         {
121             return OgnlRuntime.hasGetProperty( context, target, oname );
122         }
123         catch ( IntrospectionException ex )
124         {
125             throw new OgnlException( "checking if " + target + " has gettable property " + oname, ex );
126         }
127     }
128 
129     public boolean hasGetProperty( Map<String, Object> context, Object target, Object oname )
130         throws OgnlException
131     {
132         return hasGetProperty( (OgnlContext) context, target, oname );
133     }
134 
135     public boolean hasSetProperty( OgnlContext context, Object target, Object oname )
136         throws OgnlException
137     {
138         try
139         {
140             return OgnlRuntime.hasSetProperty( context, target, oname );
141         }
142         catch ( IntrospectionException ex )
143         {
144             throw new OgnlException( "checking if " + target + " has settable property " + oname, ex );
145         }
146     }
147 
148     public boolean hasSetProperty( Map<String, Object> context, Object target, Object oname )
149         throws OgnlException
150     {
151         return hasSetProperty( (OgnlContext) context, target, oname );
152     }
153 
154     public Object getProperty( Map<String, Object> context, Object target, Object oname )
155         throws OgnlException
156     {
157         String name = oname.toString();
158 
159         Object result = getPossibleProperty( context, target, name );
160 
161         if ( result == OgnlRuntime.NotFound )
162         {
163             throw new NoSuchPropertyException( target, name );
164         }
165 
166         return result;
167     }
168 
169     public void setProperty( Map<String, Object> context, Object target, Object oname, Object value )
170         throws OgnlException
171     {
172         String name = oname.toString();
173 
174         Object result = setPossibleProperty( context, target, name, value );
175 
176         if ( result == OgnlRuntime.NotFound )
177         {
178             throw new NoSuchPropertyException( target, name );
179         }
180     }
181 
182     public Class<?> getPropertyClass( OgnlContext context, Object target, Object index )
183     {
184         try
185         {
186             Method m = OgnlRuntime.getReadMethod( target.getClass(), index.toString() );
187 
188             if ( m == null )
189             {
190 
191                 if ( String.class.isAssignableFrom( index.getClass() ) && !target.getClass().isArray() )
192                 {
193                     String key = ( (String) index ).replaceAll( "\"", "" );
194                     try
195                     {
196                         Field f = target.getClass().getField( key );
197                         if ( f != null )
198                         {
199 
200                             return f.getType();
201                         }
202                     }
203                     catch ( NoSuchFieldException e )
204                     {
205                         return null;
206                     }
207                 }
208 
209                 return null;
210             }
211 
212             return m.getReturnType();
213 
214         }
215         catch ( Throwable t )
216         {
217             throw OgnlOps.castToRuntime( t );
218         }
219     }
220 
221     public String getSourceAccessor( OgnlContext context, Object target, Object index )
222     {
223         try
224         {
225 
226             String methodName = index.toString().replaceAll( "\"", "" );
227             Method m = OgnlRuntime.getReadMethod( target.getClass(), methodName );
228 
229             // try last ditch effort of checking if they were trying to do reflection via a return method value
230 
231             if ( m == null && context.getCurrentObject() != null )
232             {
233                 m =
234                     OgnlRuntime.getReadMethod( target.getClass(),
235                                                context.getCurrentObject().toString().replaceAll( "\"", "" ) );
236             }
237             // System.out.println("tried to get read method from target: " + target.getClass() + " with methodName:" +
238             // methodName + " result: " + m);
239             // try to get field if no method could be found
240 
241             if ( m == null )
242             {
243                 try
244                 {
245                     if ( String.class.isAssignableFrom( index.getClass() ) && !target.getClass().isArray() )
246                     {
247                         Field f = target.getClass().getField( methodName );
248 
249                         if ( f != null )
250                         {
251                             context.setCurrentType( f.getType() );
252                             context.setCurrentAccessor( f.getDeclaringClass() );
253 
254                             return "." + f.getName();
255                         }
256                     }
257                 }
258                 catch ( NoSuchFieldException e )
259                 {
260                     // ignore
261                 }
262 
263                 return "";
264             }
265 
266             context.setCurrentType( m.getReturnType() );
267             final OgnlExpressionCompiler compiler = OgnlRuntime.getCompiler( context );
268             context.setCurrentAccessor( compiler.getSuperOrInterfaceClass( m, m.getDeclaringClass() ) );
269 
270             return "." + m.getName() + "()";
271 
272         }
273         catch ( Throwable t )
274         {
275             throw OgnlOps.castToRuntime( t );
276         }
277     }
278 
279     public String getSourceSetter( OgnlContext context, Object target, Object index )
280     {
281         try
282         {
283 
284             String methodName = index.toString().replaceAll( "\"", "" );
285             Method m = OgnlRuntime.getWriteMethod( target.getClass(), methodName );
286 
287             if ( m == null && context.getCurrentObject() != null && context.getCurrentObject().toString() != null )
288             {
289                 m =
290                     OgnlRuntime.getWriteMethod( target.getClass(),
291                                                 context.getCurrentObject().toString().replaceAll( "\"", "" ) );
292             }
293 
294             if ( m == null || m.getParameterTypes() == null || m.getParameterTypes().length <= 0 )
295             {
296                 throw new UnsupportedCompilationException( "Unable to determine setting expression on "
297                     + context.getCurrentObject() + " with index of " + index );
298             }
299 
300             Class<?> parm = m.getParameterTypes()[0];
301             String conversion;
302 
303             if ( m.getParameterTypes().length > 1 )
304             {
305                 throw new UnsupportedCompilationException(
306                     "Object property accessors can only support single parameter setters." );
307             }
308 
309             final OgnlExpressionCompiler compiler = OgnlRuntime.getCompiler( context );
310             if ( parm.isPrimitive() )
311             {
312                 Class<?> wrapClass = OgnlRuntime.getPrimitiveWrapperClass( parm );
313                 conversion = compiler.createLocalReference( context, "((" + wrapClass.getName()
314                     + ")org.apache.commons.ognl.OgnlOps#convertValue($3," + wrapClass.getName() + ".class, true))."
315                     + OgnlRuntime.getNumericValueGetter( wrapClass ), parm );
316 
317             }
318             else if ( parm.isArray() )
319             {
320                 conversion = compiler.createLocalReference( context, "(" + ExpressionCompiler.getCastString( parm )
321                     + ")org.apache.commons.ognl.OgnlOps#toArray($3," + parm.getComponentType().getName() + ".class)",
322                                                             parm );
323 
324             }
325             else
326             {
327                 conversion = compiler.createLocalReference( context, "(" + parm.getName()
328                     + ")org.apache.commons.ognl.OgnlOps#convertValue($3," + parm.getName() + ".class)", parm );
329             }
330 
331             context.setCurrentType( m.getReturnType() );
332             context.setCurrentAccessor(
333                 compiler.getSuperOrInterfaceClass( m, m.getDeclaringClass() ) );
334 
335             return "." + m.getName() + "(" + conversion + ")";
336 
337         }
338         catch ( Throwable t )
339         {
340             throw OgnlOps.castToRuntime( t );
341         }
342     }
343 }