001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.lang;
018:
019: import java.lang.reflect.Method;
020: import java.lang.reflect.Modifier;
021:
022: import java.util.ArrayList;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027:
028: /**
029: * <p>Operates on classes without using reflection.</p>
030: *
031: * <p>This class handles invalid <code>null</code> inputs as best it can.
032: * Each method documents its behaviour in more detail.</p>
033: *
034: * @author Stephen Colebourne
035: * @author Gary Gregory
036: * @author Norm Deane
037: * @author Alban Peignier
038: * @since 2.0
039: * @version $Id: ClassUtils.java 437554 2006-08-28 06:21:41Z bayard $
040: */
041: public class ClassUtils {
042:
043: /**
044: * <p>The package separator character: <code>'.' == {@value}</code>.</p>
045: */
046: public static final char PACKAGE_SEPARATOR_CHAR = '.';
047:
048: /**
049: * <p>The package separator String: <code>"."</code>.</p>
050: */
051: public static final String PACKAGE_SEPARATOR = String
052: .valueOf(PACKAGE_SEPARATOR_CHAR);
053:
054: /**
055: * <p>The inner class separator character: <code>'$' == {@value}</code>.</p>
056: */
057: public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
058:
059: /**
060: * <p>The inner class separator String: <code>"$"</code>.</p>
061: */
062: public static final String INNER_CLASS_SEPARATOR = String
063: .valueOf(INNER_CLASS_SEPARATOR_CHAR);
064:
065: /**
066: * Maps primitive <code>Class</code>es to their corresponding wrapper <code>Class</code>.
067: */
068: private static Map primitiveWrapperMap = new HashMap();
069: static {
070: primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
071: primitiveWrapperMap.put(Byte.TYPE, Byte.class);
072: primitiveWrapperMap.put(Character.TYPE, Character.class);
073: primitiveWrapperMap.put(Short.TYPE, Short.class);
074: primitiveWrapperMap.put(Integer.TYPE, Integer.class);
075: primitiveWrapperMap.put(Long.TYPE, Long.class);
076: primitiveWrapperMap.put(Double.TYPE, Double.class);
077: primitiveWrapperMap.put(Float.TYPE, Float.class);
078: primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
079: }
080:
081: /**
082: * Maps a primitive class name to its corresponding abbreviation used in array class names.
083: */
084: private static Map abbreviationMap = new HashMap();
085: static {
086: abbreviationMap.put("int", "I");
087: abbreviationMap.put("boolean", "Z");
088: abbreviationMap.put("float", "F");
089: abbreviationMap.put("long", "J");
090: abbreviationMap.put("short", "S");
091: abbreviationMap.put("byte", "B");
092: abbreviationMap.put("double", "D");
093: abbreviationMap.put("char", "C");
094: }
095:
096: /**
097: * <p>ClassUtils instances should NOT be constructed in standard programming.
098: * Instead, the class should be used as
099: * <code>ClassUtils.getShortClassName(cls)</code>.</p>
100: *
101: * <p>This constructor is public to permit tools that require a JavaBean
102: * instance to operate.</p>
103: */
104: public ClassUtils() {
105: super ();
106: }
107:
108: // Short class name
109: // ----------------------------------------------------------------------
110: /**
111: * <p>Gets the class name minus the package name for an <code>Object</code>.</p>
112: *
113: * @param object the class to get the short name for, may be null
114: * @param valueIfNull the value to return if null
115: * @return the class name of the object without the package name, or the null value
116: */
117: public static String getShortClassName(Object object,
118: String valueIfNull) {
119: if (object == null) {
120: return valueIfNull;
121: }
122: return getShortClassName(object.getClass().getName());
123: }
124:
125: /**
126: * <p>Gets the class name minus the package name from a <code>Class</code>.</p>
127: *
128: * @param cls the class to get the short name for.
129: * @return the class name without the package name or an empty string
130: */
131: public static String getShortClassName(Class cls) {
132: if (cls == null) {
133: return StringUtils.EMPTY;
134: }
135: return getShortClassName(cls.getName());
136: }
137:
138: /**
139: * <p>Gets the class name minus the package name from a String.</p>
140: *
141: * <p>The string passed in is assumed to be a class name - it is not checked.</p>
142: *
143: * @param className the className to get the short name for
144: * @return the class name of the class without the package name or an empty string
145: */
146: public static String getShortClassName(String className) {
147: if (className == null) {
148: return StringUtils.EMPTY;
149: }
150: if (className.length() == 0) {
151: return StringUtils.EMPTY;
152: }
153: char[] chars = className.toCharArray();
154: int lastDot = 0;
155: for (int i = 0; i < chars.length; i++) {
156: if (chars[i] == PACKAGE_SEPARATOR_CHAR) {
157: lastDot = i + 1;
158: } else if (chars[i] == INNER_CLASS_SEPARATOR_CHAR) { // handle inner classes
159: chars[i] = PACKAGE_SEPARATOR_CHAR;
160: }
161: }
162: return new String(chars, lastDot, chars.length - lastDot);
163: }
164:
165: // Package name
166: // ----------------------------------------------------------------------
167: /**
168: * <p>Gets the package name of an <code>Object</code>.</p>
169: *
170: * @param object the class to get the package name for, may be null
171: * @param valueIfNull the value to return if null
172: * @return the package name of the object, or the null value
173: */
174: public static String getPackageName(Object object,
175: String valueIfNull) {
176: if (object == null) {
177: return valueIfNull;
178: }
179: return getPackageName(object.getClass().getName());
180: }
181:
182: /**
183: * <p>Gets the package name of a <code>Class</code>.</p>
184: *
185: * @param cls the class to get the package name for, may be <code>null</code>.
186: * @return the package name or an empty string
187: */
188: public static String getPackageName(Class cls) {
189: if (cls == null) {
190: return StringUtils.EMPTY;
191: }
192: return getPackageName(cls.getName());
193: }
194:
195: /**
196: * <p>Gets the package name from a <code>String</code>.</p>
197: *
198: * <p>The string passed in is assumed to be a class name - it is not checked.</p>
199: * <p>If the class is unpackaged, return an empty string.</p>
200: *
201: * @param className the className to get the package name for, may be <code>null</code>
202: * @return the package name or an empty string
203: */
204: public static String getPackageName(String className) {
205: if (className == null) {
206: return StringUtils.EMPTY;
207: }
208: int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
209: if (i == -1) {
210: return StringUtils.EMPTY;
211: }
212: return className.substring(0, i);
213: }
214:
215: // Superclasses/Superinterfaces
216: // ----------------------------------------------------------------------
217: /**
218: * <p>Gets a <code>List</code> of superclasses for the given class.</p>
219: *
220: * @param cls the class to look up, may be <code>null</code>
221: * @return the <code>List</code> of superclasses in order going up from this one
222: * <code>null</code> if null input
223: */
224: public static List getAllSuperclasses(Class cls) {
225: if (cls == null) {
226: return null;
227: }
228: List classes = new ArrayList();
229: Class super class = cls.getSuperclass();
230: while (super class != null) {
231: classes.add(super class);
232: super class = super class.getSuperclass();
233: }
234: return classes;
235: }
236:
237: /**
238: * <p>Gets a <code>List</code> of all interfaces implemented by the given
239: * class and its superclasses.</p>
240: *
241: * <p>The order is determined by looking through each interface in turn as
242: * declared in the source file and following its hierarchy up. Then each
243: * superclass is considered in the same way. Later duplicates are ignored,
244: * so the order is maintained.</p>
245: *
246: * @param cls the class to look up, may be <code>null</code>
247: * @return the <code>List</code> of interfaces in order,
248: * <code>null</code> if null input
249: */
250: public static List getAllInterfaces(Class cls) {
251: if (cls == null) {
252: return null;
253: }
254: List list = new ArrayList();
255: while (cls != null) {
256: Class[] interfaces = cls.getInterfaces();
257: for (int i = 0; i < interfaces.length; i++) {
258: if (list.contains(interfaces[i]) == false) {
259: list.add(interfaces[i]);
260: }
261: List super Interfaces = getAllInterfaces(interfaces[i]);
262: for (Iterator it = super Interfaces.iterator(); it
263: .hasNext();) {
264: Class intface = (Class) it.next();
265: if (list.contains(intface) == false) {
266: list.add(intface);
267: }
268: }
269: }
270: cls = cls.getSuperclass();
271: }
272: return list;
273: }
274:
275: // Convert list
276: // ----------------------------------------------------------------------
277: /**
278: * <p>Given a <code>List</code> of class names, this method converts them into classes.</p>
279: *
280: * <p>A new <code>List</code> is returned. If the class name cannot be found, <code>null</code>
281: * is stored in the <code>List</code>. If the class name in the <code>List</code> is
282: * <code>null</code>, <code>null</code> is stored in the output <code>List</code>.</p>
283: *
284: * @param classNames the classNames to change
285: * @return a <code>List</code> of Class objects corresponding to the class names,
286: * <code>null</code> if null input
287: * @throws ClassCastException if classNames contains a non String entry
288: */
289: public static List convertClassNamesToClasses(List classNames) {
290: if (classNames == null) {
291: return null;
292: }
293: List classes = new ArrayList(classNames.size());
294: for (Iterator it = classNames.iterator(); it.hasNext();) {
295: String className = (String) it.next();
296: try {
297: classes.add(Class.forName(className));
298: } catch (Exception ex) {
299: classes.add(null);
300: }
301: }
302: return classes;
303: }
304:
305: /**
306: * <p>Given a <code>List</code> of <code>Class</code> objects, this method converts
307: * them into class names.</p>
308: *
309: * <p>A new <code>List</code> is returned. <code>null</code> objects will be copied into
310: * the returned list as <code>null</code>.</p>
311: *
312: * @param classes the classes to change
313: * @return a <code>List</code> of class names corresponding to the Class objects,
314: * <code>null</code> if null input
315: * @throws ClassCastException if <code>classes</code> contains a non-<code>Class</code> entry
316: */
317: public static List convertClassesToClassNames(List classes) {
318: if (classes == null) {
319: return null;
320: }
321: List classNames = new ArrayList(classes.size());
322: for (Iterator it = classes.iterator(); it.hasNext();) {
323: Class cls = (Class) it.next();
324: if (cls == null) {
325: classNames.add(null);
326: } else {
327: classNames.add(cls.getName());
328: }
329: }
330: return classNames;
331: }
332:
333: // Is assignable
334: // ----------------------------------------------------------------------
335: /**
336: * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
337: *
338: * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
339: * Class pair in the input arrays. It can be used to check if a set of arguments
340: * (the first parameter) are suitably compatible with a set of method parameter types
341: * (the second parameter).</p>
342: *
343: * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
344: * method takes into account widenings of primitive classes and
345: * <code>null</code>s.</p>
346: *
347: * <p>Primitive widenings allow an int to be assigned to a <code>long</code>,
348: * <code>float</code> or <code>double</code>. This method returns the correct
349: * result for these cases.</p>
350: *
351: * <p><code>Null</code> may be assigned to any reference type. This method will
352: * return <code>true</code> if <code>null</code> is passed in and the toClass is
353: * non-primitive.</p>
354: *
355: * <p>Specifically, this method tests whether the type represented by the
356: * specified <code>Class</code> parameter can be converted to the type
357: * represented by this <code>Class</code> object via an identity conversion
358: * widening primitive or widening reference conversion. See
359: * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
360: * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
361: *
362: * @param classArray the array of Classes to check, may be <code>null</code>
363: * @param toClassArray the array of Classes to try to assign into, may be <code>null</code>
364: * @return <code>true</code> if assignment possible
365: */
366: public static boolean isAssignable(Class[] classArray,
367: Class[] toClassArray) {
368: if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
369: return false;
370: }
371: if (classArray == null) {
372: classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
373: }
374: if (toClassArray == null) {
375: toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
376: }
377: for (int i = 0; i < classArray.length; i++) {
378: if (isAssignable(classArray[i], toClassArray[i]) == false) {
379: return false;
380: }
381: }
382: return true;
383: }
384:
385: /**
386: * <p>Checks if one <code>Class</code> can be assigned to a variable of
387: * another <code>Class</code>.</p>
388: *
389: * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
390: * this method takes into account widenings of primitive classes and
391: * <code>null</code>s.</p>
392: *
393: * <p>Primitive widenings allow an int to be assigned to a long, float or
394: * double. This method returns the correct result for these cases.</p>
395: *
396: * <p><code>Null</code> may be assigned to any reference type. This method
397: * will return <code>true</code> if <code>null</code> is passed in and the
398: * toClass is non-primitive.</p>
399: *
400: * <p>Specifically, this method tests whether the type represented by the
401: * specified <code>Class</code> parameter can be converted to the type
402: * represented by this <code>Class</code> object via an identity conversion
403: * widening primitive or widening reference conversion. See
404: * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
405: * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
406: *
407: * @param cls the Class to check, may be null
408: * @param toClass the Class to try to assign into, returns false if null
409: * @return <code>true</code> if assignment possible
410: */
411: public static boolean isAssignable(Class cls, Class toClass) {
412: if (toClass == null) {
413: return false;
414: }
415: // have to check for null, as isAssignableFrom doesn't
416: if (cls == null) {
417: return !(toClass.isPrimitive());
418: }
419: if (cls.equals(toClass)) {
420: return true;
421: }
422: if (cls.isPrimitive()) {
423: if (toClass.isPrimitive() == false) {
424: return false;
425: }
426: if (Integer.TYPE.equals(cls)) {
427: return Long.TYPE.equals(toClass)
428: || Float.TYPE.equals(toClass)
429: || Double.TYPE.equals(toClass);
430: }
431: if (Long.TYPE.equals(cls)) {
432: return Float.TYPE.equals(toClass)
433: || Double.TYPE.equals(toClass);
434: }
435: if (Boolean.TYPE.equals(cls)) {
436: return false;
437: }
438: if (Double.TYPE.equals(cls)) {
439: return false;
440: }
441: if (Float.TYPE.equals(cls)) {
442: return Double.TYPE.equals(toClass);
443: }
444: if (Character.TYPE.equals(cls)) {
445: return Integer.TYPE.equals(toClass)
446: || Long.TYPE.equals(toClass)
447: || Float.TYPE.equals(toClass)
448: || Double.TYPE.equals(toClass);
449: }
450: if (Short.TYPE.equals(cls)) {
451: return Integer.TYPE.equals(toClass)
452: || Long.TYPE.equals(toClass)
453: || Float.TYPE.equals(toClass)
454: || Double.TYPE.equals(toClass);
455: }
456: if (Byte.TYPE.equals(cls)) {
457: return Short.TYPE.equals(toClass)
458: || Integer.TYPE.equals(toClass)
459: || Long.TYPE.equals(toClass)
460: || Float.TYPE.equals(toClass)
461: || Double.TYPE.equals(toClass);
462: }
463: // should never get here
464: return false;
465: }
466: return toClass.isAssignableFrom(cls);
467: }
468:
469: /**
470: * <p>Converts the specified primitive Class object to its corresponding
471: * wrapper Class object.</p>
472: *
473: * <p>NOTE: From v2.2, this method handles <code>Void.TYPE</code>,
474: * returning <code>Void.TYPE</code>.</p>
475: *
476: * @param cls the class to convert, may be null
477: * @return the wrapper class for <code>cls</code> or <code>cls</code> if
478: * <code>cls</code> is not a primitive. <code>null</code> if null input.
479: * @since 2.1
480: */
481: public static Class primitiveToWrapper(Class cls) {
482: Class convertedClass = cls;
483: if (cls != null && cls.isPrimitive()) {
484: convertedClass = (Class) primitiveWrapperMap.get(cls);
485: }
486: return convertedClass;
487: }
488:
489: /**
490: * <p>Converts the specified array of primitive Class objects to an array of
491: * its corresponding wrapper Class objects.</p>
492: *
493: * @param classes the class array to convert, may be null or empty
494: * @return an array which contains for each given class, the wrapper class or
495: * the original class if class is not a primitive. <code>null</code> if null input.
496: * Empty array if an empty array passed in.
497: * @since 2.1
498: */
499: public static Class[] primitivesToWrappers(Class[] classes) {
500: if (classes == null) {
501: return null;
502: }
503:
504: if (classes.length == 0) {
505: return classes;
506: }
507:
508: Class[] convertedClasses = new Class[classes.length];
509: for (int i = 0; i < classes.length; i++) {
510: convertedClasses[i] = primitiveToWrapper(classes[i]);
511: }
512: return convertedClasses;
513: }
514:
515: // Inner class
516: // ----------------------------------------------------------------------
517: /**
518: * <p>Is the specified class an inner class or static nested class.</p>
519: *
520: * @param cls the class to check, may be null
521: * @return <code>true</code> if the class is an inner or static nested class,
522: * false if not or <code>null</code>
523: */
524: public static boolean isInnerClass(Class cls) {
525: if (cls == null) {
526: return false;
527: }
528: return cls.getName().indexOf(INNER_CLASS_SEPARATOR_CHAR) >= 0;
529: }
530:
531: // Class loading
532: // ----------------------------------------------------------------------
533: /**
534: * Returns the class represented by <code>className</code> using the
535: * <code>classLoader</code>. This implementation supports names like
536: * "<code>java.lang.String[]</code>" as well as "<code>[Ljava.lang.String;</code>".
537: *
538: * @param classLoader the class loader to use to load the class
539: * @param className the class name
540: * @param initialize whether the class must be initialized
541: * @return the class represented by <code>className</code> using the <code>classLoader</code>
542: * @throws ClassNotFoundException if the class is not found
543: */
544: public static Class getClass(ClassLoader classLoader,
545: String className, boolean initialize)
546: throws ClassNotFoundException {
547: Class clazz;
548: if (abbreviationMap.containsKey(className)) {
549: String clsName = "[" + abbreviationMap.get(className);
550: clazz = Class.forName(clsName, initialize, classLoader)
551: .getComponentType();
552: } else {
553: clazz = Class.forName(toProperClassName(className),
554: initialize, classLoader);
555: }
556: return clazz;
557: }
558:
559: /**
560: * Returns the (initialized) class represented by <code>className</code>
561: * using the <code>classLoader</code>. This implementation supports names
562: * like "<code>java.lang.String[]</code>" as well as
563: * "<code>[Ljava.lang.String;</code>".
564: *
565: * @param classLoader the class loader to use to load the class
566: * @param className the class name
567: * @return the class represented by <code>className</code> using the <code>classLoader</code>
568: * @throws ClassNotFoundException if the class is not found
569: */
570: public static Class getClass(ClassLoader classLoader,
571: String className) throws ClassNotFoundException {
572: return getClass(classLoader, className, true);
573: }
574:
575: /**
576: * Returns the (initialized )class represented by <code>className</code>
577: * using the current thread's context class loader. This implementation
578: * supports names like "<code>java.lang.String[]</code>" as well as
579: * "<code>[Ljava.lang.String;</code>".
580: *
581: * @param className the class name
582: * @return the class represented by <code>className</code> using the current thread's context class loader
583: * @throws ClassNotFoundException if the class is not found
584: */
585: public static Class getClass(String className)
586: throws ClassNotFoundException {
587: return getClass(className, true);
588: }
589:
590: /**
591: * Returns the class represented by <code>className</code> using the
592: * current thread's context class loader. This implementation supports
593: * names like "<code>java.lang.String[]</code>" as well as
594: * "<code>[Ljava.lang.String;</code>".
595: *
596: * @param className the class name
597: * @param initialize whether the class must be initialized
598: * @return the class represented by <code>className</code> using the current thread's context class loader
599: * @throws ClassNotFoundException if the class is not found
600: */
601: public static Class getClass(String className, boolean initialize)
602: throws ClassNotFoundException {
603: ClassLoader contextCL = Thread.currentThread()
604: .getContextClassLoader();
605: ClassLoader loader = contextCL == null ? ClassUtils.class
606: .getClassLoader() : contextCL;
607: return getClass(loader, className, initialize);
608: }
609:
610: // Public method
611: // ----------------------------------------------------------------------
612: /**
613: * <p>Returns the desired Method much like <code>Class.getMethod</code>, however
614: * it ensures that the returned Method is from a public class or interface and not
615: * from an anonymous inner class. This means that the Method is invokable and
616: * doesn't fall foul of Java bug
617: * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).
618: *
619: * <code><pre>Set set = Collections.unmodifiableSet(...);
620: * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
621: * Object result = method.invoke(set, new Object[]);</pre></code>
622: * </p>
623: *
624: * @param cls the class to check, not null
625: * @param methodName the name of the method
626: * @param parameterTypes the list of parameters
627: * @return the method
628: * @throws NullPointerException if the class is null
629: * @throws SecurityException if a a security violation occured
630: * @throws NoSuchMethodException if the method is not found in the given class
631: * or if the metothod doen't conform with the requirements
632: */
633: public static Method getPublicMethod(Class cls, String methodName,
634: Class parameterTypes[]) throws SecurityException,
635: NoSuchMethodException {
636:
637: Method declaredMethod = cls.getMethod(methodName,
638: parameterTypes);
639: if (Modifier.isPublic(declaredMethod.getDeclaringClass()
640: .getModifiers())) {
641: return declaredMethod;
642: }
643:
644: List candidateClasses = new ArrayList();
645: candidateClasses.addAll(getAllInterfaces(cls));
646: candidateClasses.addAll(getAllSuperclasses(cls));
647:
648: for (Iterator it = candidateClasses.iterator(); it.hasNext();) {
649: Class candidateClass = (Class) it.next();
650: if (!Modifier.isPublic(candidateClass.getModifiers())) {
651: continue;
652: }
653: Method candidateMethod;
654: try {
655: candidateMethod = candidateClass.getMethod(methodName,
656: parameterTypes);
657: } catch (NoSuchMethodException ex) {
658: continue;
659: }
660: if (Modifier.isPublic(candidateMethod.getDeclaringClass()
661: .getModifiers())) {
662: return candidateMethod;
663: }
664: }
665:
666: throw new NoSuchMethodException(
667: "Can't find a public method for " + methodName + " "
668: + ArrayUtils.toString(parameterTypes));
669: }
670:
671: // ----------------------------------------------------------------------
672: /**
673: * Converts a class name to a JLS style class name.
674: *
675: * @param className the class name
676: * @return the converted name
677: */
678: private static String toProperClassName(String className) {
679: className = StringUtils.deleteWhitespace(className);
680: if (className == null) {
681: throw new NullArgumentException("className");
682: } else if (className.endsWith("[]")) {
683: StringBuffer classNameBuffer = new StringBuffer();
684: while (className.endsWith("[]")) {
685: className = className.substring(0,
686: className.length() - 2);
687: classNameBuffer.append("[");
688: }
689: String abbreviation = (String) abbreviationMap
690: .get(className);
691: if (abbreviation != null) {
692: classNameBuffer.append(abbreviation);
693: } else {
694: classNameBuffer.append("L").append(className).append(
695: ";");
696: }
697: className = classNameBuffer.toString();
698: }
699: return className;
700: }
701:
702: }
|