autoimports.js revision 1311:b8ea01a76cbc
1# autoimports script requires -scripting mode 2 3/* 4 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * - Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * - Neither the name of Oracle nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * It is tedious to import Java classes used in a script. Sometimes it is easier 36 * use simple names of java classes and have a script auto import Java classes. 37 * You can load this script at the start of an interactive jjs session or at the 38 * start of your script. This script defines a __noSuchProperty__ hook to auto 39 * import Java classes as needed and when they are referred to for the first time 40 * in your script. You can also call the "autoimports" function to print script 41 * statements that you need to use in your script, i.e., have the function generate 42 * a script to import Java classes used by your script so far. After running your 43 * script, you can call autoimports to get the exact Java imports you need and replace 44 * the autoimports load with the generated import statements (to avoid costly init of 45 * the autoimports script). 46 */ 47 48(function() { 49 var ArrayList = Java.type("java.util.ArrayList"); 50 var HashMap = Java.type("java.util.HashMap"); 51 var Files = Java.type("java.nio.file.Files"); 52 var FileSystems = Java.type("java.nio.file.FileSystems"); 53 var URI = Java.type("java.net.URI"); 54 55 // initialize a class to package map by iterating all 56 // classes available in the system by walking through "jrt fs" 57 var fs = FileSystems.getFileSystem(URI.create("jrt:/")); 58 var root = fs.getPath('/'); 59 60 var clsToPkg = new HashMap(); 61 62 function addToClsToPkg(c, p) { 63 if (clsToPkg.containsKey(c)) { 64 var val = clsToPkg.get(c); 65 if (val instanceof ArrayList) { 66 val.add(p); 67 } else { 68 var al = new ArrayList(); 69 al.add(val); 70 al.add(p); 71 clsToPkg.put(c, al); 72 } 73 } else { 74 clsToPkg.put(c, p); 75 } 76 } 77 78 // handle collision and allow user to choose package 79 function getPkgOfCls(c) { 80 var val = clsToPkg.get(c); 81 if (val instanceof ArrayList) { 82 var count = 1; 83 print("Multiple matches for " + c + ", choose package:"); 84 for each (var v in val) { 85 print(count + ". " + v); 86 count++; 87 } 88 var choice = parseInt(readLine()); 89 if (isNaN(choice) || choice < 1 || choice > val.size()) { 90 print("invalid choice: " + choice); 91 return undefined; 92 } 93 return val.get(choice - 1); 94 } else { 95 return val; 96 } 97 } 98 99 Files.walk(root).forEach(function(p) { 100 if (Files.isRegularFile(p)) { 101 var str = p.toString(); 102 if (str.endsWith(".class")) { 103 str = str.substring(1); 104 var idx = str.indexOf('/'); 105 if (idx != -1) { 106 str = str.substring(idx + 1); 107 if (str.startsWith("java") || 108 str.startsWith("javax") || 109 str.startsWith("org")) { 110 var lastIdx = str.lastIndexOf('/'); 111 if (lastIdx != -1) { 112 var pkg = str.substring(0, lastIdx).replaceAll('/', '.'); 113 var cls = str.substring(lastIdx + 1, str.lastIndexOf(".class")); 114 addToClsToPkg(cls, pkg); 115 } 116 } 117 } 118 } 119 } 120 }); 121 122 var imports = new ArrayList(); 123 var global = this; 124 var oldNoSuchProp = global.__noSuchProperty__; 125 this.__noSuchProperty__ = function(name) { 126 'use strict'; 127 128 if (clsToPkg.containsKey(name)) { 129 var pkg = getPkgOfCls(name); 130 if (pkg) { 131 var clsName = pkg + "." + name; 132 imports.add("var " + name + " = Java.type('" + clsName + "');"); 133 return global[name] = Java.type(clsName); 134 } 135 } else if (typeof oldNoSuchProp == 'function') { 136 return oldNoSuchProp.call(this, name); 137 } 138 139 if (typeof this == 'undefined') { 140 throw new ReferenceError(name); 141 } else { 142 return undefined; 143 } 144 } 145 146 this.autoimports = function() { 147 for each (var im in imports) { 148 print(im); 149 } 150 } 151})(); 152