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