    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     * Specialized executor to set a property in an object.
    022     * @since 2.0
    023     */
    024    public final class PropertySetExecutor extends AbstractExecutor.Set {
    025        /** Index of the first character of the set{p,P}roperty. */
    026        private static final int SET_START_INDEX = 3;
    027        /** The property. */
    028        private final String property;
    029
    030        /**
    031         * Creates an instance by attempting discovery of the set method.
    032         * @param is the introspector
    033         * @param clazz the class to introspect
    034         * @param identifier the property to set
    035         * @param arg the value to set into the property
    036         */
    037        public PropertySetExecutor(Introspector is, Class<?> clazz, String identifier, Object arg) {
    038            super(clazz, discover(is, clazz, identifier, arg));
    039            property = identifier;
    040
    041        }
    042
    043        /** {@inheritDoc} */
    044        @Override
    045        public Object getTargetProperty() {
    046            return property;
    047        }
    048
    049        /** {@inheritDoc} */
    050        @Override
    051        public Object execute(Object o, Object arg)
    052                throws IllegalAccessException, InvocationTargetException {
    053            Object[] pargs = {arg};
    054            if (method != null) {
    055                method.invoke(o, pargs);
    056            }
    057            return arg;
    058        }
    059
    060        /** {@inheritDoc} */
    061        @Override
    062        public Object tryExecute(Object o, Object identifier, Object arg) {
    063            if (o != null && method != null
    064                // ensure method name matches the property name
    065                && property.equals(identifier)
    066                // object class should be same as executor's method declaring class
    067                && objectClass.equals(o.getClass())
    068                // we are guaranteed the method has one parameter since it is a set(x)
    069                && (arg == null || method.getParameterTypes()[0].equals(arg.getClass()))) {
    070                try {
    071                    return execute(o, arg);
    072                } catch (InvocationTargetException xinvoke) {
    073                    return TRY_FAILED; // fail
    074                } catch (IllegalAccessException xill) {
    075                    return TRY_FAILED;// fail
    076                }
    077            }
    078            return TRY_FAILED;
    079        }
    080
    081
    082        /**
    083         * Discovers the method for a {@link PropertySet}.
    084         * <p>The method to be found should be named "set{P,p}property.</p>
    085         *@param is the introspector
    086         *@param clazz the class to find the get method from
    087         *@param property the name of the property to set
    088         *@param arg the value to assign to the property
    089         *@return the method if found, null otherwise
    090         */
    091        private static java.lang.reflect.Method discover(Introspector is,
    092                final Class<?> clazz, String property, Object arg) {
    093            // first, we introspect for the set<identifier> setter method
    094            Object[] params = {arg};
    095            StringBuilder sb = new StringBuilder("set");
    096            sb.append(property);
    097            // uppercase nth char
    098            char c = sb.charAt(SET_START_INDEX);
    099            sb.setCharAt(SET_START_INDEX, Character.toUpperCase(c));
    100            java.lang.reflect.Method method = is.getMethod(clazz, sb.toString(), params);
    101            // lowercase nth char
    102            if (method == null) {
    103                sb.setCharAt(SET_START_INDEX, Character.toLowerCase(c));
    104                method = is.getMethod(clazz, sb.toString(), params);
    105            }
    106
    107            return method;
    108        }
    109    }
    110