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    package org.apache.commons.jxpath.functions;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.InvocationTargetException;
021    
022    import org.apache.commons.jxpath.ExpressionContext;
023    import org.apache.commons.jxpath.Function;
024    import org.apache.commons.jxpath.JXPathInvalidAccessException;
025    import org.apache.commons.jxpath.util.TypeUtils;
026    
027    /**
028     * An extension function that creates an instance using a constructor.
029     *
030     * @author Dmitri Plotnikov
031     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
032     */
033    public class ConstructorFunction implements Function {
034        private static final Object[] EMPTY_ARRAY = new Object[0];
035    
036        private Constructor constructor;
037    
038        /**
039         * Create a new ConstructorFunction.
040         * @param constructor the constructor to call.
041         */
042        public ConstructorFunction(Constructor constructor) {
043            this.constructor = constructor;
044        }
045    
046        /**
047         * Converts parameters to suitable types and invokes the constructor.
048         * @param context evaluation context
049         * @param parameters constructor args
050         * @return new instance
051         */
052        public Object invoke(ExpressionContext context, Object[] parameters) {
053            try {
054                Object[] args;
055                if (parameters == null) {
056                    parameters = EMPTY_ARRAY;
057                }
058                int pi = 0;
059                Class[] types = constructor.getParameterTypes();
060                if (types.length > 0
061                    && ExpressionContext.class.isAssignableFrom(types[0])) {
062                    pi = 1;
063                }
064                args = new Object[parameters.length + pi];
065                if (pi == 1) {
066                    args[0] = context;
067                }
068                for (int i = 0; i < parameters.length; i++) {
069                    args[i + pi] = TypeUtils.convert(parameters[i], types[i + pi]);
070                }
071                return constructor.newInstance(args);
072            }
073            catch (Throwable ex) {
074                if (ex instanceof InvocationTargetException) {
075                    ex = ((InvocationTargetException) ex).getTargetException();
076                }
077                throw new JXPathInvalidAccessException(
078                    "Cannot invoke constructor " + constructor,
079                    ex);
080            }
081        }
082    }