InstantiateFactory.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4.functors;

  18. import java.lang.reflect.Constructor;
  19. import java.lang.reflect.InvocationTargetException;
  20. import java.util.Objects;

  21. import org.apache.commons.collections4.Factory;
  22. import org.apache.commons.collections4.FunctorException;

  23. /**
  24.  * Factory implementation that creates a new object instance by reflection.
  25.  * <p>
  26.  * <strong>WARNING:</strong> from v4.1 onwards this class will <strong>not</strong> be serializable anymore
  27.  * in order to prevent potential remote code execution exploits. Please refer to
  28.  * <a href="https://issues.apache.org/jira/browse/COLLECTIONS-580">COLLECTIONS-580</a>
  29.  * for more details.
  30.  * </p>
  31.  *
  32.  * @param <T> the type of results supplied by this supplier.
  33.  * @since 3.0
  34.  */
  35. public class InstantiateFactory<T> implements Factory<T> {

  36.     /**
  37.      * Factory method that performs validation.
  38.      *
  39.      * @param <T>  the type the factory creates
  40.      * @param classToInstantiate  the class to instantiate, not null
  41.      * @param paramTypes  the constructor parameter types, cloned
  42.      * @param args  the constructor arguments, cloned
  43.      * @return a new instantiate factory
  44.      * @throws NullPointerException if classToInstantiate is null
  45.      * @throws IllegalArgumentException if paramTypes does not match args
  46.      */
  47.     public static <T> Factory<T> instantiateFactory(final Class<T> classToInstantiate,
  48.                                                     final Class<?>[] paramTypes,
  49.                                                     final Object[] args) {
  50.         Objects.requireNonNull(classToInstantiate, "classToInstantiate");
  51.         if (paramTypes == null && args != null
  52.             || paramTypes != null && args == null
  53.             || paramTypes != null && args != null && paramTypes.length != args.length) {
  54.             throw new IllegalArgumentException("Parameter types must match the arguments");
  55.         }

  56.         if (paramTypes == null || paramTypes.length == 0) {
  57.             return new InstantiateFactory<>(classToInstantiate);
  58.         }
  59.         return new InstantiateFactory<>(classToInstantiate, paramTypes, args);
  60.     }
  61.     /** The class to create */
  62.     private final Class<T> iClassToInstantiate;
  63.     /** The constructor parameter types */
  64.     private final Class<?>[] iParamTypes;
  65.     /** The constructor arguments */
  66.     private final Object[] iArgs;

  67.     /** The constructor */
  68.     private transient Constructor<T> iConstructor;

  69.     /**
  70.      * Constructor that performs no validation.
  71.      * Use {@code instantiateFactory} if you want that.
  72.      *
  73.      * @param classToInstantiate  the class to instantiate
  74.      */
  75.     public InstantiateFactory(final Class<T> classToInstantiate) {
  76.         iClassToInstantiate = classToInstantiate;
  77.         iParamTypes = null;
  78.         iArgs = null;
  79.         findConstructor();
  80.     }

  81.     /**
  82.      * Constructor that performs no validation.
  83.      * Use {@code instantiateFactory} if you want that.
  84.      *
  85.      * @param classToInstantiate  the class to instantiate
  86.      * @param paramTypes  the constructor parameter types, cloned
  87.      * @param args  the constructor arguments, cloned
  88.      */
  89.     public InstantiateFactory(final Class<T> classToInstantiate, final Class<?>[] paramTypes, final Object[] args) {
  90.         iClassToInstantiate = classToInstantiate;
  91.         iParamTypes = paramTypes.clone();
  92.         iArgs = args.clone();
  93.         findConstructor();
  94.     }

  95.     /**
  96.      * Creates an object using the stored constructor.
  97.      *
  98.      * @return the new object
  99.      */
  100.     @Override
  101.     public T create() {
  102.         // needed for post-serialization
  103.         if (iConstructor == null) {
  104.             findConstructor();
  105.         }

  106.         try {
  107.             return iConstructor.newInstance(iArgs);
  108.         } catch (final InstantiationException ex) {
  109.             throw new FunctorException("InstantiateFactory: InstantiationException", ex);
  110.         } catch (final IllegalAccessException ex) {
  111.             throw new FunctorException("InstantiateFactory: Constructor must be public", ex);
  112.         } catch (final InvocationTargetException ex) {
  113.             throw new FunctorException("InstantiateFactory: Constructor threw an exception", ex);
  114.         }
  115.     }

  116.     /**
  117.      * Find the Constructor for the class specified.
  118.      */
  119.     private void findConstructor() {
  120.         try {
  121.             iConstructor = iClassToInstantiate.getConstructor(iParamTypes);
  122.         } catch (final NoSuchMethodException ex) {
  123.             throw new IllegalArgumentException("InstantiateFactory: The constructor must exist and be public ");
  124.         }
  125.     }

  126. }