Wed, 07 Oct 2015 10:01:40 -0700
Merge
1 # autoimports script requires -scripting mode
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 */
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 */
48 (function() {
49 var ArrayList = Java.type("java.util.ArrayList");
50 var HashMap = Java.type("java.util.HashMap");
51 var JarFile = Java.type("java.util.jar.JarFile");
52 var File = Java.type("java.io.File");
53 var Files = Java.type("java.nio.file.Files");
54 var FileSystems = Java.type("java.nio.file.FileSystems");
55 var System = Java.type("java.lang.System");
56 var URI = Java.type("java.net.URI");
58 // initialize a class to package map by iterating all
59 // classes available in the system by walking through "jrt fs"
61 var clsToPkg = new HashMap();
63 // locate rt.jar from sun.boot.class.path
64 function findRtJar() {
65 var paths = System.getProperty("sun.boot.class.path").split(File.pathSeparator);
66 for each (var p in paths) {
67 if (p.endsWith("rt.jar") && new File(p).exists()) {
68 return p;
69 }
70 }
71 }
74 function addToClsToPkg(c, p) {
75 if (clsToPkg.containsKey(c)) {
76 var val = clsToPkg.get(c);
77 if (val instanceof ArrayList) {
78 val.add(p);
79 } else {
80 var al = new ArrayList();
81 al.add(val);
82 al.add(p);
83 clsToPkg.put(c, al);
84 }
85 } else {
86 clsToPkg.put(c, p);
87 }
88 }
90 // handle collision and allow user to choose package
91 function getPkgOfCls(c) {
92 var val = clsToPkg.get(c);
93 if (val instanceof ArrayList) {
94 var count = 1;
95 print("Multiple matches for " + c + ", choose package:");
96 for each (var v in val) {
97 print(count + ". " + v);
98 count++;
99 }
100 var choice = parseInt(readLine());
101 if (isNaN(choice) || choice < 1 || choice > val.size()) {
102 print("invalid choice: " + choice);
103 return undefined;
104 }
105 return val.get(choice - 1);
106 } else {
107 return val;
108 }
109 }
111 var rtJar = findRtJar();
112 var stream = new JarFile(rtJar).stream();
113 try {
114 stream.forEach(
115 function(entry) {
116 var str = entry.name;
117 if (str.endsWith(".class")) {
118 if (str.startsWith("java") ||
119 str.startsWith("javax") ||
120 str.startsWith("org")) {
121 var lastIdx = str.lastIndexOf('/');
122 if (lastIdx != -1) {
123 var pkg = str.substring(0, lastIdx).replaceAll('/', '.');
124 var cls = str.substring(lastIdx + 1, str.lastIndexOf(".class"));
125 addToClsToPkg(cls, pkg);
126 }
127 }
128 }
129 });
130 } finally {
131 stream.close();
132 }
134 var imports = new ArrayList();
135 var global = this;
136 var oldNoSuchProp = global.__noSuchProperty__;
137 this.__noSuchProperty__ = function(name) {
138 'use strict';
140 if (clsToPkg.containsKey(name)) {
141 var pkg = getPkgOfCls(name);
142 if (pkg) {
143 var clsName = pkg + "." + name;
144 imports.add("var " + name + " = Java.type('" + clsName + "');");
145 return global[name] = Java.type(clsName);
146 }
147 } else if (typeof oldNoSuchProp == 'function') {
148 return oldNoSuchProp.call(this, name);
149 }
151 if (typeof this == 'undefined') {
152 throw new ReferenceError(name);
153 } else {
154 return undefined;
155 }
156 }
158 this.autoimports = function() {
159 for each (var im in imports) {
160 print(im);
161 }
162 }
163 })();