Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/myfaces/el/PropertyResolverImpl.java


1   /*
2    * Copyright 2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.myfaces.el;
17  
18  import org.apache.commons.beanutils.MethodUtils;
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  import javax.faces.el.EvaluationException;
23  import javax.faces.el.PropertyNotFoundException;
24  import javax.faces.el.PropertyResolver;
25  import javax.faces.el.ReferenceSyntaxException;
26  import java.beans.BeanInfo;
27  import java.beans.IntrospectionException;
28  import java.beans.Introspector;
29  import java.beans.PropertyDescriptor;
30  import java.lang.reflect.Array;
31  import java.lang.reflect.Method;
32  import java.util.List;
33  import java.util.Map;
34  
35  
36  /**
37   * @author Manfred Geiler (latest modification by $Author: oros $)
38   * @author Anton Koinov
39   * @version $Revision: 293105 $ $Date: 2005-10-02 08:45:03 -0400 (Sun, 02 Oct 2005) $
40   */
41  public class PropertyResolverImpl extends PropertyResolver
42  {
43      private static final Log log =
44          LogFactory.getLog(PropertyResolverImpl.class);
45  
46      //~ Static fields/initializers ---------------------------------------------
47  
48      private static final Object[] NO_ARGS = {};
49  
50      //~ Public PropertyResolver Methods ----------------------------------------
51  
52      public Object getValue(Object base, Object property)
53              throws EvaluationException, PropertyNotFoundException
54      {
55          try
56          {
57             //fix for myfaces-315 - empty string as key to a map-value is allowed
58             //thanks to duffy gillman
59             if (base == null || property == null ||
60                 (property instanceof String && ((String)property).length() == 0 &&
61                  !(base instanceof Map)))
62             {
63                 return null;
64             }
65             if (base instanceof Map)
66             {
67                 return ((Map) base).get(property);
68             }
69  
70              // If none of the special bean types, then process as normal Bean
71              return getProperty(base, property.toString());
72          }
73          catch (PropertyNotFoundException e) {
74              throw e;
75          }
76          catch (RuntimeException e)
77          {
78              throw new EvaluationException("Exception getting value of property " + property
79                  + " of bean "
80                  + base != null ? base.getClass().getName() : "NULL", e);
81          }
82      }
83  
84      public Object getValue(Object base, int index)
85              throws EvaluationException, PropertyNotFoundException
86      {
87          try
88          {
89              if (base == null)
90              {
91                  return null;
92              }
93  
94              try
95              {
96                  if (base.getClass().isArray())
97                  {
98                      return Array.get(base, index);
99                  }
100                 if (base instanceof List)
101                 {
102                     return ((List) base).get(index);
103                 }
104             }
105             catch (IndexOutOfBoundsException e)
106             {
107                 // Note: ArrayIndexOutOfBoundsException also here
108                 return null;
109             }
110 
111             throw new ReferenceSyntaxException("Must be array or List. Bean: "
112                 + base.getClass().getName() + ", index " + index);
113         }
114         catch (RuntimeException e)
115         {
116             throw new EvaluationException("Exception getting value for index " + index
117                 + " of bean "
118                 + base != null ? base.getClass().getName() : "NULL", e);
119         }
120     }
121 
122     public void setValue(Object base, Object property, Object newValue)
123             throws EvaluationException, PropertyNotFoundException
124     {
125         try
126         {
127             if (base == null)
128             {
129                 throw new PropertyNotFoundException(
130                     "Null bean, property: " + property);
131             }
132             if (property == null ||
133                 property instanceof String && ((String)property).length() == 0)
134             {
135                 throw new PropertyNotFoundException("Bean: "
136                     + base.getClass().getName()
137                     + ", null or empty property name");
138             }
139 
140             if (base instanceof Map)
141             {
142                 ((Map) base).put(property, newValue);
143 
144                 return;
145             }
146 
147             // If none of the special bean types, then process as normal Bean
148             setProperty(base, property.toString(), newValue);
149         }
150         catch (PropertyNotFoundException e) {
151             throw e;
152         }
153         catch (RuntimeException e)
154         {
155             throw new EvaluationException("Exception setting property " + property
156                 + " of bean "
157                 + base != null ? base.getClass().getName() : "NULL", e);
158         }
159     }
160 
161     public void setValue(Object base, int index, Object newValue)
162             throws EvaluationException, PropertyNotFoundException
163     {
164         try
165         {
166             if (base == null)
167             {
168                 throw new PropertyNotFoundException(
169                     "Null bean, index: " + index);
170             }
171 
172             try
173             {
174                 if (base.getClass().isArray())
175                 {
176                     Array.set(base, index, newValue);
177 
178                     return;
179                 }
180                 if (base instanceof List)
181                 {
182                     // REVISIT: should we try to grow the list, if growable type
183                     //          (e.g., ArrayList, etc.), and if not large
184                     //          enough?
185                     ((List) base).set(index, newValue);
186 
187                     return;
188                 }
189             }
190             catch (IndexOutOfBoundsException e)
191             {
192                 throw new PropertyNotFoundException("Bean: "
193                     + base.getClass().getName() + ", index " + index, e);
194             }
195 
196             throw new EvaluationException(
197                 "Bean must be array or List. Bean: "
198                 + base.getClass().getName() + ", index " + index);
199         }
200         catch (PropertyNotFoundException e) {
201             throw e;
202         }
203         catch (RuntimeException e)
204         {
205             throw new EvaluationException("Exception setting value of index " + index + " of bean "
206                 + base != null ? base.getClass().getName() : "NULL", e);
207         }
208     }
209 
210     public boolean isReadOnly(Object base, Object property)
211     {
212         try
213         {
214             if (base == null || property == null ||
215                 property instanceof String && ((String)property).length() == 0)
216             {
217                 // Cannot determine read-only, return false (is this what the spec requires?)
218                 return false;
219             }
220 
221             // Is there any way to determine whether Map.put() will fail?
222             if (base instanceof Map)
223             {
224                 return false;
225             }
226 
227             // If none of the special bean types, then process as normal Bean
228             PropertyDescriptor propertyDescriptor =
229                 getPropertyDescriptor(base, property.toString());
230 
231             return propertyDescriptor.getWriteMethod() == null;
232         }
233         catch (Exception e)
234         {
235             // Cannot determine read-only, return false (is this what the spec requires?)
236             return false;
237         }
238     }
239 
240     public boolean isReadOnly(Object base, int index)
241     {
242         try
243         {
244             if (base == null)
245             {
246                 // Cannot determine read-only, return false (is this what the spec requires?)
247                 return false;
248             }
249             if (base instanceof List || base.getClass().isArray())
250             {
251                 // Is there any way to determine whether List.set() will fail?
252                 return false;
253             }
254 
255             // Cannot determine read-only, return false (is this what the spec requires?)
256             return false;
257         }
258         catch (Exception e)
259         {
260             // Cannot determine read-only, return false (is this what the spec requires?)
261             return false;
262         }
263     }
264 
265     public Class getType(Object base, Object property)
266     {
267         try
268         {
269             if (base == null || property == null ||
270                 property instanceof String && ((String)property).length() == 0)
271             {
272                 throw new PropertyNotFoundException("Bean is null");
273             }
274 
275             if (base instanceof Map)
276             {
277                 Object value = ((Map) base).get(property);
278 
279                 // REVISIT: when generics are imlemented in JVM 1.5
280                 return (value == null) ? Object.class : value.getClass();
281             }
282 
283             // If none of the special bean types, then process as normal Bean
284             PropertyDescriptor propertyDescriptor =
285                 getPropertyDescriptor(base, property.toString());
286 
287             return propertyDescriptor.getPropertyType();
288         }
289         catch (PropertyNotFoundException e) {
290             throw e;
291         }
292         catch (Exception e)
293         {
294             return null;
295         }
296     }
297 
298     public Class getType(Object base, int index)
299     {
300         if (base == null)
301         {
302             throw new PropertyNotFoundException("Bean is null");
303         }
304 
305         try
306         {
307             if (base.getClass().isArray())
308             {
309                 if (base instanceof Object[] && ((Object[])base)[index] != null) {
310                     Object[] array = (Object[]) base;
311                     return array[index].getClass().getComponentType();
312                 } else {
313                     return base.getClass().getComponentType();
314                 }
315             }
316 
317             if (base instanceof List)
318             {
319                 // REVISIT: does it make sense to do this or simply return
320                 //          Object.class? What if the new value is not of
321                 //          the old value's class?
322                 Object value = ((List) base).get(index);
323 
324                 // REVISIT: when generics are implemented in JVM 1.5
325                 return (value != null) ? value.getClass() : Object.class;
326             }
327 
328             // Cannot determine type, return null per JSF spec
329             return null;
330         }
331         catch (IndexOutOfBoundsException e) {
332             throw new PropertyNotFoundException("Bean: "
333                 + base.getClass().getName() + ", index " + index, e);
334         }
335         catch (Exception e)
336         {
337             throw new EvaluationException("Exception getting type of index " + index + " of bean "
338                 + base != null ? base.getClass().getName() : "NULL", e);
339         }
340     }
341 
342 
343     //~ Internal Helper Methods ------------------------------------------------
344 
345     public static void setProperty(Object base, String name, Object newValue)
346     {
347         PropertyDescriptor propertyDescriptor =
348             getPropertyDescriptor(base, name);
349 
350         Method m = propertyDescriptor.getWriteMethod();
351         if (m == null)
352         {
353             throw new PropertyNotFoundException(
354                 "Bean: " + base.getClass().getName() + ", property: " + name);
355         }
356 
357         // Check if the concrete class of this method is accessible and if not
358         // search for a public interface that declares this method
359         m = MethodUtils.getAccessibleMethod(m);
360         if (m == null)
361         {
362             throw new PropertyNotFoundException(
363                 "Bean: " + base.getClass().getName() + ", property: " + name + " (not accessible!)");
364         }
365 
366         try
367         {
368             m.invoke(base, new Object[] {newValue});
369         }
370         catch (Throwable t)
371         {
372             throw new EvaluationException("Bean: "
373                 + base.getClass().getName() + ", property: " + name, t);
374         }
375     }
376 
377     public static Object getProperty(Object base, String name)
378     {
379         PropertyDescriptor propertyDescriptor =
380             getPropertyDescriptor(base, name);
381 
382         Method m = propertyDescriptor.getReadMethod();
383         if (m == null)
384         {
385             throw new PropertyNotFoundException(
386                 "Bean: " + base.getClass().getName() + ", property: " + name);
387         }
388 
389         // Check if the concrete class of this method is accessible and if not
390         // search for a public interface that declares this method
391         m = MethodUtils.getAccessibleMethod(m);
392         if (m == null)
393         {
394             throw new PropertyNotFoundException(
395                 "Bean: " + base.getClass().getName() + ", property: " + name + " (not accessible!)");
396         }
397 
398         try
399         {
400             return m.invoke(base, NO_ARGS);
401         }
402         catch (Throwable t)
403         {
404             throw new EvaluationException("Bean: "
405                 + base.getClass().getName() + ", property: " + name, t);
406         }
407     }
408 
409     public static PropertyDescriptor getPropertyDescriptor(
410         Object base, String name)
411     {
412         PropertyDescriptor propertyDescriptor;
413 
414         try
415         {
416             propertyDescriptor =
417                 getPropertyDescriptor(
418                     Introspector.getBeanInfo(base.getClass()), name);
419         }
420         catch (IntrospectionException e)
421         {
422             throw new PropertyNotFoundException("Bean: "
423                 + base.getClass().getName() + ", property: " + name, e);
424         }
425 
426         return propertyDescriptor;
427     }
428 
429     public static PropertyDescriptor getPropertyDescriptor(
430         BeanInfo beanInfo, String propertyName)
431     {
432         PropertyDescriptor[] propDescriptors =
433             beanInfo.getPropertyDescriptors();
434 
435         if (propDescriptors != null)
436         {
437             // TODO: cache this in classLoader safe way
438             for (int i = 0, len = propDescriptors.length; i < len; i++)
439             {
440                 if (propDescriptors[i].getName().equals(propertyName))
441                     return propDescriptors[i];
442             }
443         }
444 
445         throw new PropertyNotFoundException("Bean: "
446             + beanInfo.getBeanDescriptor().getBeanClass().getName()
447             + ", property: " + propertyName);
448     }
449 
450 }