SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
ClassFinder.java
1/*
2 * Class: ClassFinder
3 * Description: Convert a simple class name to a fully qualified class object
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.util;
26
27import java.util.ArrayList;
28import java.util.LinkedList;
29import java.util.List;
30
67public class ClassFinder implements Cloneable, java.io.Serializable {
68 private static final long serialVersionUID = -4847630831331065792L;
69
77 private List<List<String>> imports = new LinkedList<List<String>>();
78
82 public ClassFinder() {
83 List<String> imp = new ArrayList<String>();
84 imports.add(imp);
85 }
86
93 public List<String> getImports() {
94 return imports.get(imports.size() - 1);
95 }
96
102 public void saveImports() {
103 List<String> imp = getImports();
104 List<String> impBack = new ArrayList<String>(imp);
105 imports.add(impBack);
106 }
107
113 public void restoreImports() {
114 if (imports.size() == 1)
115 getImports().clear();
116 else
117 imports.remove(imports.size() - 1);
118 }
119
146 public Class<?> findClass(String name) throws ClassNotFoundException, NameConflictException {
147 // Try to consider the name as a fully qualified class name
148 try {
149 return Class.forName(name);
150 } catch (ClassNotFoundException cnfe) {
151 }
152
153 List<String> imports = getImports();
154 Class<?> candidate = null;
155 String candidateImportString = "";
156 boolean candidateImportOnDemand = false;
157
158 // Determines the name of the outermost class
159 // if name corresponds to the simple name of a nested class, e.g., for A.B.C
160 // outerName will contain A.
161 int idxOut = name.indexOf('.');
162 String outerName;
163 if (idxOut == -1)
164 outerName = name;
165 else
166 outerName = name.substring(0, idxOut);
167 for (String importString : imports) {
168 // For each import declaration, we try to load
169 // a class and store the result in cl.
170 // When cl is not null, the Class object is
171 // compared with the best candidate candidate.
172 Class<?> cl = null;
173 boolean onDemand = false;
174 if (!importString.endsWith(".*")) {
175 // Single-type import declaration
176 // We must ensure that this will correspond to
177 // the desired class name. For example, if we
178 // search List and the import java.util.ArrayList
179 // is found in importString, the ArrayList
180 // class must not be returned.
181 if (importString.endsWith("." + outerName)) {
182 // The name of outer class was found in importString and
183 // a period is found left to it.
184 // So try to load this class.
185 // Simple class names have precedence over
186 // on-demand names.
187
188 // Replace, in importString, the name of
189 // the outer class with the true class name
190 // we want to load. If the simple name
191 // does not refer to a nested class, this
192 // has no effect.
193 String cn = importString.substring(0, importString.length() - outerName.length()) + name;
194 try {
195 cl = Class.forName(cn);
196 } catch (ClassNotFoundException cnfe) {
197 }
198 }
199 } else {
200 // Type import on demand declaration
201 try {
202 // Replace the * with name and
203 // try to load the class.
204 // If that succeeds, our candidate cl
205 // is onDemand.
206 cl = Class.forName(importString.substring(0, importString.length() - 1) + name);
207 onDemand = true;
208 } catch (ClassNotFoundException cnfe) {
209 }
210 }
211 if (cl != null) {
212 // Something was loaded
213 if (candidate == null || (candidateImportOnDemand && !onDemand)) {
214 // We had no candidate or the candidate was imported
215 // on-demand while this one is a single-type import.
216 candidate = cl;
217 candidateImportString = importString;
218 candidateImportOnDemand = onDemand;
219 } else if (candidate != cl)
220 throw new NameConflictException(this, name,
221 "simple class name " + name + " matches " + candidate.getName() + " (import string "
222 + candidateImportString + ") or " + cl.getName() + " (import string " + importString + ")");
223 }
224 }
225 if (candidate == null)
226 throw new ClassNotFoundException("Cannot find the class with name " + name);
227 return candidate;
228 }
229
245 public String getSimpleName(Class<?> cls) {
246 if (cls.isArray())
247 return getSimpleName(cls.getComponentType()) + "[]";
248 if (cls.isPrimitive())
249 return cls.getName();
250 Class<?> outer = cls;
251 while (outer.getDeclaringClass() != null)
252 outer = outer.getDeclaringClass();
253 boolean needsFullyQualified = true;
254 for (String importString : getImports()) {
255 if (importString.equals(outer.getName()))
256 // A single-type import is given, can return an unqualified name.
257 needsFullyQualified = false;
258 else if (importString.endsWith(".*")) {
259 // Remove the .* at the end of the import string to get a package name.
260 String pack = importString.substring(0, importString.length() - 2);
261 // Compare this package name.
262 if (pack.equals(cls.getPackage().getName()))
263 needsFullyQualified = false;
264 }
265 }
266 if (needsFullyQualified)
267 return cls.getName();
268 else {
269 String name = cls.getName();
270 String pack = cls.getPackage().getName();
271 if (!name.startsWith(pack))
272 throw new IllegalStateException("The class name " + name + " does not contain the package name " + pack);
273
274 // Removes the package and the . from the fully qualified class name.
275 return name.substring(pack.length() + 1);
276 }
277 }
278
283 ClassFinder cf;
284 try {
285 cf = (ClassFinder) super.clone();
286 } catch (CloneNotSupportedException cne) {
287 throw new InternalError("CloneNotSupported thrown for a class implementing Cloneable");
288 }
289 cf.imports = new LinkedList<List<String>>();
290 for (List<String> imp : imports) {
291 List<String> impCpy = new ArrayList<String>(imp);
292 cf.imports.add(impCpy);
293 }
294 return cf;
295 }
296}
List< String > getImports()
Returns the current list of import declarations.
Class<?> findClass(String name)
Tries to find the class corresponding to the simple name name.
ClassFinder clone()
Clones this class finder, and copies its lists of import declarations.
void saveImports()
Saves the current import list on the import stack.
String getSimpleName(Class<?> cls)
Returns the simple name of the class cls that can be used when the imports contained in this class fi...
void restoreImports()
Restores the list of import declarations.
ClassFinder()
Constructs a new class finder with an empty list of import declarations.
This exception is thrown by a ClassFinder when two or more fully qualified class names can be associa...
This subpackage provides tools for exporting data to text and binary files, as well as for importing ...