View Javadoc
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 }