001: package tide.classsyntax;
002:
003: import tide.utils.SyntaxUtils;
004: import tide.editor.MainEditorFrame;
005: import java.io.*;
006: import java.lang.reflect.*;
007: import java.util.*;
008: import java.net.URL;
009: import java.security.CodeSource;
010:
011: public final class ClassUtils {
012: private ClassUtils() {
013: }
014:
015: public static String getClassName(File base, File clas) {
016: String name = clas.getAbsolutePath();
017: String baseName = base.getAbsolutePath();
018: return getClassName(baseName, name);
019: }
020:
021: public static String getClassName(String base, String fileName) {
022: String name = fileName;
023: name = name.substring(base.length()); // remove base
024: if (name.startsWith("/") || name.startsWith("\\")) {
025: name = name.substring(1);
026: }
027: name = name.substring(0, name.length() - 6); // remove .class
028: name = name.replace('\\', '.');
029: name = name.replace('/', '.');
030: //name = name.replace('$','.');
031: return name;
032: }
033:
034: /** @return the package name of the class. Also works for inner classes.
035: */
036: public static String getPackageName(Class c) {
037: if (c.getPackage() != null)
038: return c.getPackage().getName();
039: // Tricky, some? inner classes have NO package.
040: String n = c.getName(); // test.A$CCC
041: // Alternatice: one could also look in the declaring class.
042: int posPt = n.lastIndexOf('.');
043: if (posPt < 0)
044: return "";
045: return n.substring(0, posPt); // "test"
046: }
047:
048: public static String toStringConstructor(Constructor cons) {
049: StringBuilder sb = new StringBuilder();
050: String cs = cons.toString();
051: int posP = cs.indexOf('(');
052: if (posP >= 0) {
053: cs = cs.substring(posP + 1).trim();
054: }
055: posP = cs.indexOf(')');
056: if (posP >= 0) {
057: cs = cs.substring(0, posP);
058: }
059:
060: if (cs.length() == 0)
061: return "none";
062: sb.append(cs);
063: return sb.toString();
064: }
065:
066: public static String toStringConstructorArgs(Constructor cons,
067: TypeParametersMapper mapper) {
068: StringBuilder sb = new StringBuilder();
069: sb.append(ClassUtils.toStringParameters(cons
070: .getParameterTypes(), mapper, cons.isVarArgs()));
071: return sb.toString();
072: }
073:
074: /** @return { int, E } {Object, int}, ...
075: somehow complex...
076: if the type string doesn't contain the arg string
077: TODO
078: */
079: public static String toStringParameters(final Class[] args,
080: final Type[] types, final TypeParametersMapper mapper) {
081: StringBuilder sb = new StringBuilder();
082: for (int i = 0; i < args.length; i++) {
083: String name = args[i].getSimpleName();
084: if (types != null) {
085: name = formatTypeSimpleName(types[i], args[i]); // TODO...
086: }
087: sb.append(name);
088: /*
089: String argName = args[i].getName(); // java.lang.Object or
090: String typeName = "";
091: if( types!=null) typeName = ""+types[i];
092: else typeName = argName; // E or "class java.lang.Object"
093:
094: if(typeName.indexOf(argName)>=0)
095: {
096: // use short
097: sb.append(args[i].getSimpleName());
098: }
099: else
100: {
101: sb.append(typeName);
102: } */
103:
104: if (i < args.length - 1) {
105: sb.append(", ");
106: }
107: }
108: return sb.toString();
109: }
110:
111: public static String toStringExceptions(Class[] args) {
112: return toStringParameters(args, null, null);
113: }
114:
115: /** @return "< K,V>" for the Hashtable class, "" for string
116: */
117: public static String toStringGenericTypeDeclaration(Class c) {
118: if (c.getTypeParameters().length == 0)
119: return "";
120:
121: StringBuilder tp = new StringBuilder("<");
122: int n = c.getTypeParameters().length;
123: for (int i = 0; i < n; i++) {
124: tp.append("" + c.getTypeParameters()[i]);
125: if (i < n - 1)
126: tp.append(", ");
127: }
128: tp.append(">");
129: return tp.toString();
130: }
131:
132: /** "nice name" using generics if specified. ?? AMELIORATE THIS !!
133: */
134: public static String formatTypeSimpleName(Type type, Class cl) {
135: String name = cl.getName(); // java.lang.Object
136: String typeName = "" + type; // E or "class java.lang.Object"
137:
138: if (typeName.startsWith("class ")
139: || typeName.startsWith("interface ")) {
140: // not specified
141: // (guessed ! because the Class.toString() was used)
142: return cl.getSimpleName();
143: } else {
144: // a last trick: make the name simple (i.e. String instead of java.lang.String)
145: String simpleName = cl.getSimpleName();
146: typeName = typeName.replace(name, simpleName);
147:
148: return typeName;
149: }
150: }
151:
152: public static String toStringForCompletion(Constructor co,
153: TypeParametersMapper mapper) {
154: StringBuilder sb = new StringBuilder();
155:
156: sb.append(co.getName());
157: sb.append(" ( "
158: + toStringParameters(co.getGenericParameterTypes(),
159: mapper, co.isVarArgs()));
160: sb.append(" )");
161:
162: return sb.toString();
163: }
164:
165: /** @param mapper if non null, replaces the type names E,V with the instance values defined (Integer, XXX, ...)
166: */
167: public static String toStringParameters(Type[] types,
168: TypeParametersMapper mapper, boolean vararg) {
169: StringBuilder sb = new StringBuilder();
170: if (types == null || types.length == 0)
171: return "";
172: for (int i = 0; i < types.length; i++) {
173: Type t = types[i];
174:
175: String name = null;
176: if (mapper != null) {
177: name = mapper.mapType(t);
178: } else {
179: name = ClassUtils.toStringTypeForCompletion(t);
180: }
181:
182: if (vararg && i == types.length - 1) {
183: name = name.substring(0, name.length() - 2) + "...";
184: }
185:
186: sb.append("" + name);
187: sb.append(", ");
188: }
189:
190: sb.setLength(sb.length() - 2); // remove the last ","
191:
192: return sb.toString();
193: }
194:
195: /** Appears in the completion.
196: * name ( params )
197: */
198: public static String toStringMethodForCompletion(Method m,
199: TypeParametersMapper mapper) {
200: StringBuilder sb = new StringBuilder();
201: sb.append(m.getName());
202: // [Feb2007]: removed two spaces, nice, but not good for filtering in table
203: sb.append("( "
204: + toStringParameters(m.getGenericParameterTypes(),
205: mapper, m.isVarArgs()));
206: sb.append(")");
207:
208: //Type[] exc = m.getGenericExceptionTypes();
209: /*
210: String ret = toStringTypeForCompletion(m.getGenericReturnType());
211: if(!ret.equals("void"))
212: {
213: sb.append( " returns "+ret );
214: }*/
215: return sb.toString();
216: }
217:
218: public static String toStringMethodArgsForCompletion(Method m,
219: TypeParametersMapper mapper) {
220: StringBuilder sb = new StringBuilder();
221: sb.append(""
222: + toStringParameters(m.getGenericParameterTypes(),
223: mapper, m.isVarArgs()));
224: sb.append("");
225: return sb.toString();
226: }
227:
228: public static String toStringFieldForCompletion(Field f) {
229: StringBuilder sb = new StringBuilder();
230: sb.append(f.getName());
231:
232: /*
233: String ret = toStringTypeForCompletion(f.getGenericType());
234: if(!ret.equals("void"))
235: {
236: sb.append( " of type "+ret );
237: }*/
238: return sb.toString();
239: }
240:
241: /** "void" => "" is ignored.
242: */
243: public static String toStringReturnTypeForCompletion(Type t,
244: TypeParametersMapper mapper) {
245: String ts = toStringTypeForCompletion(t);
246: if (ts.equals("void"))
247: return "";
248: if (mapper != null)
249: return mapper.mapType(t);
250: return ts;
251: }
252:
253: /** <code><K=..., V=...></code>
254: */
255: public static String toStringTypeParameters(Type[] types,
256: String instanceNames) {
257: if (types == null || types.length == 0)
258: return "";
259:
260: if (instanceNames == null || instanceNames.length() == 0)
261: return "";
262: String[] tn = instanceNames.split(",");
263: if (tn.length != types.length)
264: return " <?>";
265: StringBuilder sb = new StringBuilder("<");
266: for (int i = 0; i < types.length; i++) {
267: if (i > 0)
268: sb.append(", ");
269: sb.append("" + types[i] + "=" + tn[i]);
270: }
271: sb.append(">");
272: return sb.toString();
273: }
274:
275: public static String toStringTypeForCompletion(Type t) {
276: StringBuilder sb = new StringBuilder();
277: if (t instanceof Class) // java.lang.Class => Class
278: {
279: return "" + ((Class) t).getSimpleName();
280: } else if (t instanceof GenericArrayType) // java.lang.Class<?> => Class<?>
281: {
282: String tn = "" + t;
283: return tn; //StringClassUtils.removeBeforeIncluded(tn, ".");
284: }
285: /* else
286: {
287: System.out.println("Unknown type type "+t.getClass()+": "+t);
288: }*/
289:
290: String tn = "" + t;
291: sb.append(tn); // NO StringClassUtils.removeBeforeIncluded(tn, ".") );
292: return sb.toString();
293: }
294:
295: public static String toStringModifiersShort(int mod) {
296: StringBuilder modifString = new StringBuilder(12);
297: if (Modifier.isStatic(mod))
298: modifString.append("sta");
299: if (Modifier.isStrict(mod))
300: modifString.append(" str");
301: if (Modifier.isSynchronized(mod))
302: modifString.append(" sync");
303: if (Modifier.isFinal(mod))
304: modifString.append(" fin");
305: if (Modifier.isPublic(mod))
306: modifString.append(" pub");
307: if (Modifier.isPrivate(mod))
308: modifString.append(" pri");
309: if (Modifier.isProtected(mod))
310: modifString.append(" pro");
311: if (Modifier.isAbstract(mod))
312: modifString.append(" abs");
313: if (Modifier.isNative(mod))
314: modifString.append(" nat");
315: return modifString.toString().trim();
316: }
317:
318: /** Only pub pri pro sta sync.
319: */
320: public static String toStringPrincipalModifiersShort(int mod) {
321: StringBuilder modifString = new StringBuilder(12);
322: if (Modifier.isStatic(mod))
323: modifString.append("sta");
324: //if( Modifier.isStrict(mod) ) modifString.append(" str");
325: if (Modifier.isSynchronized(mod))
326: modifString.append(" sync");
327: //if( Modifier.isFinal(mod) ) modifString.append(" fin");
328: if (Modifier.isPublic(mod))
329: modifString.append(" pub");
330: if (Modifier.isPrivate(mod))
331: modifString.append(" pri");
332: if (Modifier.isProtected(mod))
333: modifString.append(" pro");
334: //if( Modifier.isAbstract(mod) ) modifString.append(" abs");
335: //if( Modifier.isNative(mod) ) modifString.append(" nat");
336: return modifString.toString().trim();
337: }
338:
339: public static boolean isAtLeastPackageScope(int mod) {
340: if (Modifier.isPublic(mod))
341: return true;
342: if (Modifier.isProtected(mod))
343: return false;
344: return !Modifier.isPrivate(mod);
345: }
346:
347: /** Called from IDChain to resolve expressions like a.b.c starting from a
348: * here we know that name is a field,
349: * (NOT a method, NOT an inner class like Point2D.Double(
350: * if no field found, try the inner classes (this also finds out the enums)
351: *
352: * @return the full resolved name of the class declaring the field.
353: *
354: * [Feb2008]: directly returns the class ref.
355: */
356: public static Class getTypeForFieldInClass(Class c, String name) {
357: if (c == null)
358: throw new NullPointerException("Cannot search for field "
359: + name + " in class null");
360:
361: try {
362: Field f = c.getDeclaredField(name);
363: if (f != null)
364: return f.getType(); //.getName();
365: } catch (Exception e) {
366: //MainEditorFrame.debugOut("no declared field "+name+" in "+(c!=null ? c.getName(): "null"));
367: //e.printStackTrace(); // often throwed...
368: } catch (Error e) {
369: e.printStackTrace();
370: } // can occur (illegal access)
371:
372: try {
373: Field f = c.getField(name);
374: if (f != null)
375: return f.getType(); //.getName();
376: } catch (Exception e) {
377: //System.out.println("No field "+name+" found in "+c);
378: MainEditorFrame.debugOut("No field " + name + " found in "
379: + c.getName() + " trying super classes");
380: //e.printStackTrace(); // often throwed...
381: } catch (Error e) {
382: e.printStackTrace();
383: }
384:
385: // [April2007]: Javadoc say that it looks in super ? (for PUBLIC fields only !...)
386: Class sc = c;
387: while ((sc = sc.getSuperclass()) != null) {
388: try {
389: Field f = sc.getDeclaredField(name); // getField only for public ones => use getDeclaredField !!!
390: if (f != null)
391: return f.getType(); //.getName();
392: } catch (Exception e) {
393: MainEditorFrame.debugOut("No field " + name
394: + " found in superclass " + sc.getName());
395: } catch (Error e) {
396: e.printStackTrace();
397: }
398: }
399:
400: MainEditorFrame.debugOut("No field " + name + " found in "
401: + c.getName() + " trying inner classes");
402: //MainEditorFrame.debugOut("fields = "+Arrays.toString(c.getDeclaredFields()));
403:
404: // looking if a public class member is named so !! (enums are also included !)
405: try {
406: for (Class pcm : c.getClasses()) {
407: //MainEditorFrame.debugOut("inner class(1) candidate: "+pcm.getSimpleName()+" for seeked "+name);
408: if (pcm.getSimpleName().equals(name)) {
409: //new Throwable().printStackTrace();
410: return pcm; //.getName();
411: }
412: }
413:
414: for (Class pcm : c.getDeclaredClasses()) // excludes inherited
415: {
416: // inner classes, (including static, private, ...)
417: //MainEditorFrame.debugOut("inner class(2) candidate: "+pcm.getSimpleName()+" for seeked "+name);
418: if (pcm.getSimpleName().equals(name)) {
419: //new Throwable().printStackTrace();
420: return pcm; //.getName();
421: }
422: }
423:
424: // look also in inherited ?
425: } catch (Exception e) {
426: e.printStackTrace();
427: } catch (Error e) {
428: e.printStackTrace();
429: }
430:
431: MainEditorFrame.debugOut("No public classes " + name
432: + " found in " + c.getName());
433:
434: return null;
435: }
436:
437: /** example [K,V], JFrame, K => JFrame
438: */
439: public static String getParameterType(Type[] classParams,
440: String params, Type param) {
441: // [May2007] ???
442: if (params == null || params.length() == 0) {
443: /*String tn = ""+param;
444: return tn; // TODO: remove "class "*/
445: return null;
446: }
447:
448: String[] paramsS = params.split(",");
449: if (paramsS.length != classParams.length)
450: return null;
451:
452: for (int i = 0; i < classParams.length; i++) {
453: if (classParams[i] == param)
454: return paramsS[i];
455: }
456: return null;
457: }
458:
459: public static boolean isDeprecated(AnnotatedElement c) // Members such as Method, Field
460: {
461: return c.isAnnotationPresent(java.lang.Deprecated.class);
462: }
463:
464: /** Arrays and classes implementing java.lang.Iterable are iterable, i.e.
465: * can be used in the enhanced for loop (since java5).
466: * @return false if class is null
467: */
468: public static boolean isIterable(Class cla) {
469: if (cla == null)
470: return false;
471:
472: for (Class inte : cla.getInterfaces()) // only directly implemented
473: {
474: if (inte.equals(java.lang.Iterable.class)) {
475: return true;
476: } else {
477: // recurse!
478: if (isIterable(inte))
479: return true;
480: }
481: }
482: return false;
483: }
484:
485: /** True if methods from interface OR marked as abstract are present.
486: * False if null class passed.
487: */
488: public static boolean hasAbstractMethods(final Class c) {
489: if (c == null)
490: return false;
491:
492: // [March2008] annotations like Override
493: // have abstract methods... but they are NOT to be implemented ( declared in interface java.lang.Annotation)
494: // this is strange and has to be filtered out here:
495: if (c.isAnnotation())
496: return false;
497:
498: for (Method m : c.getDeclaredMethods()) {
499: if (Modifier.isAbstract(m.getModifiers()))
500: return true;
501: }
502:
503: // resolves parents, interfaces, ...
504: for (Method m : c.getMethods()) {
505: if (Modifier.isAbstract(m.getModifiers()))
506: return true;
507: }
508:
509: return false;
510: }
511:
512: /** Takes the first name matching.
513: * TODO: bad strategy, same name method, with other args may exist !
514: * a method is uniquely ref with name + args...
515: * TODO: parameter types
516: */
517: public static String getTypeForMethodInClass(final Class c,
518: final String name, final String params) {
519: MainEditorFrame.debugOut("### Search return type of method "
520: + name + " in " + c + " p=" + params);
521: if (c == null)
522: throw new IllegalArgumentException(
523: "null class passed, cannot find method " + name);
524:
525: try {
526:
527: for (Method m : c.getDeclaredMethods()) {
528: if (m.getName().equals(name)) {
529: if (params != null && params.length() > 0) {
530: Type gen = m.getGenericReturnType();
531: String genStr = gen.toString();
532: if (genStr.length() > 0) {
533: if (SyntaxUtils.isPrimitiveType(genStr))
534: return genStr; //[May2007]
535:
536: MainEditorFrame
537: .debugOut("Generic return type1: "
538: + gen); // K
539: MainEditorFrame.debugOut("Class params1: "
540: + Arrays.toString(c
541: .getTypeParameters())); // [K,V]
542: MainEditorFrame.debugOut("parsed1: "
543: + params); // JFrame
544:
545: String ret = getParameterType(c
546: .getTypeParameters(), params, gen);
547: if (ret != null)
548: return ret;
549: }
550: }
551:
552: return m.getReturnType().getName();
553: }
554: }
555: } catch (Exception e) {
556: e.printStackTrace();
557: } catch (Error e) {
558: e.printStackTrace();
559: } // can occur (illegal access)
560:
561: try {
562: for (Method m : c.getMethods()) {
563: if (m.getName().equals(name)) {
564: if (params != null && params.length() > 0) {
565: Type gen = m.getGenericReturnType();
566:
567: String genStr = gen.toString();
568: if (genStr.length() > 0) {
569: if (SyntaxUtils.isPrimitiveType(genStr))
570: return genStr; //[May2007]
571:
572: MainEditorFrame
573: .debugOut("Generic return type2: "
574: + gen);
575: MainEditorFrame.debugOut("Class params2: "
576: + Arrays.toString(c
577: .getTypeParameters())); // [K,V]
578: MainEditorFrame.debugOut("parsed2: "
579: + params);
580: String ret = getParameterType(c
581: .getTypeParameters(), params, gen);
582: if (ret != null)
583: return ret;
584: }
585: }
586:
587: return m.getReturnType().getName();
588: }
589: }
590: } catch (Exception e) {
591: e.printStackTrace();
592: } catch (Error e) {
593: e.printStackTrace();
594: }
595:
596: // not found ? [April2007] c.getMethod only gives the PUBLIC ones
597: Class sc = c;
598: while ((sc = sc.getSuperclass()) != null) {
599: try {
600: for (Method m : sc.getDeclaredMethods()) {
601: if (m.getName().equals(name)) {
602: if (params != null && params.length() > 0) {
603: Type gen = m.getGenericReturnType();
604: String genStr = gen.toString();
605: if (genStr.length() > 0) {
606: if (SyntaxUtils.isPrimitiveType(genStr))
607: return genStr; //[May2007]
608:
609: MainEditorFrame
610: .debugOut("Generic return type3: "
611: + gen);
612: MainEditorFrame
613: .debugOut("Class params3: "
614: + Arrays
615: .toString(sc
616: .getTypeParameters())); // [K,V]
617: MainEditorFrame.debugOut("parsed3: "
618: + params);
619: String ret = getParameterType(sc
620: .getTypeParameters(), params,
621: gen);
622: if (ret != null)
623: return ret;
624: }
625: }
626: return m.getReturnType().getName();
627: }
628: }
629: } catch (Exception e) {
630: MainEditorFrame.debugOut("No field " + name
631: + " found in superclass " + sc.getName());
632: } catch (Error e) {
633: e.printStackTrace();
634: }
635: }
636:
637: // also look for inner types ???
638: return null;
639: }
640:
641: /** For classes loaded from signed jar, we see a full signature certificate, ...
642: */
643: public static void lookAtSource(String javaName) {
644: try {
645: lookAtSource(Class.forName(javaName));
646: } catch (Exception e) {
647: MainEditorFrame.debugOut("Unable to locate class "
648: + javaName);
649: e.printStackTrace();
650: }
651: }
652:
653: /** For classes loaded from signed jar, we see a full signature certificate, ...
654: */
655: public static void lookAtSource(Class cl) {
656: if (cl == null)
657: return;
658: try {
659: CodeSource source = cl.getProtectionDomain()
660: .getCodeSource();
661: if (source != null) {
662: URL location = source.getLocation(); // JAR FILE !
663: MainEditorFrame.debugOut(" source of " + cl.getName()
664: + ": " + location + ", " + source);
665: } else {
666: MainEditorFrame.debugOut(" " + cl.getName()
667: + ": unknown source, loader="
668: + cl.getClassLoader());
669: // loader:
670:
671: }
672: } catch (Exception e) {
673: MainEditorFrame
674: .debugOut("Unable to locate class source of "
675: + (cl != null ? cl.getName() : null));
676: e.printStackTrace();
677: }
678: }
679:
680: /* test */
681: public static void main(String[] args) throws Exception {
682:
683: Class cov = Class.forName("java.lang.Override");
684: for (Method dm : cov.getMethods()) {
685: System.out.println("\n" + dm.toGenericString() + "\tin\t"
686: + dm.getDeclaringClass());
687: System.out.println(""
688: + SyntaxUtils.makeAllJavaNamesSimpleInText(""
689: + dm.getGenericReturnType()));
690:
691: String cn = "" + dm.getGenericReturnType();
692: if (cn.startsWith("class "))
693: cn = cn.substring(6);
694: System.out.println(""
695: + SyntaxUtils.makeSingleJavaNameSimple(cn));
696:
697: }
698:
699: if (true)
700: return;
701:
702: Class cla = Class
703: .forName("javax.swing.table.AbstractTableModel");
704: System.out.println("ham=" + hasAbstractMethods(cla));
705: for (Method m : cla.getMethods()) {
706: System.out.println("" + m);
707: }
708: if (true)
709: return;
710:
711: Vector<String> ve = new Vector<String>();
712: Method m = ve.getClass().getMethod("iterator");
713: System.out.println("" + m.getGenericReturnType()); // java.util.Iterator<E>
714: System.out.println(""
715: + Arrays.toString(ve.getClass().getTypeParameters())); // [E]
716:
717: /*for(Method m : ve.getClass().getMethods())
718: {
719: //if(m.getName().indexOf("iter")>0)
720: {
721: }
722: } */
723: System.out.println("" + isIterable(java.util.Vector.class));
724: Object[][][] a = new Object[2][2][2];
725: System.out.println("sim name= " + a.getClass().getSimpleName());
726: System.out.println("can name= "
727: + a.getClass().getCanonicalName());
728: System.out.println(" name= " + a.getClass());
729:
730: lookAtSource("java.lang.String");
731: lookAtSource("tide.classsyntax.ClassUtils");
732: }
733: }
|