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.collections.functors;
018    
019    import java.io.Serializable;
020    import java.lang.reflect.Constructor;
021    import java.lang.reflect.InvocationTargetException;
022    
023    import org.apache.commons.collections.FunctorException;
024    import org.apache.commons.collections.Transformer;
025    
026    /**
027     * Transformer implementation that creates a new object instance by reflection.
028     * 
029     * @since Commons Collections 3.0
030     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
031     *
032     * @author Stephen Colebourne
033     */
034    public class InstantiateTransformer implements Transformer, Serializable {
035    
036        /** The serial version */
037        private static final long serialVersionUID = 3786388740793356347L;
038        
039        /** Singleton instance that uses the no arg constructor */
040        public static final Transformer NO_ARG_INSTANCE = new InstantiateTransformer();
041    
042        /** The constructor parameter types */
043        private final Class[] iParamTypes;
044        /** The constructor arguments */
045        private final Object[] iArgs;
046    
047        /**
048         * Transformer method that performs validation.
049         * 
050         * @param paramTypes  the constructor parameter types
051         * @param args  the constructor arguments
052         * @return an instantiate transformer
053         */
054        public static Transformer getInstance(Class[] paramTypes, Object[] args) {
055            if (((paramTypes == null) && (args != null))
056                || ((paramTypes != null) && (args == null))
057                || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
058                throw new IllegalArgumentException("Parameter types must match the arguments");
059            }
060    
061            if (paramTypes == null || paramTypes.length == 0) {
062                return NO_ARG_INSTANCE;
063            } else {
064                paramTypes = (Class[]) paramTypes.clone();
065                args = (Object[]) args.clone();
066            }
067            return new InstantiateTransformer(paramTypes, args);
068        }
069    
070        /**
071         * Constructor for no arg instance.
072         */
073        private InstantiateTransformer() {
074            super();
075            iParamTypes = null;
076            iArgs = null;
077        }
078    
079        /**
080         * Constructor that performs no validation.
081         * Use <code>getInstance</code> if you want that.
082         * 
083         * @param paramTypes  the constructor parameter types, not cloned
084         * @param args  the constructor arguments, not cloned
085         */
086        public InstantiateTransformer(Class[] paramTypes, Object[] args) {
087            super();
088            iParamTypes = paramTypes;
089            iArgs = args;
090        }
091    
092        /**
093         * Transforms the input Class object to a result by instantiation.
094         * 
095         * @param input  the input object to transform
096         * @return the transformed result
097         */
098        public Object transform(Object input) {
099            try {
100                if (input instanceof Class == false) {
101                    throw new FunctorException(
102                        "InstantiateTransformer: Input object was not an instanceof Class, it was a "
103                            + (input == null ? "null object" : input.getClass().getName()));
104                }
105                Constructor con = ((Class) input).getConstructor(iParamTypes);
106                return con.newInstance(iArgs);
107    
108            } catch (NoSuchMethodException ex) {
109                throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
110            } catch (InstantiationException ex) {
111                throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
112            } catch (IllegalAccessException ex) {
113                throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
114            } catch (InvocationTargetException ex) {
115                throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
116            }
117        }
118    
119    }