1 //******************************************************************************
2 //
3 // File: Instance.java
4 // Package: edu.rit.util
5 // Unit: Class edu.rit.util.Instance
6 //
7 // This Java source file is copyright (C) 2010 by Alan Kaminsky. All rights
8 // reserved. For further information, contact the author, Alan Kaminsky, at
9 // ark@cs.rit.edu.
10 //
11 // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12 // software; you can redistribute it and/or modify it under the terms of the GNU
13 // General Public License as published by the Free Software Foundation; either
14 // version 3 of the License, or (at your option) any later version.
15 //
16 // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18 // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 //
20 // Linking this library statically or dynamically with other modules is making a
21 // combined work based on this library. Thus, the terms and conditions of the GNU
22 // General Public License cover the whole combination.
23 //
24 // As a special exception, the copyright holders of this library give you
25 // permission to link this library with independent modules to produce an
26 // executable, regardless of the license terms of these independent modules, and
27 // to copy and distribute the resulting executable under terms of your choice,
28 // provided that you also meet, for each linked independent module, the terms
29 // and conditions of the license of that module. An independent module is a module
30 // which is not derived from or based on this library. If you modify this library,
31 // you may extend this exception to your version of the library, but you are not
32 // obligated to do so. If you do not wish to do so, delete this exception
33 // statement from your version.
34 //
35 // A copy of the GNU General Public License is provided in the file gpl.txt. You
36 // may also obtain a copy of the GNU General Public License on the World Wide
37 // Web at http://www.gnu.org/licenses/gpl.html.
38 //
39 //******************************************************************************
40 package edu.rit.util;
41
42 import java.lang.reflect.Constructor;
43 import java.lang.reflect.InvocationTargetException;
44
45 /**
46 * Class Instance provides static methods for creating instances of classes.
47 *
48 * @author Alan Kaminsky
49 * @version 09-Oct-2010
50 */
51 public class Instance {
52
53 // Prevent construction.
54 private Instance() {
55 }
56
57 // Exported operations.
58 /**
59 * Create a new instance of a class as specified by the given string. The
60 * string must consist of a fully-qualified class name, a left parenthesis,
61 * zero or more comma-separated arguments, and a right parenthesis. No
62 * whitespace is allowed. This method attempts to find a constructor for the
63 * given class as follows, where <I>N</I> is the number of arguments:
64 * <UL>
65 * <LI>
66 * If <I>N</I> = 0, use a no-argument constructor.
67 * <LI>
68 * Else if all arguments are integers, use a constructor with <I>N</I>
69 * arguments of type <code>int</code>.
70 * <LI>
71 * Else if all arguments are integers and there is no such constructor, use
72 * a constructor with one argument of type <code>int[]</code>.
73 * <LI>
74 * Else if not all arguments are integers, use a constructor with <I>N</I>
75 * arguments of type <code>String</code>.
76 * <LI>
77 * Else if not all arguments are integers and there is no such constructor,
78 * use a constructor with one argument of type <code>String[]</code>.
79 * <LI>
80 * Else throw a NoSuchMethodException.
81 * </UL>
82 * This method invokes the chosen constructor, passing in the given argument
83 * values, and returns a reference to the newly-created instance.
84 * <I>Note:</I> To find the given class, the calling thread's context class
85 * loader is used.
86 *
87 * @param s Constructor expression string.
88 * @return New instance.
89 * @exception IllegalArgumentException (unchecked exception) Thrown if
90 * <code>s</code> does not obey the required syntax.
91 * @exception ClassNotFoundException Thrown if the given class cannot be
92 * found.
93 * @exception NoSuchMethodException Thrown if a suitable constructor cannot
94 * be found in the given class.
95 * @exception InstantiationException Thrown if an instance cannot be created
96 * because the given class is an interface or an abstract class.
97 * @exception IllegalAccessException Thrown if an instance cannot be created
98 * because the calling method does not have access to the given constructor.
99 * @exception InvocationTargetException Thrown if the given constructor
100 * throws an exception.
101 * @throws java.lang.ClassNotFoundException if any.
102 * @throws java.lang.NoSuchMethodException if any.
103 * @throws java.lang.InstantiationException if any.
104 * @throws java.lang.IllegalAccessException if any.
105 * @throws java.lang.reflect.InvocationTargetException if any.
106 */
107 public static Object newInstance(String s)
108 throws
109 ClassNotFoundException,
110 NoSuchMethodException,
111 InstantiationException,
112 IllegalAccessException,
113 InvocationTargetException {
114 int i, j;
115
116 // Parse class name.
117 i = 0;
118 j = s.indexOf('(', i);
119 if (j == -1) {
120 throw new IllegalArgumentException("Instance.newInstance(\"" + s + "\"): Missing '('");
121 }
122 if (i == j) {
123 throw new IllegalArgumentException("Instance.newInstance(\"" + s + "\"): Missing class name");
124 }
125 String classname = s.substring(i, j);
126
127 // Parse arguments.
128 i = j + 1;
129 j = s.indexOf(')', i);
130 if (j == -1) {
131 throw new IllegalArgumentException("Instance.newInstance(\"" + s + "\"): Missing ')'");
132 }
133 if (j != s.length() - 1) {
134 throw new IllegalArgumentException("Instance.newInstance(\"" + s
135 + "\"): Extraneous characters after ')'");
136 }
137 String arguments = s.substring(i, j);
138
139 // Parse individual arguments.
140 String[] args;
141 if (i == j) {
142 args = new String[0];
143 } else {
144 args = arguments.split(",", -1);
145 }
146 Integer[] intargs = new Integer[args.length];
147 boolean allAreInts = true;
148 for (i = 0; i < args.length; ++i) {
149 try {
150 intargs[i] = Integer.valueOf(args[i]);
151 } catch (NumberFormatException exc) {
152 allAreInts = false;
153 }
154 }
155
156 // Get class.
157 Class<?> theClass = Class.forName(classname,
158 true,
159 Thread.currentThread().getContextClassLoader());
160
161 // Get constructor and create instance.
162 Constructor<?> ctor;
163 Class<?>[] argtypes;
164
165 // No-argument constructor.
166 if (args.length == 0) {
167 try {
168 ctor = theClass.getConstructor();
169 return ctor.newInstance();
170 } catch (NoSuchMethodException ignored) {
171 }
172 }
173
174 // Constructor(int,int,...,int).
175 if (allAreInts) {
176 try {
177 argtypes = new Class<?>[args.length];
178 for (i = 0; i < args.length; ++i) {
179 argtypes[i] = Integer.TYPE;
180 }
181 ctor = theClass.getConstructor(argtypes);
182 return ctor.newInstance((Object[]) intargs);
183 } catch (NoSuchMethodException ignored) {
184 }
185 }
186
187 // Constructor(int[]).
188 if (allAreInts) {
189 try {
190 ctor = theClass.getConstructor(int[].class);
191 return ctor.newInstance((Object) intargs);
192 } catch (NoSuchMethodException ignored) {
193 }
194 }
195
196 // Constructor(String,String,...,String).
197 try {
198 argtypes = new Class<?>[args.length];
199 for (i = 0; i < args.length; ++i) {
200 argtypes[i] = String.class;
201 }
202 ctor = theClass.getConstructor(argtypes);
203 return ctor.newInstance((Object[]) args);
204 } catch (NoSuchMethodException ignored) {
205 }
206
207 // Constructor(String[]).
208 try {
209 ctor = theClass.getConstructor(String[].class);
210 return ctor.newInstance((Object) args);
211 } catch (NoSuchMethodException ignored) {
212 }
213
214 // Could not find suitable constructor.
215 throw new NoSuchMethodException("Instance.newInstance(\"" + s
216 + "\"): Cannot find suitable constructor");
217 }
218
219 // Unit test main program.
220 // /**
221 // * Unit test main program.
222 // */
223 // public static void main
224 // (String[] args)
225 // throws Exception
226 // {
227 // System.out.println (Instance.newInstance (args[0]));
228 // }
229 }