    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
    018package org.apache.commons.jxpath.functions;
    019
    020import java.lang.reflect.Constructor;
    021import java.lang.reflect.InvocationTargetException;
    022
    023import org.apache.commons.jxpath.ExpressionContext;
    024import org.apache.commons.jxpath.Function;
    025import org.apache.commons.jxpath.JXPathInvalidAccessException;
    026import org.apache.commons.jxpath.util.TypeUtils;
    027
    028/**
    029 * An extension function that creates an instance using a constructor.
    030 */
    031public class ConstructorFunction implements Function {
    032
    033    private static final Object[] EMPTY_ARRAY = {};
    034    private final Constructor constructor;
    035
    036    /**
    037     * Constructs a new ConstructorFunction.
    038     *
    039     * @param constructor the constructor to call.
    040     */
    041    public ConstructorFunction(final Constructor constructor) {
    042        this.constructor = constructor;
    043    }
    044
    045    /**
    046     * Converts parameters to suitable types and invokes the constructor.
    047     *
    048     * @param context    evaluation context
    049     * @param parameters constructor args
    050     * @return new instance
    051     */
    052    @Override
    053    public Object invoke(final ExpressionContext context, Object[] parameters) {
    054        try {
    055            Object[] args;
    056            if (parameters == null) {
    057                parameters = EMPTY_ARRAY;
    058            }
    059            int pi = 0;
    060            final Class[] types = constructor.getParameterTypes();
    061            if (types.length > 0 && 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        } catch (Throwable ex) {
    073            if (ex instanceof InvocationTargetException) {
    074                ex = ((InvocationTargetException) ex).getTargetException();
    075            }
    076            throw new JXPathInvalidAccessException("Cannot invoke constructor " + constructor, ex);
    077        }
    078    }
    079}