001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.util; 020 021import icy.file.FileUtil; 022import icy.network.URLUtil; 023import icy.plugin.PluginLoader; 024import icy.system.IcyExceptionHandler; 025import icy.system.SystemUtil; 026 027import java.io.File; 028import java.io.IOException; 029import java.lang.reflect.Field; 030import java.lang.reflect.InvocationTargetException; 031import java.lang.reflect.Method; 032import java.lang.reflect.Modifier; 033import java.net.JarURLConnection; 034import java.net.URL; 035import java.net.URLConnection; 036import java.net.URLDecoder; 037import java.util.ArrayList; 038import java.util.Enumeration; 039import java.util.HashSet; 040import java.util.List; 041import java.util.Set; 042import java.util.Vector; 043import java.util.jar.JarEntry; 044import java.util.jar.JarFile; 045 046/** 047 * @author stephane 048 */ 049public class ClassUtil 050{ 051 /** 052 * Return the current thread context class loader 053 */ 054 public static ClassLoader getContextClassLoader() 055 { 056 return SystemUtil.getContextClassLoader(); 057 } 058 059 /** 060 * Return the system class loader 061 */ 062 public static ClassLoader getSystemClassLoader() 063 { 064 return SystemUtil.getSystemClassLoader(); 065 } 066 067 /** 068 * Return the list of all loaded classes by the specified {@link ClassLoader}.<br> 069 * Warning: this function is not safe and would not always work as expected.<br> 070 * It can return <code>null</code> if an error occurred. 071 */ 072 public static List<Class<?>> getLoadedClasses(ClassLoader cl) 073 { 074 try 075 { 076 final Vector classes = (Vector) ReflectionUtil.getFieldObject(cl, "classes", true); 077 return new ArrayList<Class<?>>(classes); 078 } 079 catch (Exception e) 080 { 081 IcyExceptionHandler.showErrorMessage(e, false, true); 082 } 083 084 return null; 085 } 086 087 /** 088 * @param primitiveName 089 * @return The Java primitive type represented by the given name, or null if the given name does 090 * not represent a primitive type 091 */ 092 public static Class<?> getPrimitiveType(String primitiveName) 093 { 094 if (primitiveName.equals("byte")) 095 return byte.class; 096 if (primitiveName.equals("short")) 097 return short.class; 098 if (primitiveName.equals("int")) 099 return int.class; 100 if (primitiveName.equals("long")) 101 return long.class; 102 if (primitiveName.equals("char")) 103 return char.class; 104 if (primitiveName.equals("float")) 105 return float.class; 106 if (primitiveName.equals("double")) 107 return double.class; 108 if (primitiveName.equals("boolean")) 109 return boolean.class; 110 if (primitiveName.equals("void")) 111 return void.class; 112 113 return null; 114 } 115 116 /** 117 * Get Class object of specified class name.<br> 118 * First search in Plugin Class loader then from the system class loader.<br> 119 * Primitive type are accepted. 120 * 121 * @throws ClassNotFoundException 122 */ 123 public static Class<?> findClass(String className) throws ClassNotFoundException 124 { 125 try 126 { 127 // first try to load from Plugin class loader 128 return PluginLoader.loadClass(className); 129 } 130 catch (ClassNotFoundException e1) 131 { 132 try 133 { 134 // then try to load from System class loader 135 return ClassLoader.getSystemClassLoader().loadClass(className); 136 } 137 catch (ClassNotFoundException e2) 138 { 139 try 140 { 141 // try forName style from Plugin class loader with initialization 142 return Class.forName(className, true, PluginLoader.getLoader()); 143 } 144 catch (ClassNotFoundException e3) 145 { 146 try 147 { 148 // try forName style from Plugin class loader without initialization 149 return Class.forName(className, false, PluginLoader.getLoader()); 150 } 151 catch (ClassNotFoundException e4) 152 { 153 // try with primitive type... 154 final Class<?> result = getPrimitiveType(className); 155 156 if (result != null) 157 return result; 158 159 // last luck... 160 return Class.forName(className); 161 } 162 } 163 } 164 } 165 } 166 167 /** 168 * Transform the specified path in qualified name.<br> 169 * <br> 170 * ex : "document/class/loader.class" --> "document.class.loader.class" (unix) 171 * "document\class\loader.class" --> "document.class.loader.class" (win) 172 * 173 * @param path 174 */ 175 public static String getQualifiedNameFromPath(String path) 176 { 177 return FileUtil.getGenericPath(path).replace(FileUtil.separatorChar, '.'); 178 } 179 180 /** 181 * Transform the specified qualified name in path.<br> 182 * Be careful, this function do not handle the file extension.<br> 183 * <br> 184 * ex : "plugins.user.loader.test" --> "plugins/user/loader/test" 185 */ 186 public static String getPathFromQualifiedName(String qualifiedName) 187 { 188 return qualifiedName.replace('.', FileUtil.separatorChar); 189 } 190 191 /** 192 * Get package name<br> 193 * ex : "plugin.test.myClass" --> "plugin.test" 194 */ 195 public static String getPackageName(String className) 196 { 197 final int index = className.lastIndexOf('.'); 198 199 if (index != -1) 200 return className.substring(0, index); 201 202 return ""; 203 } 204 205 /** 206 * Get first package name<br> 207 * ex : "plugin.test.myClass" --> "plugin" 208 */ 209 public static String getFirstPackageName(String className) 210 { 211 final String packageName = getPackageName(className); 212 final int index = packageName.lastIndexOf('.'); 213 214 if (index != -1) 215 return packageName.substring(0, index); 216 217 return packageName; 218 } 219 220 /** 221 * Get the base class name<br> 222 * ex : "plugin.myClass$InternClass$1" --> "plugin.myClass" 223 */ 224 public static String getBaseClassName(String className) 225 { 226 // handle inner classes... 227 final int lastDollar = className.indexOf('$'); 228 if (lastDollar > 0) 229 return className.substring(0, lastDollar); 230 231 return className; 232 } 233 234 /** 235 * Get simple class name<br> 236 * ex : "plugin.test.myClass$InternClass$1" --> "myClass$InternClass$1" 237 */ 238 public static String getSimpleClassName(String className) 239 { 240 final int index = className.lastIndexOf('.'); 241 242 if (index != -1) 243 return className.substring(index + 1); 244 245 return className; 246 } 247 248 /** 249 * Returns the source JAR file (if any) from where the specified class has been loaded from 250 */ 251 public static String getJarPath(Class<?> c) 252 { 253 final URL url = c.getResource('/' + c.getName().replace('.', '/') + ".class"); 254 255 // JAR url ? 256 if ((url != null) && url.getProtocol().equalsIgnoreCase("jar")) 257 { 258 String result; 259 int ind; 260 261 // extract 262 result = url.getPath(); 263 264 ind = result.indexOf(':'); 265 if (ind != -1) result= result.substring(ind+1); 266 267 ind = result.indexOf('!'); 268 if (ind != -1) result = result.substring(0, ind); 269 270 return new File(result).getAbsolutePath(); 271 } 272 273 return ""; 274 } 275 276 /** 277 * Return true if clazz implements the specified interface 278 */ 279 public static Class<?>[] getInterfaces(Class<?> c) 280 { 281 if (c == null) 282 return new Class[0]; 283 284 return c.getInterfaces(); 285 } 286 287 /** 288 * Return true if class is abstract 289 */ 290 public static boolean isAbstract(Class<?> c) 291 { 292 if (c == null) 293 return false; 294 295 return Modifier.isAbstract(c.getModifiers()); 296 } 297 298 /** 299 * Return true if class is public 300 */ 301 public static boolean isPublic(Class<?> c) 302 { 303 if (c == null) 304 return false; 305 306 return Modifier.isPublic(c.getModifiers()); 307 } 308 309 /** 310 * Return true if class is private 311 */ 312 public static boolean isPrivate(Class<?> c) 313 { 314 if (c == null) 315 return false; 316 317 return Modifier.isPrivate(c.getModifiers()); 318 } 319 320 /** 321 * Return true if clazz is the same class or extends baseClass 322 */ 323 public static boolean isSubClass(Class<?> clazz, Class<?> baseClass) 324 { 325 if ((clazz == null) || (baseClass == null)) 326 return false; 327 328 return baseClass.isAssignableFrom(clazz); 329 } 330 331 /** 332 * This method returns all resources that are located in the package identified by the given 333 * <code>packageName</code>.<br> 334 * <b>WARNING:</b><br> 335 * This is a relative expensive operation. Depending on your classpath multiple directories, JAR and WAR files may 336 * need to be scanned.<br> 337 * Original code written by Jorg Hohwiller for the m-m-m project (http://m-m-m.sf.net) 338 * 339 * @param packageName 340 * is the name of the {@link Package} to scan (ex: "java.awt.metrics") 341 * @param extension 342 * resource extension if we want to retrieve only a specific type of resource (ex: ".class")<br> 343 * Note that extension filtering is not case sensitive. 344 * @param recursive 345 * if set to <code>true</code> files from sub packages/folder are also returned. 346 * @param includeFolder 347 * if <code>true</code> folder entry are also returned 348 * @param includeJar 349 * if <code>true</code> all sub JAR files are also scanned 350 * @param includeHidden 351 * if <code>true</code> all hidden files (starting by '.' character) are also scanned 352 * @return 353 * all files contained in this package represented in path format (ex: "java/awt/geom/Rectangle2D.class") 354 */ 355 public static List<String> getResourcesInPackage(String packageName, String extension, boolean recursive, 356 boolean includeFolder, boolean includeJar, boolean includeHidden) throws IOException 357 { 358 final List<String> result = new ArrayList<String>(); 359 360 getResourcesInPackage(packageName, extension, recursive, includeFolder, includeJar, includeHidden, result); 361 362 return result; 363 } 364 365 /** 366 * Internal use, see {@link #getResourcesInPackage(String, String, boolean)} 367 */ 368 private static void getResourcesInPackage(String packageName, String extension, boolean recursive, 369 boolean includeFolder, boolean includeJar, boolean includeHidden, List<String> result) throws IOException 370 { 371 final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 372 final String path = ClassUtil.getPathFromQualifiedName(packageName); 373 final Enumeration<URL> urls = classLoader.getResources(path); 374 final String ext = StringUtil.isEmpty(extension) ? "" : extension.toLowerCase(); 375 376 while (urls.hasMoreElements()) 377 { 378 final URL packageUrl = urls.nextElement(); 379 final String urlPath = URLDecoder.decode(packageUrl.getFile(), "UTF-8"); 380 final String protocol = packageUrl.getProtocol().toLowerCase(); 381 382 if ("file".equals(protocol)) 383 getResourcesInPath(urlPath, packageName, recursive, includeFolder, includeJar, includeHidden, result); 384 else if ("jar".equals(protocol)) 385 { 386 final JarURLConnection connection = (JarURLConnection) packageUrl.openConnection(); 387 final JarFile jarFile = connection.getJarFile(); 388 final Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries(); 389 final String pathWithPrefix = path + '/'; 390 final int prefixLength = path.length() + 1; 391 392 while (jarEntryEnumeration.hasMoreElements()) 393 { 394 final JarEntry jarEntry = jarEntryEnumeration.nextElement(); 395 String absoluteFileName = jarEntry.getName(); 396 397 if (StringUtil.isEmpty(extension) || absoluteFileName.endsWith(ext)) 398 { 399 if (absoluteFileName.startsWith("/")) 400 absoluteFileName = absoluteFileName.substring(1); 401 402 boolean accept = true; 403 if (absoluteFileName.startsWith(pathWithPrefix)) 404 { 405 if (!recursive) 406 { 407 int index = absoluteFileName.indexOf('/', prefixLength); 408 if (index != -1) 409 accept = false; 410 } 411 412 if (!includeFolder && jarEntry.isDirectory()) 413 accept = false; 414 415 if (accept) 416 result.add(absoluteFileName); 417 } 418 } 419 } 420 421 jarFile.close(); 422 } 423 } 424 } 425 426 /** 427 * This method returns all resources that are located in the specified path.<br> 428 * 429 * @param path 430 * path to scan. 431 * @param recursive 432 * if <code>true</code> all sub folder are also scanned. 433 * @param includeJar 434 * if <code>true</code> all JAR files are also scanned 435 * @param includeHidden 436 * if <code>true</code> all hidden files (starting by '.' character) are also scanned 437 * @return list of found resources. 438 */ 439 public static List<String> getResourcesInPath(String path, boolean recursive, boolean includeFolder, 440 boolean includeJar, boolean includeHidden) 441 { 442 final List<String> result = new ArrayList<String>(); 443 444 getResourcesInPath(path, ClassUtil.getQualifiedNameFromPath(path), recursive, includeFolder, includeJar, 445 includeHidden, result); 446 447 return result; 448 } 449 450 /** 451 * This method returns all resources that are located in the specified path.<br> 452 * 453 * @param path 454 * path to scan. 455 * @param basePath 456 * path prefix 457 * @param recursive 458 * if <code>true</code> all sub folder are also scanned. 459 * @param includeJar 460 * if <code>true</code> all JAR files are also scanned 461 * @param includeHidden 462 * if <code>true</code> all hidden files (starting by '.' character) are also scanned 463 * @return set of found class. 464 */ 465 public static List<String> getResourcesInPath(String path, String basePath, boolean recursive, 466 boolean includeFolder, boolean includeJar, boolean includeHidden) 467 { 468 final List<String> result = new ArrayList<String>(); 469 470 getResourcesInPath(path, basePath, recursive, includeFolder, includeJar, includeHidden, result); 471 472 return result; 473 } 474 475 /** 476 * This method returns all resources that are located in the specified path.<br> 477 * 478 * @param path 479 * path to scan. 480 * @param basePath 481 * path prefix 482 * @param recursive 483 * if <code>true</code> all sub folder are also scanned. 484 * @param includeJar 485 * if <code>true</code> all JAR files are also scanned 486 * @param includeHidden 487 * if <code>true</code> all hidden files (starting by '.' character) are also scanned 488 * @param result 489 * result list 490 */ 491 public static void getResourcesInPath(String path, String basePath, boolean recursive, boolean includeFolder, 492 boolean includeJar, boolean includeHidden, List<String> result) 493 { 494 final File file = new File(path); 495 final String qualifiedPath; 496 497 if (StringUtil.isEmpty(basePath)) 498 qualifiedPath = ""; 499 else 500 qualifiedPath = basePath + "/"; 501 502 if (file.isDirectory()) 503 { 504 if (recursive) 505 findResourcesRecursive(file, includeFolder, includeJar, includeHidden, result, qualifiedPath); 506 else 507 { 508 for (File subFile : file.listFiles()) 509 findResourceInFile(subFile, includeJar, includeHidden, result, qualifiedPath); 510 } 511 } 512 else 513 findResourceInFile(file, includeJar, includeHidden, result, qualifiedPath); 514 } 515 516 private static void findResourcesRecursive(File directory, boolean includeFolder, boolean includeJar, 517 boolean includeHidden, List<String> result, String basePath) 518 { 519 for (File childFile : directory.listFiles()) 520 { 521 final String childFilename = childFile.getName(); 522 523 // folder ? 524 if (childFile.isDirectory()) 525 { 526 if (!includeHidden && childFilename.startsWith(".")) 527 continue; 528 529 // include this folder entry 530 if (includeFolder) 531 result.add(basePath + childFilename); 532 533 // then search in sub folder 534 findResourcesRecursive(childFile, includeJar, includeFolder, includeHidden, result, 535 basePath + childFilename + '/'); 536 } 537 else 538 findResourceInFile(childFile, includeJar, includeHidden, result, basePath); 539 } 540 } 541 542 /** 543 * Search for all classes in specified file 544 */ 545 public static void findResourceInFile(File file, boolean includeJar, boolean includeHidden, List<String> result, 546 String basePath) 547 { 548 final String shortName = file.getName(); 549 550 if (!includeHidden && shortName.startsWith(".")) 551 return; 552 553 final String fileName = file.getPath(); 554 555 if (FileUtil.getFileExtension(fileName, false).toLowerCase().equals("jar")) 556 { 557 if (includeJar) 558 JarUtil.getAllFiles(fileName, false, includeHidden, result); 559 } 560 else 561 result.add(basePath + shortName); 562 } 563 564 /** 565 * This method finds all classes that are located in the package identified by the given 566 * <code>packageName</code>.<br> 567 * <b>ATTENTION:</b><br> 568 * This is a relative expensive operation. Depending on your classpath multiple 569 * directories,JAR-, and WAR-files may need to be scanned. <br> 570 * 571 * @param packageName 572 * is the name of the {@link Package} to scan. 573 * @param includeSubPackages 574 * - if <code>true</code> all sub-packages of the specified {@link Package} will be 575 * included in the search. 576 * @return found classes set 577 * @throws IOException 578 * if the operation failed with an I/O error. 579 */ 580 public static Set<String> findClassNamesInPackage(String packageName, boolean includeSubPackages) throws IOException 581 { 582 final HashSet<String> classes = new HashSet<String>(); 583 584 findClassNamesInPackage(packageName, includeSubPackages, classes); 585 586 return classes; 587 } 588 589 /** 590 * This method finds all classes that are located in the package identified by the given 591 * <code>packageName</code>.<br> 592 * <b>ATTENTION:</b><br> 593 * This is a relative expensive operation. Depending on your classpath multiple 594 * directories,JAR-, and WAR-files may need to be scanned. <br> 595 * Original code written by Jorg Hohwiller for the m-m-m project (http://m-m-m.sf.net) 596 * 597 * @param packageName 598 * is the name of the {@link Package} to scan. 599 * @param includeSubPackages 600 * - if <code>true</code> all sub-packages of the specified {@link Package} will be 601 * included in the search. 602 * @param classes 603 * save found classes here 604 */ 605 public static void findClassNamesInPackage(String packageName, boolean includeSubPackages, Set<String> classes) 606 throws IOException 607 { 608 final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 609 final String path = ClassUtil.getPathFromQualifiedName(packageName); 610 final Enumeration<URL> urls = classLoader.getResources(path); 611 612 while (urls.hasMoreElements()) 613 { 614 final URL packageUrl = urls.nextElement(); 615 final String urlPath = URLDecoder.decode(packageUrl.getFile(), "UTF-8"); 616 final String protocol = packageUrl.getProtocol().toLowerCase(); 617 618 if ("file".equals(protocol)) 619 findClassNamesInPath(urlPath, packageName, includeSubPackages, classes); 620 else if ("jar".equals(protocol)) 621 { 622 final JarURLConnection connection = (JarURLConnection) packageUrl.openConnection(); 623 final JarFile jarFile = connection.getJarFile(); 624 final Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries(); 625 final String pathWithPrefix = path + '/'; 626 final int prefixLength = path.length() + 1; 627 628 while (jarEntryEnumeration.hasMoreElements()) 629 { 630 final JarEntry jarEntry = jarEntryEnumeration.nextElement(); 631 String absoluteFileName = jarEntry.getName(); 632 633 if (absoluteFileName.endsWith(".class")) 634 { 635 if (absoluteFileName.startsWith("/")) 636 absoluteFileName = absoluteFileName.substring(1); 637 638 boolean accept = true; 639 if (absoluteFileName.startsWith(pathWithPrefix)) 640 { 641 String qualifiedName = absoluteFileName.replace('/', '.'); 642 643 if (!includeSubPackages) 644 { 645 int index = absoluteFileName.indexOf('/', prefixLength); 646 if (index != -1) 647 accept = false; 648 } 649 650 if (accept) 651 { 652 final String className = filenameToClassname(qualifiedName); 653 if (className != null) 654 classes.add(className); 655 } 656 } 657 } 658 } 659 660 jarFile.close(); 661 } 662 } 663 } 664 665 /** 666 * This method finds all classes that are located in the specified directory.<br> 667 * 668 * @param path 669 * path to scan. 670 * @param includeSubDir 671 * if <code>true</code> all sub-directory are also scanned. 672 * @return set of found class. 673 */ 674 public static HashSet<String> findClassNamesInPath(String path, boolean includeSubDir) 675 { 676 return findClassNamesInPath(path, ClassUtil.getQualifiedNameFromPath(path), includeSubDir, true); 677 } 678 679 /** 680 * This method finds all classes that are located in the specified directory.<br> 681 * 682 * @param path 683 * path to scan. 684 * @param includeSubDir 685 * if <code>true</code> all sub-directory are also scanned. 686 * @param includeJar 687 * if <code>true</code> all JAR files are also scanned 688 * @return set of found class. 689 */ 690 public static HashSet<String> findClassNamesInPath(String path, boolean includeSubDir, boolean includeJar) 691 { 692 return findClassNamesInPath(path, ClassUtil.getQualifiedNameFromPath(path), includeSubDir, includeJar); 693 } 694 695 /** 696 * This method finds all classes that are located in the specified directory.<br> 697 * 698 * @param path 699 * path to scan. 700 * @param packageName 701 * package name prefix 702 * @param includeSubDir 703 * if <code>true</code> all sub-directory are also scanned. 704 * @return set of found class. 705 */ 706 public static HashSet<String> findClassNamesInPath(String path, String packageName, boolean includeSubDir) 707 { 708 final HashSet<String> classes = new HashSet<String>(); 709 710 findClassNamesInPath(path, packageName, includeSubDir, true, classes); 711 712 return classes; 713 } 714 715 /** 716 * This method finds all classes that are located in the specified directory.<br> 717 * 718 * @param path 719 * path to scan. 720 * @param packageName 721 * package name prefix 722 * @param includeSubDir 723 * if <code>true</code> all sub-directory are also scanned. 724 * @param includeJar 725 * if <code>true</code> all JAR files are also scanned 726 * @return set of found class. 727 */ 728 public static HashSet<String> findClassNamesInPath(String path, String packageName, boolean includeSubDir, 729 boolean includeJar) 730 { 731 final HashSet<String> classes = new HashSet<String>(); 732 733 findClassNamesInPath(path, packageName, includeSubDir, includeJar, classes); 734 735 return classes; 736 } 737 738 /** 739 * This method finds all classes that are located in the specified directory.<br> 740 * 741 * @param path 742 * path to scan. 743 * @param packageName 744 * package name prefix 745 * @param includeSubDir 746 * if <code>true</code> all sub-directory are also scanned. 747 * @param classes 748 * save found classes here 749 */ 750 public static void findClassNamesInPath(String path, String packageName, boolean includeSubDir, Set<String> classes) 751 { 752 findClassNamesInPath(path, packageName, includeSubDir, true, classes); 753 } 754 755 /** 756 * This method finds all classes that are located in the specified directory.<br> 757 * 758 * @param path 759 * path to scan. 760 * @param packageName 761 * package name prefix 762 * @param includeSubDir 763 * if <code>true</code> all sub-directory are also scanned. 764 * @param includeJar 765 * if <code>true</code> all JAR files are also scanned 766 * @param classes 767 * save found classes here 768 */ 769 public static void findClassNamesInPath(String path, String packageName, boolean includeSubDir, boolean includeJar, 770 Set<String> classes) 771 { 772 final File dir = new File(path); 773 final String qualifiedName; 774 775 if (StringUtil.isEmpty(packageName)) 776 qualifiedName = ""; 777 else 778 qualifiedName = packageName + '.'; 779 780 if (dir.isDirectory()) 781 { 782 if (includeSubDir) 783 findClassNamesRecursive(dir, includeJar, classes, qualifiedName); 784 else 785 for (File file : dir.listFiles()) 786 findClassNameInFile(file, includeJar, classes, qualifiedName); 787 } 788 else 789 findClassNameInFile(dir, classes, qualifiedName); 790 } 791 792 private static void findClassNamesRecursive(File directory, boolean includeJar, Set<String> classSet, 793 String qualifiedName) 794 { 795 for (File childFile : directory.listFiles()) 796 { 797 final String childFilename = childFile.getName(); 798 799 // files or directories starting with "." aren't allowed 800 if (!childFilename.startsWith(".")) 801 { 802 if (childFile.isDirectory()) 803 findClassNamesRecursive(childFile, includeJar, classSet, qualifiedName + childFilename + '.'); 804 else 805 findClassNameInFile(childFile, includeJar, classSet, qualifiedName); 806 } 807 } 808 } 809 810 /** 811 * Search for all classes in specified file 812 */ 813 public static void findClassNameInFile(File file, boolean includeJar, Set<String> classSet, 814 String qualifiedNamePrefix) 815 { 816 final String fileName = file.getPath(); 817 if (FileUtil.getFileExtension(fileName, false).toLowerCase().equals("jar")) 818 { 819 if (includeJar) 820 findClassNamesInJAR(fileName, classSet); 821 } 822 else 823 addClassFileName(file.getName(), classSet, qualifiedNamePrefix); 824 } 825 826 /** 827 * Search for all classes in specified file 828 */ 829 public static void findClassNameInFile(File file, Set<String> classSet, String qualifiedNamePrefix) 830 { 831 findClassNameInFile(file, true, classSet, qualifiedNamePrefix); 832 } 833 834 /** 835 * Search for all classes in JAR file 836 */ 837 public static void findClassNamesInJAR(String fileName, Set<String> classSet) 838 { 839 final JarFile jarFile; 840 841 try 842 { 843 jarFile = new JarFile(fileName); 844 } 845 catch (IOException e) 846 { 847 System.err.println("Cannot open " + fileName + ":"); 848 IcyExceptionHandler.showErrorMessage(e, false, true); 849 return; 850 } 851 852 final Enumeration<JarEntry> entries = jarFile.entries(); 853 854 while (entries.hasMoreElements()) 855 { 856 final JarEntry jarEntry = entries.nextElement(); 857 858 if (!jarEntry.isDirectory()) 859 addClassFileName(jarEntry.getName(), classSet, ""); 860 } 861 862 try 863 { 864 jarFile.close(); 865 } 866 catch (IOException e) 867 { 868 // ignore 869 } 870 } 871 872 /** 873 * Search for all classes in JAR file 874 * 875 * @param fileName 876 */ 877 public static Set<String> findClassNamesInJAR(String fileName) 878 { 879 final HashSet<String> result = new HashSet<String>(); 880 881 findClassNamesInJAR(fileName, result); 882 883 return result; 884 } 885 886 private static void addClassFileName(String fileName, Set<String> classSet, String prefix) 887 { 888 final String simpleClassName = filenameToClassname(fileName); 889 890 if (simpleClassName != null) 891 classSet.add(prefix + simpleClassName); 892 } 893 894 /** 895 * This method checks and transforms the filename of a potential {@link Class} given by <code>fileName</code>. 896 * 897 * @param fileName 898 * is the filename. 899 * @return the according Java {@link Class#getName() class-name} for the given <code>fileName</code> if it is a 900 * class-file that is no anonymous {@link Class}, else <code>null</code>. 901 */ 902 public static String filenameToClassname(String fileName) 903 { 904 // class file ? 905 if (fileName.toLowerCase().endsWith(".class")) 906 // remove ".class" extension and fix classname 907 return fixClassName(fileName.substring(0, fileName.length() - 6)); 908 909 return null; 910 } 911 912 /** 913 * This method checks and transforms the filename of a potential {@link Class} given by <code>fileName</code>.<br> 914 * Code written by Jorg Hohwiller for the m-m-m project (http://m-m-m.sf.net) 915 * 916 * @param fileName 917 * is the filename. 918 * @return the according Java {@link Class#getName() class-name} for the given <code>fileName</code> if it is a 919 * class-file that is no anonymous {@link Class}, else <code>null</code>. 920 */ 921 public static String fixClassName(String fileName) 922 { 923 // replace path separator by package separator 924 String result = fileName.replace('/', '.'); 925 926 // handle inner classes... 927 final int lastDollar = result.lastIndexOf('$'); 928 if (lastDollar > 0) 929 { 930 char innerChar = result.charAt(lastDollar + 1); 931 // ignore anonymous inner class 932 if ((innerChar >= '0') && (innerChar <= '9')) 933 return null; 934 935 // TODO: check we really don't need to replace '$' by '.' 936 // return result.replace('$', '.'); 937 } 938 939 return result; 940 } 941 942 /** 943 * Find the file (.jar or .class usually) that host this class. 944 * 945 * @param fullClassName 946 * The class name to look for. 947 * @return The File that contains this class. 948 * It will return <code>null</code> if the class was not loaded from a file or for any 949 * other error. 950 */ 951 public static File getFile(String fullClassName) 952 { 953 final String className = ClassUtil.getBaseClassName(fullClassName); 954 955 try 956 { 957 final Class<?> clazz = findClass(className); 958 959 URL classUrl = clazz.getResource(clazz.getSimpleName() + ".class"); 960 if (classUrl == null) 961 classUrl = clazz.getResource(clazz.getName() + ".class"); 962 963 final URLConnection connection = classUrl.openConnection(); 964 965 if (connection instanceof JarURLConnection) 966 return new File(((JarURLConnection) connection).getJarFileURL().toURI()); 967 // if (connection instanceof FileURLConnection) 968 // return new File(classUrl.toURI()); 969 // try from URI 970 return new File(classUrl.toURI()); 971 } 972 catch (Exception e) 973 { 974 // ignore 975 IcyExceptionHandler.showErrorMessage(e, false, true); 976 } 977 978 return null; 979 } 980 981 /** 982 * @deprecated Use {@link ReflectionUtil#getMethod(Object, String, boolean, Class...)} instead 983 */ 984 @Deprecated 985 public static Method getMethod(Object object, String methodName, boolean forceAccess, Class<?>... parameterTypes) 986 throws SecurityException, NoSuchMethodException 987 { 988 return ReflectionUtil.getMethod(object, methodName, forceAccess, parameterTypes); 989 } 990 991 /** 992 * @deprecated Use {@link ReflectionUtil#invokeMethod(Object, String, boolean, Object...)} instead 993 */ 994 @Deprecated 995 public static Object invokeMethod(Object object, String methodName, boolean forceAccess, Object... args) 996 throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, 997 InvocationTargetException 998 { 999 return ReflectionUtil.invokeMethod(object, methodName, forceAccess, args); 1000 } 1001 1002 /** 1003 * @deprecated Use {@link ReflectionUtil#getField(Object, String, boolean)} instead 1004 */ 1005 @Deprecated 1006 public static Field getField(Object object, String fieldName, boolean forceAccess) 1007 throws SecurityException, NoSuchFieldException 1008 { 1009 return ReflectionUtil.getField(object, fieldName, forceAccess); 1010 } 1011 1012 /** 1013 * @deprecated Use {@link ReflectionUtil#getFieldObject(Object, String, boolean)} instead 1014 */ 1015 @Deprecated 1016 public static Object getFieldObject(Object object, String fieldName, boolean forceAccess) 1017 throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException 1018 { 1019 return ReflectionUtil.getFieldObject(object, fieldName, forceAccess); 1020 } 1021}