    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