001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.jexl2.internal;
019    import java.lang.reflect.InvocationTargetException;
020    
021    /**
022     * Specialized executor to get a property from an object.
023     * @since 2.0
024     */
025    public final class PropertyGetExecutor extends AbstractExecutor.Get {
026        /** A static signature for method(). */
027        private static final Object[] EMPTY_PARAMS = {};
028        /** The property. */
029        private final String property;
030        
031        /**
032         * Creates an instance by attempting discovery of the get method.
033         * @param is the introspector
034         * @param clazz the class to introspect
035         * @param identifier the property to get
036         */
037        public PropertyGetExecutor(Introspector is, Class<?> clazz, String identifier) {
038            super(clazz, discover(is, clazz, identifier));
039            property = identifier;
040        }
041    
042        /** {@inheritDoc} */
043        @Override
044        public Object getTargetProperty() {
045            return property;
046        }
047        
048        /** {@inheritDoc} */
049        @Override
050        public Object execute(Object o)
051            throws IllegalAccessException, InvocationTargetException {
052            return method == null ? null : method.invoke(o, (Object[]) null);
053        }
054    
055        /** {@inheritDoc} */
056        @Override
057        public Object tryExecute(Object o, Object identifier) {
058            if (o != null && method !=  null
059                && property.equals(identifier)
060                && objectClass.equals(o.getClass())) {
061                try {
062                    return method.invoke(o, (Object[]) null);
063                } catch (InvocationTargetException xinvoke) {
064                    return TRY_FAILED; // fail
065                } catch (IllegalAccessException xill) {
066                    return TRY_FAILED;// fail
067                }
068            }
069            return TRY_FAILED;
070        }
071    
072        /**
073         * Discovers the method for a {@link PropertyGet}.
074         * <p>The method to be found should be named "get{P,p}property.</p>
075         *@param is the introspector
076         *@param clazz the class to find the get method from
077         *@param property the property name to find
078         *@return the method if found, null otherwise
079         */
080        static java.lang.reflect.Method discover(Introspector is,
081                final Class<?> clazz, String property) {
082            return discoverGet(is, "get", clazz, property);
083        }
084    
085    
086        /**
087         * Base method for boolean & object property get.
088         * @param is the introspector
089         * @param which "is" or "get" for boolean or object
090         * @param clazz The class being examined.
091         * @param property The property being addressed.
092         * @return The {get,is}{p,P}roperty method if one exists, null otherwise.
093         */
094        static java.lang.reflect.Method discoverGet(Introspector is,
095                String which, Class<?> clazz, String property) {
096            //  this is gross and linear, but it keeps it straightforward.
097            java.lang.reflect.Method method = null;
098            final int start = which.length(); // "get" or "is" so 3 or 2 for char case switch
099            // start with get<Property>
100            StringBuilder sb = new StringBuilder(which);
101            sb.append(property);
102            // uppercase nth char
103            char c = sb.charAt(start);
104            sb.setCharAt(start, Character.toUpperCase(c));
105            method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS);
106            //lowercase nth char
107            if (method == null) {
108                sb.setCharAt(start, Character.toLowerCase(c));
109                method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS);
110            }
111            return method;
112        }
113    }
114