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    *      https://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  
21  import org.apache.commons.jexl3.JexlException;
22  
23  /**
24   * Specialized executor to get a property from an object.
25   * @since 2.0
26   */
27  public final class PropertyGetExecutor extends AbstractExecutor.Get {
28      /** A static signature for method(). */
29      private static final Object[] EMPTY_PARAMS = {};
30      /**
31       * Discovers a PropertyGetExecutor.
32       * <p>The method to be found should be named "get{P,p}property.</p>
33       *
34       * @param is the introspector
35       * @param clazz the class to find the get method from
36       * @param property the property name to find
37       * @return the executor if found, null otherwise
38       */
39      public static PropertyGetExecutor discover(final Introspector is, final Class<?> clazz, final String property) {
40          final java.lang.reflect.Method method = discoverGet(is, "get", clazz, property);
41          return method == null ? null : new PropertyGetExecutor(clazz, method, property);
42      }
43  
44      /**
45       * Base method for boolean and object property get.
46       * @param is the introspector
47       * @param which "is" or "get" for boolean or object
48       * @param clazz The class being examined.
49       * @param property The property being addressed.
50       * @return The {get,is}{p,P}roperty method if one exists, null otherwise.
51       */
52      static java.lang.reflect.Method discoverGet(final Introspector is,
53                                                  final String which,
54                                                  final Class<?> clazz,
55                                                  final String property) {
56          if (property == null || property.isEmpty()) {
57              return null;
58          }
59          //  this is gross and linear, but it keeps it straightforward.
60          java.lang.reflect.Method method;
61          final int start = which.length(); // "get" or "is" so 3 or 2 for char case switch
62          // start with get<Property>
63          final StringBuilder sb = new StringBuilder(which);
64          sb.append(property);
65          // uppercase nth char
66          final char c = sb.charAt(start);
67          sb.setCharAt(start, Character.toUpperCase(c));
68          method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS);
69          //lowercase nth char
70          if (method == null) {
71              sb.setCharAt(start, Character.toLowerCase(c));
72              method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS);
73          }
74          return method;
75      }
76  
77      /** The property. */
78      private final String property;
79  
80      /**
81       * Creates an instance.
82       * @param clazz he class the get method applies to
83       * @param method the method held by this executor
84       * @param identifier the property to get
85       */
86      private PropertyGetExecutor(final Class<?> clazz, final java.lang.reflect.Method method, final String identifier) {
87          super(clazz, method);
88          property = identifier;
89      }
90  
91      @Override
92      public Object getTargetProperty() {
93          return property;
94      }
95  
96      @Override
97      public Object invoke(final Object o) throws IllegalAccessException, InvocationTargetException {
98          return method == null ? null : method.invoke(o, (Object[]) null);
99      }
100 
101     @Override
102     public Object tryInvoke(final Object o, final Object identifier) {
103         if (o != null && method != null
104             && property.equals(castString(identifier))
105             && objectClass.equals(o.getClass())) {
106             try {
107                 return method.invoke(o, (Object[]) null);
108             } catch (IllegalAccessException | IllegalArgumentException xill) {
109                 return TRY_FAILED; // fail
110             } catch (final InvocationTargetException xinvoke) {
111                 throw JexlException.tryFailed(xinvoke); // throw
112             }
113         }
114         return TRY_FAILED;
115     }
116 }
117