author | sundar |
Tue, 12 Mar 2013 18:12:42 +0530 | |
changeset 16522 | d643e3ee819c |
parent 16272 | 675a0caf75bc |
child 16777 | 207a993adb9a |
permissions | -rw-r--r-- |
16147 | 1 |
/* |
16151 | 2 |
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
16147 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package jdk.nashorn.internal.objects; |
|
27 |
||
28 |
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; |
|
29 |
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; |
|
30 |
||
31 |
import java.lang.reflect.Array; |
|
32 |
import java.util.Collection; |
|
16234
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16233
diff
changeset
|
33 |
import jdk.internal.dynalink.beans.StaticClass; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16233
diff
changeset
|
34 |
import jdk.internal.dynalink.support.TypeUtilities; |
16147 | 35 |
import jdk.nashorn.internal.objects.annotations.Attribute; |
36 |
import jdk.nashorn.internal.objects.annotations.Function; |
|
37 |
import jdk.nashorn.internal.objects.annotations.ScriptClass; |
|
38 |
import jdk.nashorn.internal.objects.annotations.Where; |
|
39 |
import jdk.nashorn.internal.runtime.JSType; |
|
40 |
import jdk.nashorn.internal.runtime.ScriptObject; |
|
41 |
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; |
|
42 |
||
43 |
/** |
|
44 |
* This class is the implementation for the {@code Java} global object exposed to programs running under Nashorn. This |
|
45 |
* object acts as the API entry point to Java platform specific functionality, dealing with creating new instances of |
|
46 |
* Java classes, subclassing Java classes, implementing Java interfaces, converting between Java arrays and ECMAScript |
|
47 |
* arrays, and so forth. |
|
48 |
*/ |
|
49 |
@ScriptClass("Java") |
|
16226
0e4f37e6cc40
8007915: Nashorn IR, codegen, parser packages and Context instance should be inaccessible to user code
sundar
parents:
16212
diff
changeset
|
50 |
public final class NativeJava { |
16147 | 51 |
|
52 |
private NativeJava() { |
|
53 |
} |
|
54 |
||
55 |
/** |
|
56 |
* Returns true if the specified object is a Java type object, that is an instance of {@link StaticClass}. |
|
57 |
* @param self not used |
|
58 |
* @param type the object that is checked if it is a type object or not |
|
59 |
* @return tells whether given object is a Java type object or not. |
|
60 |
* @see #type(Object, Object) |
|
61 |
*/ |
|
62 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
63 |
public static Object isType(final Object self, final Object type) { |
|
64 |
return type instanceof StaticClass; |
|
65 |
} |
|
66 |
||
67 |
/** |
|
16272 | 68 |
* <p> |
16147 | 69 |
* Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects |
70 |
* used to represent Java types in Nashorn is not {@link java.lang.Class} but rather {@link StaticClass}. They are |
|
71 |
* the objects that you can use with the {@code new} operator to create new instances of the class as well as to |
|
72 |
* access static members of the class. In Nashorn, {@code Class} objects are just regular Java objects that aren't |
|
73 |
* treated specially. Instead of them, {@link StaticClass} instances - which we sometimes refer to as "Java type |
|
74 |
* objects" are used as constructors with the {@code new} operator, and they expose static fields, properties, and |
|
75 |
* methods. While this might seem confusing at first, it actually closely matches the Java language: you use a |
|
76 |
* different expression (e.g. {@code java.io.File}) as an argument in "new" and to address statics, and it is |
|
77 |
* distinct from the {@code Class} object (e.g. {@code java.io.File.class}). Below we cover in details the |
|
78 |
* properties of the type objects. |
|
16272 | 79 |
* </p> |
80 |
* <p><b>Constructing Java objects</b></p> |
|
16147 | 81 |
* Examples: |
82 |
* <pre> |
|
83 |
* var arrayListType = Java.type("java.util.ArrayList") |
|
84 |
* var intType = Java.type("int") |
|
85 |
* var stringArrayType = Java.type("java.lang.String[]") |
|
86 |
* var int2DArrayType = Java.type("int[][]") |
|
87 |
* </pre> |
|
88 |
* Note that the name of the type is always a string for a fully qualified name. You can use any of these types to |
|
89 |
* create new instances, e.g.: |
|
90 |
* <pre> |
|
91 |
* var anArrayList = new Java.type("java.util.ArrayList") |
|
92 |
* </pre> |
|
93 |
* or |
|
94 |
* <pre> |
|
95 |
* var ArrayList = Java.type("java.util.ArrayList") |
|
96 |
* var anArrayList = new ArrayList |
|
97 |
* var anArrayListWithSize = new ArrayList(16) |
|
98 |
* </pre> |
|
99 |
* In the special case of inner classes, you need to use the JVM fully qualified name, meaning using {@code $} sign |
|
100 |
* in the class name: |
|
101 |
* <pre> |
|
102 |
* var ftype = Java.type("java.awt.geom.Arc2D$Float") |
|
103 |
* </pre> |
|
104 |
* However, once you retrieved the outer class, you can access the inner class as a property on it: |
|
105 |
* <pre> |
|
106 |
* var arctype = Java.type("java.awt.geom.Arc2D") |
|
107 |
* var ftype = arctype.Float |
|
108 |
* </pre> |
|
16272 | 109 |
* <p> |
16147 | 110 |
* You can access both static and non-static inner classes. If you want to create an instance of a non-static |
111 |
* inner class, remember to pass an instance of its outer class as the first argument to the constructor. |
|
16272 | 112 |
* </p> |
113 |
* <p> |
|
16147 | 114 |
* If the type is abstract, you can instantiate an anonymous subclass of it using an argument list that is |
115 |
* applicable to any of its public or protected constructors, but inserting a JavaScript object with functions |
|
116 |
* properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the |
|
117 |
* JavaScript function will provide implementation for all overloads. E.g.: |
|
16272 | 118 |
* </p> |
16147 | 119 |
* <pre> |
120 |
* var TimerTask = Java.type("java.util.TimerTask") |
|
121 |
* var task = new TimerTask({ run: function() { print("Hello World!") } }) |
|
122 |
* </pre> |
|
16272 | 123 |
* <p> |
16147 | 124 |
* Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to |
125 |
* invoking the constructor and passing the argument to it, so you can write the above example also as: |
|
16272 | 126 |
* </p> |
16147 | 127 |
* <pre> |
128 |
* var task = new TimerTask { |
|
129 |
* run: function() { |
|
130 |
* print("Hello World!") |
|
131 |
* } |
|
132 |
* } |
|
133 |
* </pre> |
|
16272 | 134 |
* <p> |
16147 | 135 |
* which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract |
136 |
* type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share |
|
137 |
* the same overloaded name), then instead of an object, you can just pass a function, so the above example can |
|
138 |
* become even more simplified to: |
|
16272 | 139 |
* </p> |
16147 | 140 |
* <pre> |
141 |
* var task = new TimerTask(function() { print("Hello World!") }) |
|
142 |
* </pre> |
|
16272 | 143 |
* <p> |
16147 | 144 |
* Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors |
145 |
* that take some arguments, you can invoke those simply by specifying the arguments after the initial |
|
146 |
* implementation object or function. |
|
16272 | 147 |
* </p> |
148 |
* <p>The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, |
|
16147 | 149 |
* you can just pass in a function object, and Nashorn will know what you meant: |
16272 | 150 |
* </p> |
16147 | 151 |
* <pre> |
152 |
* var timer = new Java.type("java.util.Timer") |
|
153 |
* timer.schedule(function() { print("Hello World!") }) |
|
154 |
* </pre> |
|
16272 | 155 |
* <p> |
16147 | 156 |
* Here, {@code Timer.schedule()} expects a {@code TimerTask} as its argument, so Nashorn creates an instance of a |
157 |
* {@code TimerTask} subclass and uses the passed function to implement its only abstract method, {@code run()}. In |
|
158 |
* this usage though, you can't use non-default constructors; the type must be either an interface, or must have a |
|
159 |
* protected or public no-arg constructor. |
|
16272 | 160 |
* </p> |
161 |
* <p> |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
162 |
* You can also subclass non-abstract classes; for that you will need to use the {@link #extend(Object, Object...)} |
16147 | 163 |
* method. |
16272 | 164 |
* </p> |
165 |
* <p><b>Accessing static members</b></p> |
|
16147 | 166 |
* Examples: |
167 |
* <pre> |
|
168 |
* var File = Java.type("java.io.File") |
|
169 |
* var pathSep = File.pathSeparator |
|
170 |
* var tmpFile1 = File.createTempFile("abcdefg", ".tmp") |
|
171 |
* var tmpFile2 = File.createTempFile("abcdefg", ".tmp", new File("/tmp")) |
|
172 |
* </pre> |
|
173 |
* Actually, you can even assign static methods to variables, so the above example can be rewritten as: |
|
174 |
* <pre> |
|
175 |
* var File = Java.type("java.io.File") |
|
176 |
* var createTempFile = File.createTempFile |
|
177 |
* var tmpFile1 = createTempFile("abcdefg", ".tmp") |
|
178 |
* var tmpFile2 = createTempFile("abcdefg", ".tmp", new File("/tmp")) |
|
179 |
* </pre> |
|
180 |
* If you need to access the actual {@code java.lang.Class} object for the type, you can use the {@code class} |
|
181 |
* property on the object representing the type: |
|
182 |
* <pre> |
|
183 |
* var File = Java.type("java.io.File") |
|
184 |
* var someFile = new File("blah") |
|
185 |
* print(File.class === someFile.getClass()) // prints true |
|
186 |
* </pre> |
|
187 |
* Of course, you can also use the {@code getClass()} method or its equivalent {@code class} property on any |
|
188 |
* instance of the class. Other way round, you can use the synthetic {@code static} property on any |
|
189 |
* {@code java.lang.Class} object to retrieve its type-representing object: |
|
190 |
* <pre> |
|
191 |
* var File = Java.type("java.io.File") |
|
192 |
* print(File.class.static === File) // prints true |
|
193 |
* </pre> |
|
16272 | 194 |
* <p><b>{@code instanceof} operator</b></p> |
16147 | 195 |
* The standard ECMAScript {@code instanceof} operator is extended to recognize Java objects and their type objects: |
196 |
* <pre> |
|
197 |
* var File = Java.type("java.io.File") |
|
198 |
* var aFile = new File("foo") |
|
199 |
* print(aFile instanceof File) // prints true |
|
200 |
* print(aFile instanceof File.class) // prints false - Class objects aren't type objects. |
|
201 |
* </pre> |
|
202 |
* @param self not used |
|
203 |
* @param objTypeName the object whose JS string value represents the type name. You can use names of primitive Java |
|
204 |
* types to obtain representations of them, and you can use trailing square brackets to represent Java array types. |
|
205 |
* @return the object representing the named type |
|
206 |
* @throws ClassNotFoundException if the class is not found |
|
207 |
*/ |
|
208 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
209 |
public static Object type(final Object self, final Object objTypeName) throws ClassNotFoundException { |
|
210 |
return type(objTypeName); |
|
211 |
} |
|
212 |
||
213 |
private static StaticClass type(final Object objTypeName) throws ClassNotFoundException { |
|
214 |
return StaticClass.forClass(type(JSType.toString(objTypeName))); |
|
215 |
} |
|
216 |
||
217 |
private static Class<?> type(final String typeName) throws ClassNotFoundException { |
|
218 |
if (typeName.endsWith("[]")) { |
|
219 |
return arrayType(typeName); |
|
220 |
} |
|
221 |
||
222 |
return simpleType(typeName); |
|
223 |
} |
|
224 |
||
225 |
/** |
|
16522 | 226 |
* Returns name of a java type {@link StaticClass}. |
227 |
* @param self not used |
|
228 |
* @param type the type whose name is returned |
|
229 |
* @return name of the given type |
|
230 |
*/ |
|
231 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
232 |
public static Object typeName(final Object self, final Object type) { |
|
233 |
if (type instanceof StaticClass) { |
|
234 |
return ((StaticClass)type).getRepresentedClass().getName(); |
|
235 |
} else if (type instanceof Class) { |
|
236 |
return ((Class<?>)type).getName(); |
|
237 |
} else { |
|
238 |
return UNDEFINED; |
|
239 |
} |
|
240 |
} |
|
241 |
||
242 |
/** |
|
16147 | 243 |
* Given a JavaScript array and a Java type, returns a Java array with the same initial contents, and with the |
244 |
* specified component type. Example: |
|
245 |
* <pre> |
|
246 |
* var anArray = [1, "13", false] |
|
247 |
* var javaIntArray = Java.toJavaArray(anArray, "int") |
|
248 |
* print(javaIntArray[0]) // prints 1 |
|
249 |
* print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion |
|
250 |
* print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion |
|
251 |
* </pre> |
|
252 |
* @param self not used |
|
253 |
* @param objArray the JavaScript array. Can be null. |
|
254 |
* @param objType either a {@link #type(Object, Object) type object} or a String describing the component type of |
|
255 |
* the Java array to create. Can not be null. If undefined, Object is assumed (allowing the argument to be omitted). |
|
256 |
* @return a Java array with the copy of JavaScript array's contents, converted to the appropriate Java component |
|
257 |
* type. Returns null if objArray is null. |
|
258 |
* @throws ClassNotFoundException if the class described by objType is not found |
|
259 |
*/ |
|
260 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
261 |
public static Object toJavaArray(final Object self, final Object objArray, final Object objType) throws ClassNotFoundException { |
|
262 |
final StaticClass componentType = |
|
263 |
objType instanceof StaticClass ? |
|
264 |
(StaticClass)objType : |
|
265 |
objType == UNDEFINED ? |
|
266 |
StaticClass.forClass(Object.class) : |
|
267 |
type(objType); |
|
268 |
||
269 |
if (objArray == null) { |
|
270 |
return null; |
|
271 |
} |
|
272 |
||
273 |
Global.checkObject(objArray); |
|
274 |
||
275 |
return ((ScriptObject)objArray).getArray().asArrayOfType(componentType.getRepresentedClass()); |
|
276 |
} |
|
277 |
||
278 |
/** |
|
279 |
* Given a Java array or {@link Collection}, returns a JavaScript array with a shallow copy of its contents. Note |
|
280 |
* that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you |
|
281 |
* need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will |
|
282 |
* want to use this method. Example: |
|
283 |
* <pre> |
|
284 |
* var File = Java.type("java.io.File") |
|
285 |
* var listHomeDir = new File("~").listFiles() |
|
286 |
* var jsListHome = Java.toJavaScriptArray(listHomeDir) |
|
287 |
* var jpegModifiedDates = jsListHome |
|
288 |
* .filter(function(val) { return val.getName().endsWith(".jpg") }) |
|
289 |
* .map(function(val) { return val.lastModified() }) |
|
290 |
* </pre> |
|
291 |
* @param self not used |
|
292 |
* @param objArray the java array or collection. Can be null. |
|
293 |
* @return a JavaScript array with the copy of Java array's or collection's contents. Returns null if objArray is |
|
294 |
* null. |
|
295 |
*/ |
|
296 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
297 |
public static Object toJavaScriptArray(final Object self, final Object objArray) { |
|
298 |
if (objArray == null) { |
|
299 |
return null; |
|
300 |
} else if (objArray instanceof Collection) { |
|
301 |
return new NativeArray(((Collection<?>)objArray).toArray()); |
|
302 |
} else if (objArray instanceof Object[]) { |
|
303 |
return new NativeArray(((Object[])objArray).clone()); |
|
304 |
} else if (objArray instanceof int[]) { |
|
305 |
return new NativeArray(((int[])objArray).clone()); |
|
306 |
} else if (objArray instanceof double[]) { |
|
307 |
return new NativeArray(((double[])objArray).clone()); |
|
308 |
} else if (objArray instanceof long[]) { |
|
309 |
return new NativeArray(((long[])objArray).clone()); |
|
310 |
} else if (objArray instanceof byte[]) { |
|
311 |
return new NativeArray(copyArray((byte[])objArray)); |
|
312 |
} else if (objArray instanceof short[]) { |
|
313 |
return new NativeArray(copyArray((short[])objArray)); |
|
314 |
} else if (objArray instanceof char[]) { |
|
315 |
return new NativeArray(copyArray((char[])objArray)); |
|
316 |
} else if (objArray instanceof float[]) { |
|
317 |
return new NativeArray(copyArray((float[])objArray)); |
|
318 |
} else if (objArray instanceof boolean[]) { |
|
319 |
return new NativeArray(copyArray((boolean[])objArray)); |
|
320 |
} |
|
321 |
||
16256
f2d9a0c49914
8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents:
16234
diff
changeset
|
322 |
throw typeError("cant.convert.to.javascript.array", objArray.getClass().getName()); |
16147 | 323 |
} |
324 |
||
325 |
private static int[] copyArray(final byte[] in) { |
|
326 |
final int[] out = new int[in.length]; |
|
327 |
for(int i = 0; i < in.length; ++i) { |
|
328 |
out[i] = in[i]; |
|
329 |
} |
|
330 |
return out; |
|
331 |
} |
|
332 |
||
333 |
private static int[] copyArray(final short[] in) { |
|
334 |
final int[] out = new int[in.length]; |
|
335 |
for(int i = 0; i < in.length; ++i) { |
|
336 |
out[i] = in[i]; |
|
337 |
} |
|
338 |
return out; |
|
339 |
} |
|
340 |
||
341 |
private static int[] copyArray(final char[] in) { |
|
342 |
final int[] out = new int[in.length]; |
|
343 |
for(int i = 0; i < in.length; ++i) { |
|
344 |
out[i] = in[i]; |
|
345 |
} |
|
346 |
return out; |
|
347 |
} |
|
348 |
||
349 |
private static double[] copyArray(final float[] in) { |
|
350 |
final double[] out = new double[in.length]; |
|
351 |
for(int i = 0; i < in.length; ++i) { |
|
352 |
out[i] = in[i]; |
|
353 |
} |
|
354 |
return out; |
|
355 |
} |
|
356 |
||
357 |
private static Object[] copyArray(final boolean[] in) { |
|
358 |
final Object[] out = new Object[in.length]; |
|
359 |
for(int i = 0; i < in.length; ++i) { |
|
360 |
out[i] = in[i]; |
|
361 |
} |
|
362 |
return out; |
|
363 |
} |
|
364 |
||
365 |
private static Class<?> simpleType(final String typeName) throws ClassNotFoundException { |
|
366 |
final Class<?> primClass = TypeUtilities.getPrimitiveTypeByName(typeName); |
|
16185 | 367 |
return primClass != null ? primClass : Global.getThisContext().findClass(typeName); |
16147 | 368 |
} |
369 |
||
370 |
private static Class<?> arrayType(final String typeName) throws ClassNotFoundException { |
|
371 |
return Array.newInstance(type(typeName.substring(0, typeName.length() - 2)), 0).getClass(); |
|
372 |
} |
|
373 |
||
374 |
/** |
|
375 |
* Returns a type object for a subclass of the specified Java class (or implementation of the specified interface) |
|
376 |
* that acts as a script-to-Java adapter for it. See {@link #type(Object, Object)} for a discussion of type objects, |
|
377 |
* and see {@link JavaAdapterFactory} for details on script-to-Java adapters. Note that you can also implement |
|
378 |
* interfaces and subclass abstract classes using {@code new} operator on a type object for an interface or abstract |
|
379 |
* class. However, to extend a non-abstract class, you will have to use this method. Example: |
|
380 |
* <pre> |
|
381 |
* var ArrayList = Java.type("java.util.ArrayList") |
|
382 |
* var ArrayListExtender = Java.extend(ArrayList) |
|
383 |
* var printSizeInvokedArrayList = new ArrayListExtender() { |
|
16212
363737d0d757
8007452: add scripting programmers doc changes for nashorn
sundar
parents:
16188
diff
changeset
|
384 |
* size: function() { print("size invoked!"); } |
16147 | 385 |
* } |
386 |
* var printAddInvokedArrayList = new ArrayListExtender() { |
|
16212
363737d0d757
8007452: add scripting programmers doc changes for nashorn
sundar
parents:
16188
diff
changeset
|
387 |
* add: function(x, y) { |
16147 | 388 |
* if(typeof(y) === "undefined") { |
389 |
* print("add(e) invoked!"); |
|
390 |
* } else { |
|
391 |
* print("add(i, e) invoked!"); |
|
392 |
* } |
|
393 |
* } |
|
394 |
* </pre> |
|
395 |
* We can see several important concepts in the above example: |
|
396 |
* <ul> |
|
397 |
* <li>Every Java class will have exactly one extender subclass in Nashorn - repeated invocations of {@code extend} |
|
398 |
* for the same type will yield the same extender type. It's a generic adapter that delegates to whatever JavaScript |
|
399 |
* functions its implementation object has on a per-instance basis.</li> |
|
400 |
* <li>If the Java method is overloaded (as in the above example {@code List.add()}), then your JavaScript adapter |
|
401 |
* must be prepared to deal with all overloads.</li> |
|
402 |
* <li>You can't invoke {@code super.*()} from adapters for now.</li> |
|
16272 | 403 |
* </ul> |
16147 | 404 |
* @param self not used |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
405 |
* @param types the original types. The caller must pass at least one Java type object of class {@link StaticClass} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
406 |
* representing either a public interface or a non-final public class with at least one public or protected |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
407 |
* constructor. If more than one type is specified, at most one can be a class and the rest have to be interfaces. |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
408 |
* Invoking the method twice with exactly the same types in the same order will return the same adapter |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
409 |
* class, any reordering of types or even addition or removal of redundant types (i.e. interfaces that other types |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
410 |
* in the list already implement/extend, or {@code java.lang.Object} in a list of types consisting purely of |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
411 |
* interfaces) will result in a different adapter class, even though those adapter classes are functionally |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
412 |
* identical; we deliberately don't want to incur the additional processing cost of canonicalizing type lists. |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
413 |
* @return a new {@link StaticClass} that represents the adapter for the original types. |
16147 | 414 |
*/ |
415 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
416 |
public static Object extend(final Object self, final Object... types) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
417 |
if(types == null || types.length == 0) { |
16256
f2d9a0c49914
8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents:
16234
diff
changeset
|
418 |
throw typeError("extend.expects.at.least.one.argument"); |
16147 | 419 |
} |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
420 |
final Class<?>[] stypes = new Class<?>[types.length]; |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
421 |
try { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
422 |
for(int i = 0; i < types.length; ++i) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
423 |
stypes[i] = ((StaticClass)types[i]).getRepresentedClass(); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
424 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
425 |
} catch(final ClassCastException e) { |
16256
f2d9a0c49914
8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents:
16234
diff
changeset
|
426 |
throw typeError("extend.expects.java.types"); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
427 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
428 |
return JavaAdapterFactory.getAdapterClassFor(stypes); |
16147 | 429 |
} |
430 |
} |