View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jexl3.internal.introspection;
19  import java.lang.reflect.InvocationTargetException;
20  import org.apache.commons.jexl3.JexlException;
21  
22  /**
23   * Specialized executor to get a property from an object.
24   * @since 2.0
25   */
26  public final class PropertyGetExecutor extends AbstractExecutor.Get {
27      /** A static signature for method(). */
28      private static final Object[] EMPTY_PARAMS = {};
29      /** The property. */
30      private final String property;
31  
32      /**
33       * Discovers a PropertyGetExecutor.
34       * <p>The method to be found should be named "get{P,p}property.</p>
35       *
36       * @param is the introspector
37       * @param clazz the class to find the get method from
38       * @param property the property name to find
39       * @return the executor if found, null otherwise
40       */
41      public static PropertyGetExecutor discover(final Introspector is, final Class<?> clazz, final String property) {
42          final java.lang.reflect.Method method = discoverGet(is, "get", clazz, property);
43          return method == null? null : new PropertyGetExecutor(clazz, method, property);
44      }
45  
46      /**
47       * Creates an instance.
48       * @param clazz he class the get method applies to
49       * @param method the method held by this executor
50       * @param identifier the property to get
51       */
52      private PropertyGetExecutor(final Class<?> clazz, final java.lang.reflect.Method method, final String identifier) {
53          super(clazz, method);
54          property = identifier;
55      }
56  
57      @Override
58      public Object getTargetProperty() {
59          return property;
60      }
61  
62      @Override
63      public Object invoke(final Object o) throws IllegalAccessException, InvocationTargetException {
64          return method == null ? null : method.invoke(o, (Object[]) null);
65      }
66  
67      @Override
68      public Object tryInvoke(final Object o, final Object identifier) {
69          if (o != null && method != null
70              && property.equals(castString(identifier))
71              && objectClass.equals(o.getClass())) {
72              try {
73                  return method.invoke(o, (Object[]) null);
74              } catch (IllegalAccessException | IllegalArgumentException xill) {
75                  return TRY_FAILED;// fail
76              } catch (final InvocationTargetException xinvoke) {
77                  throw JexlException.tryFailed(xinvoke); // throw
78              }
79          }
80          return TRY_FAILED;
81      }
82  
83      /**
84       * Base method for boolean and object property get.
85       * @param is the introspector
86       * @param which "is" or "get" for boolean or object
87       * @param clazz The class being examined.
88       * @param property The property being addressed.
89       * @return The {get,is}{p,P}roperty method if one exists, null otherwise.
90       */
91      static java.lang.reflect.Method discoverGet(final Introspector is,
92                                                  final String which,
93                                                  final Class<?> clazz,
94                                                  final String property) {
95          if (property == null || property.isEmpty()) {
96              return null;
97          }
98          //  this is gross and linear, but it keeps it straightforward.
99          java.lang.reflect.Method method;
100         final int start = which.length(); // "get" or "is" so 3 or 2 for char case switch
101         // start with get<Property>
102         final StringBuilder sb = new StringBuilder(which);
103         sb.append(property);
104         // uppercase nth char
105         final char c = sb.charAt(start);
106         sb.setCharAt(start, Character.toUpperCase(c));
107         method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS);
108         //lowercase nth char
109         if (method == null) {
110             sb.setCharAt(start, Character.toLowerCase(c));
111             method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS);
112         }
113         return method;
114     }
115 }
116