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.collections.functors;
18
19 import java.io.Serializable;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.InvocationTargetException;
22
23 import org.apache.commons.collections.Factory;
24 import org.apache.commons.collections.FunctorException;
25
26 /**
27 * Factory implementation that creates a new object instance by reflection.
28 *
29 * @since 3.0
30 * @version $Id: InstantiateFactory.java 1437018 2013-01-22 16:08:48Z tn $
31 */
32 public class InstantiateFactory<T> implements Factory<T>, Serializable {
33
34 /** The serial version */
35 private static final long serialVersionUID = -7732226881069447957L;
36
37 /** The class to create */
38 private final Class<T> iClassToInstantiate;
39 /** The constructor parameter types */
40 private final Class<?>[] iParamTypes;
41 /** The constructor arguments */
42 private final Object[] iArgs;
43 /** The constructor */
44 private transient Constructor<T> iConstructor = null;
45
46 /**
47 * Factory method that performs validation.
48 *
49 * @param <T> the type the factory creates
50 * @param classToInstantiate the class to instantiate, not null
51 * @param paramTypes the constructor parameter types, cloned
52 * @param args the constructor arguments, cloned
53 * @return a new instantiate factory
54 */
55 public static <T> Factory<T> instantiateFactory(final Class<T> classToInstantiate,
56 Class<?>[] paramTypes,
57 Object[] args) {
58 if (classToInstantiate == null) {
59 throw new IllegalArgumentException("Class to instantiate must not be null");
60 }
61 if (paramTypes == null && args != null
62 || paramTypes != null && args == null
63 || paramTypes != null && args != null && paramTypes.length != args.length) {
64 throw new IllegalArgumentException("Parameter types must match the arguments");
65 }
66
67 if (paramTypes == null || paramTypes.length == 0) {
68 return new InstantiateFactory<T>(classToInstantiate);
69 }
70 return new InstantiateFactory<T>(classToInstantiate, paramTypes, args);
71 }
72
73 /**
74 * Constructor that performs no validation.
75 * Use <code>getInstance</code> if you want that.
76 *
77 * @param classToInstantiate the class to instantiate
78 */
79 public InstantiateFactory(final Class<T> classToInstantiate) {
80 super();
81 iClassToInstantiate = classToInstantiate;
82 iParamTypes = null;
83 iArgs = null;
84 findConstructor();
85 }
86
87 /**
88 * Constructor that performs no validation.
89 * Use <code>getInstance</code> if you want that.
90 *
91 * @param classToInstantiate the class to instantiate
92 * @param paramTypes the constructor parameter types, cloned
93 * @param args the constructor arguments, cloned
94 */
95 public InstantiateFactory(final Class<T> classToInstantiate, final Class<?>[] paramTypes, final Object[] args) {
96 super();
97 iClassToInstantiate = classToInstantiate;
98 iParamTypes = paramTypes.clone();
99 iArgs = args.clone();
100 findConstructor();
101 }
102
103 /**
104 * Find the Constructor for the class specified.
105 */
106 private void findConstructor() {
107 try {
108 iConstructor = iClassToInstantiate.getConstructor(iParamTypes);
109 } catch (final NoSuchMethodException ex) {
110 throw new IllegalArgumentException("InstantiateFactory: The constructor must exist and be public ");
111 }
112 }
113
114 /**
115 * Creates an object using the stored constructor.
116 *
117 * @return the new object
118 */
119 public T create() {
120 // needed for post-serialization
121 if (iConstructor == null) {
122 findConstructor();
123 }
124
125 try {
126 return iConstructor.newInstance(iArgs);
127 } catch (final InstantiationException ex) {
128 throw new FunctorException("InstantiateFactory: InstantiationException", ex);
129 } catch (final IllegalAccessException ex) {
130 throw new FunctorException("InstantiateFactory: Constructor must be public", ex);
131 } catch (final InvocationTargetException ex) {
132 throw new FunctorException("InstantiateFactory: Constructor threw an exception", ex);
133 }
134 }
135
136 }