author | sundar |
Fri, 05 Jul 2013 14:38:04 +0530 | |
changeset 18851 | bdb92c95f886 |
parent 18846 | 4ef5f2321c67 |
child 19627 | 90d910ec15a3 |
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; |
|
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
33 |
import java.util.Deque; |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
34 |
import java.util.List; |
18842
3c3be808b593
8019585: Sometimes a var declaration using itself in its init wasn't declared as canBeUndefined, causing erroneous bytecode
lagergren
parents:
18618
diff
changeset
|
35 |
|
16234
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16233
diff
changeset
|
36 |
import jdk.internal.dynalink.beans.StaticClass; |
86cb162cec6c
8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents:
16233
diff
changeset
|
37 |
import jdk.internal.dynalink.support.TypeUtilities; |
16147 | 38 |
import jdk.nashorn.internal.objects.annotations.Attribute; |
39 |
import jdk.nashorn.internal.objects.annotations.Function; |
|
40 |
import jdk.nashorn.internal.objects.annotations.ScriptClass; |
|
41 |
import jdk.nashorn.internal.objects.annotations.Where; |
|
18846
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
42 |
import jdk.nashorn.internal.runtime.Context; |
16147 | 43 |
import jdk.nashorn.internal.runtime.JSType; |
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
44 |
import jdk.nashorn.internal.runtime.ListAdapter; |
18618
136279c4cbe6
8019157: Avoid calling ScriptObject.setProto() if possible
hannesw
parents:
17765
diff
changeset
|
45 |
import jdk.nashorn.internal.runtime.PropertyMap; |
16147 | 46 |
import jdk.nashorn.internal.runtime.ScriptObject; |
47 |
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; |
|
48 |
||
49 |
/** |
|
50 |
* This class is the implementation for the {@code Java} global object exposed to programs running under Nashorn. This |
|
51 |
* object acts as the API entry point to Java platform specific functionality, dealing with creating new instances of |
|
52 |
* Java classes, subclassing Java classes, implementing Java interfaces, converting between Java arrays and ECMAScript |
|
53 |
* arrays, and so forth. |
|
54 |
*/ |
|
55 |
@ScriptClass("Java") |
|
16226
0e4f37e6cc40
8007915: Nashorn IR, codegen, parser packages and Context instance should be inaccessible to user code
sundar
parents:
16212
diff
changeset
|
56 |
public final class NativeJava { |
16147 | 57 |
|
18618
136279c4cbe6
8019157: Avoid calling ScriptObject.setProto() if possible
hannesw
parents:
17765
diff
changeset
|
58 |
// initialized by nasgen |
18842
3c3be808b593
8019585: Sometimes a var declaration using itself in its init wasn't declared as canBeUndefined, causing erroneous bytecode
lagergren
parents:
18618
diff
changeset
|
59 |
@SuppressWarnings("unused") |
18618
136279c4cbe6
8019157: Avoid calling ScriptObject.setProto() if possible
hannesw
parents:
17765
diff
changeset
|
60 |
private static PropertyMap $nasgenmap$; |
136279c4cbe6
8019157: Avoid calling ScriptObject.setProto() if possible
hannesw
parents:
17765
diff
changeset
|
61 |
|
16147 | 62 |
private NativeJava() { |
18851
bdb92c95f886
8019947: inherited property invalidation does not work with two globals in same context
sundar
parents:
18846
diff
changeset
|
63 |
// don't create me |
bdb92c95f886
8019947: inherited property invalidation does not work with two globals in same context
sundar
parents:
18846
diff
changeset
|
64 |
throw new UnsupportedOperationException(); |
16147 | 65 |
} |
66 |
||
67 |
/** |
|
68 |
* Returns true if the specified object is a Java type object, that is an instance of {@link StaticClass}. |
|
69 |
* @param self not used |
|
70 |
* @param type the object that is checked if it is a type object or not |
|
71 |
* @return tells whether given object is a Java type object or not. |
|
72 |
* @see #type(Object, Object) |
|
73 |
*/ |
|
74 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
75 |
public static Object isType(final Object self, final Object type) { |
|
76 |
return type instanceof StaticClass; |
|
77 |
} |
|
78 |
||
79 |
/** |
|
16272 | 80 |
* <p> |
16147 | 81 |
* Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects |
82 |
* used to represent Java types in Nashorn is not {@link java.lang.Class} but rather {@link StaticClass}. They are |
|
83 |
* the objects that you can use with the {@code new} operator to create new instances of the class as well as to |
|
84 |
* access static members of the class. In Nashorn, {@code Class} objects are just regular Java objects that aren't |
|
85 |
* treated specially. Instead of them, {@link StaticClass} instances - which we sometimes refer to as "Java type |
|
86 |
* objects" are used as constructors with the {@code new} operator, and they expose static fields, properties, and |
|
87 |
* methods. While this might seem confusing at first, it actually closely matches the Java language: you use a |
|
88 |
* different expression (e.g. {@code java.io.File}) as an argument in "new" and to address statics, and it is |
|
89 |
* distinct from the {@code Class} object (e.g. {@code java.io.File.class}). Below we cover in details the |
|
90 |
* properties of the type objects. |
|
16272 | 91 |
* </p> |
92 |
* <p><b>Constructing Java objects</b></p> |
|
16147 | 93 |
* Examples: |
94 |
* <pre> |
|
95 |
* var arrayListType = Java.type("java.util.ArrayList") |
|
96 |
* var intType = Java.type("int") |
|
97 |
* var stringArrayType = Java.type("java.lang.String[]") |
|
98 |
* var int2DArrayType = Java.type("int[][]") |
|
99 |
* </pre> |
|
100 |
* Note that the name of the type is always a string for a fully qualified name. You can use any of these types to |
|
101 |
* create new instances, e.g.: |
|
102 |
* <pre> |
|
103 |
* var anArrayList = new Java.type("java.util.ArrayList") |
|
104 |
* </pre> |
|
105 |
* or |
|
106 |
* <pre> |
|
107 |
* var ArrayList = Java.type("java.util.ArrayList") |
|
108 |
* var anArrayList = new ArrayList |
|
109 |
* var anArrayListWithSize = new ArrayList(16) |
|
110 |
* </pre> |
|
18846
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
111 |
* In the special case of inner classes, you can either use the JVM fully qualified name, meaning using {@code $} |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
112 |
* sign in the class name, or you can use the dot: |
16147 | 113 |
* <pre> |
114 |
* var ftype = Java.type("java.awt.geom.Arc2D$Float") |
|
115 |
* </pre> |
|
18846
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
116 |
* and |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
117 |
* <pre> |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
118 |
* var ftype = Java.type("java.awt.geom.Arc2D.Float") |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
119 |
* </pre> |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
120 |
* both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
121 |
* as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
122 |
* dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
123 |
* dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
124 |
* the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
125 |
* inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
126 |
* alternative way to access the inner class is as a property of the outer class: |
16147 | 127 |
* <pre> |
128 |
* var arctype = Java.type("java.awt.geom.Arc2D") |
|
129 |
* var ftype = arctype.Float |
|
130 |
* </pre> |
|
16272 | 131 |
* <p> |
16147 | 132 |
* You can access both static and non-static inner classes. If you want to create an instance of a non-static |
133 |
* inner class, remember to pass an instance of its outer class as the first argument to the constructor. |
|
16272 | 134 |
* </p> |
135 |
* <p> |
|
16147 | 136 |
* If the type is abstract, you can instantiate an anonymous subclass of it using an argument list that is |
137 |
* applicable to any of its public or protected constructors, but inserting a JavaScript object with functions |
|
138 |
* properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the |
|
139 |
* JavaScript function will provide implementation for all overloads. E.g.: |
|
16272 | 140 |
* </p> |
16147 | 141 |
* <pre> |
142 |
* var TimerTask = Java.type("java.util.TimerTask") |
|
143 |
* var task = new TimerTask({ run: function() { print("Hello World!") } }) |
|
144 |
* </pre> |
|
16272 | 145 |
* <p> |
16147 | 146 |
* Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to |
147 |
* invoking the constructor and passing the argument to it, so you can write the above example also as: |
|
16272 | 148 |
* </p> |
16147 | 149 |
* <pre> |
150 |
* var task = new TimerTask { |
|
151 |
* run: function() { |
|
152 |
* print("Hello World!") |
|
153 |
* } |
|
154 |
* } |
|
155 |
* </pre> |
|
16272 | 156 |
* <p> |
16147 | 157 |
* which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract |
158 |
* type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share |
|
159 |
* the same overloaded name), then instead of an object, you can just pass a function, so the above example can |
|
160 |
* become even more simplified to: |
|
16272 | 161 |
* </p> |
16147 | 162 |
* <pre> |
163 |
* var task = new TimerTask(function() { print("Hello World!") }) |
|
164 |
* </pre> |
|
16272 | 165 |
* <p> |
16147 | 166 |
* Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors |
167 |
* that take some arguments, you can invoke those simply by specifying the arguments after the initial |
|
168 |
* implementation object or function. |
|
16272 | 169 |
* </p> |
170 |
* <p>The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, |
|
16147 | 171 |
* you can just pass in a function object, and Nashorn will know what you meant: |
16272 | 172 |
* </p> |
16147 | 173 |
* <pre> |
174 |
* var timer = new Java.type("java.util.Timer") |
|
175 |
* timer.schedule(function() { print("Hello World!") }) |
|
176 |
* </pre> |
|
16272 | 177 |
* <p> |
16147 | 178 |
* Here, {@code Timer.schedule()} expects a {@code TimerTask} as its argument, so Nashorn creates an instance of a |
179 |
* {@code TimerTask} subclass and uses the passed function to implement its only abstract method, {@code run()}. In |
|
180 |
* this usage though, you can't use non-default constructors; the type must be either an interface, or must have a |
|
181 |
* protected or public no-arg constructor. |
|
16272 | 182 |
* </p> |
183 |
* <p> |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
184 |
* You can also subclass non-abstract classes; for that you will need to use the {@link #extend(Object, Object...)} |
16147 | 185 |
* method. |
16272 | 186 |
* </p> |
187 |
* <p><b>Accessing static members</b></p> |
|
16147 | 188 |
* Examples: |
189 |
* <pre> |
|
190 |
* var File = Java.type("java.io.File") |
|
191 |
* var pathSep = File.pathSeparator |
|
192 |
* var tmpFile1 = File.createTempFile("abcdefg", ".tmp") |
|
193 |
* var tmpFile2 = File.createTempFile("abcdefg", ".tmp", new File("/tmp")) |
|
194 |
* </pre> |
|
195 |
* Actually, you can even assign static methods to variables, so the above example can be rewritten as: |
|
196 |
* <pre> |
|
197 |
* var File = Java.type("java.io.File") |
|
198 |
* var createTempFile = File.createTempFile |
|
199 |
* var tmpFile1 = createTempFile("abcdefg", ".tmp") |
|
200 |
* var tmpFile2 = createTempFile("abcdefg", ".tmp", new File("/tmp")) |
|
201 |
* </pre> |
|
202 |
* If you need to access the actual {@code java.lang.Class} object for the type, you can use the {@code class} |
|
203 |
* property on the object representing the type: |
|
204 |
* <pre> |
|
205 |
* var File = Java.type("java.io.File") |
|
206 |
* var someFile = new File("blah") |
|
207 |
* print(File.class === someFile.getClass()) // prints true |
|
208 |
* </pre> |
|
209 |
* Of course, you can also use the {@code getClass()} method or its equivalent {@code class} property on any |
|
210 |
* instance of the class. Other way round, you can use the synthetic {@code static} property on any |
|
211 |
* {@code java.lang.Class} object to retrieve its type-representing object: |
|
212 |
* <pre> |
|
213 |
* var File = Java.type("java.io.File") |
|
214 |
* print(File.class.static === File) // prints true |
|
215 |
* </pre> |
|
16272 | 216 |
* <p><b>{@code instanceof} operator</b></p> |
16147 | 217 |
* The standard ECMAScript {@code instanceof} operator is extended to recognize Java objects and their type objects: |
218 |
* <pre> |
|
219 |
* var File = Java.type("java.io.File") |
|
220 |
* var aFile = new File("foo") |
|
221 |
* print(aFile instanceof File) // prints true |
|
222 |
* print(aFile instanceof File.class) // prints false - Class objects aren't type objects. |
|
223 |
* </pre> |
|
224 |
* @param self not used |
|
225 |
* @param objTypeName the object whose JS string value represents the type name. You can use names of primitive Java |
|
226 |
* types to obtain representations of them, and you can use trailing square brackets to represent Java array types. |
|
227 |
* @return the object representing the named type |
|
228 |
* @throws ClassNotFoundException if the class is not found |
|
229 |
*/ |
|
230 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
231 |
public static Object type(final Object self, final Object objTypeName) throws ClassNotFoundException { |
|
232 |
return type(objTypeName); |
|
233 |
} |
|
234 |
||
235 |
private static StaticClass type(final Object objTypeName) throws ClassNotFoundException { |
|
236 |
return StaticClass.forClass(type(JSType.toString(objTypeName))); |
|
237 |
} |
|
238 |
||
239 |
private static Class<?> type(final String typeName) throws ClassNotFoundException { |
|
240 |
if (typeName.endsWith("[]")) { |
|
241 |
return arrayType(typeName); |
|
242 |
} |
|
243 |
||
244 |
return simpleType(typeName); |
|
245 |
} |
|
246 |
||
247 |
/** |
|
16522 | 248 |
* Returns name of a java type {@link StaticClass}. |
249 |
* @param self not used |
|
250 |
* @param type the type whose name is returned |
|
251 |
* @return name of the given type |
|
252 |
*/ |
|
253 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
254 |
public static Object typeName(final Object self, final Object type) { |
|
255 |
if (type instanceof StaticClass) { |
|
256 |
return ((StaticClass)type).getRepresentedClass().getName(); |
|
257 |
} else if (type instanceof Class) { |
|
258 |
return ((Class<?>)type).getName(); |
|
259 |
} else { |
|
260 |
return UNDEFINED; |
|
261 |
} |
|
262 |
} |
|
263 |
||
264 |
/** |
|
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
265 |
* Given a script object and a Java type, converts the script object into the desired Java type. Currently it |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
266 |
* performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example: |
16147 | 267 |
* <pre> |
268 |
* var anArray = [1, "13", false] |
|
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
269 |
* var javaIntArray = Java.to(anArray, "int[]") |
16147 | 270 |
* print(javaIntArray[0]) // prints 1 |
271 |
* print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion |
|
272 |
* print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion |
|
273 |
* </pre> |
|
274 |
* @param self not used |
|
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
275 |
* @param obj the script object. Can be null. |
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
276 |
* @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java |
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
277 |
* object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be |
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
278 |
* omitted). |
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
279 |
* @return a Java object whose value corresponds to the original script object's value. Specifically, for array |
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
280 |
* target types, returns a Java array of the same type with contents converted to the array's component type. Does |
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
281 |
* not recursively convert for multidimensional arrays. For {@link List} or {@link Deque}, returns a live wrapper |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
282 |
* around the object, see {@link ListAdapter} for details. Returns null if obj is null. |
16147 | 283 |
* @throws ClassNotFoundException if the class described by objType is not found |
284 |
*/ |
|
285 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
286 |
public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException { |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
287 |
if (obj == null) { |
16147 | 288 |
return null; |
289 |
} |
|
290 |
||
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
291 |
Global.checkObject(obj); |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
292 |
|
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
293 |
final Class<?> targetClass; |
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
294 |
if(objType == UNDEFINED) { |
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
295 |
targetClass = Object[].class; |
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
296 |
} else { |
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
297 |
final StaticClass targetType; |
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
298 |
if(objType instanceof StaticClass) { |
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
299 |
targetType = (StaticClass)objType; |
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
300 |
} else { |
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
301 |
targetType = type(objType); |
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
302 |
} |
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
303 |
targetClass = targetType.getRepresentedClass(); |
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
304 |
} |
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
305 |
|
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
306 |
if(targetClass.isArray()) { |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
307 |
return ((ScriptObject)obj).getArray().asArrayOfType(targetClass.getComponentType()); |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
308 |
} |
16147 | 309 |
|
17765
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
310 |
if(targetClass == List.class || targetClass == Deque.class) { |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
311 |
return new ListAdapter((ScriptObject)obj); |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
312 |
} |
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
313 |
|
6b45f57bebc4
8015267: Allow conversion of JS arrays to Java List/Deque
attila
parents:
17758
diff
changeset
|
314 |
throw typeError("unsupported.java.to.type", targetClass.getName()); |
16147 | 315 |
} |
316 |
||
317 |
/** |
|
318 |
* Given a Java array or {@link Collection}, returns a JavaScript array with a shallow copy of its contents. Note |
|
319 |
* that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you |
|
320 |
* need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will |
|
321 |
* want to use this method. Example: |
|
322 |
* <pre> |
|
323 |
* var File = Java.type("java.io.File") |
|
324 |
* var listHomeDir = new File("~").listFiles() |
|
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
325 |
* var jsListHome = Java.from(listHomeDir) |
16147 | 326 |
* var jpegModifiedDates = jsListHome |
327 |
* .filter(function(val) { return val.getName().endsWith(".jpg") }) |
|
328 |
* .map(function(val) { return val.lastModified() }) |
|
329 |
* </pre> |
|
330 |
* @param self not used |
|
331 |
* @param objArray the java array or collection. Can be null. |
|
332 |
* @return a JavaScript array with the copy of Java array's or collection's contents. Returns null if objArray is |
|
333 |
* null. |
|
334 |
*/ |
|
335 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
17758
2b056941e4dd
8014797: rename Java.toJavaArray/toJavaScriptArray to Java.to/from, respectively.
attila
parents:
16777
diff
changeset
|
336 |
public static Object from(final Object self, final Object objArray) { |
16147 | 337 |
if (objArray == null) { |
338 |
return null; |
|
339 |
} else if (objArray instanceof Collection) { |
|
340 |
return new NativeArray(((Collection<?>)objArray).toArray()); |
|
341 |
} else if (objArray instanceof Object[]) { |
|
342 |
return new NativeArray(((Object[])objArray).clone()); |
|
343 |
} else if (objArray instanceof int[]) { |
|
344 |
return new NativeArray(((int[])objArray).clone()); |
|
345 |
} else if (objArray instanceof double[]) { |
|
346 |
return new NativeArray(((double[])objArray).clone()); |
|
347 |
} else if (objArray instanceof long[]) { |
|
348 |
return new NativeArray(((long[])objArray).clone()); |
|
349 |
} else if (objArray instanceof byte[]) { |
|
350 |
return new NativeArray(copyArray((byte[])objArray)); |
|
351 |
} else if (objArray instanceof short[]) { |
|
352 |
return new NativeArray(copyArray((short[])objArray)); |
|
353 |
} else if (objArray instanceof char[]) { |
|
354 |
return new NativeArray(copyArray((char[])objArray)); |
|
355 |
} else if (objArray instanceof float[]) { |
|
356 |
return new NativeArray(copyArray((float[])objArray)); |
|
357 |
} else if (objArray instanceof boolean[]) { |
|
358 |
return new NativeArray(copyArray((boolean[])objArray)); |
|
359 |
} |
|
360 |
||
16256
f2d9a0c49914
8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents:
16234
diff
changeset
|
361 |
throw typeError("cant.convert.to.javascript.array", objArray.getClass().getName()); |
16147 | 362 |
} |
363 |
||
364 |
private static int[] copyArray(final byte[] in) { |
|
365 |
final int[] out = new int[in.length]; |
|
366 |
for(int i = 0; i < in.length; ++i) { |
|
367 |
out[i] = in[i]; |
|
368 |
} |
|
369 |
return out; |
|
370 |
} |
|
371 |
||
372 |
private static int[] copyArray(final short[] in) { |
|
373 |
final int[] out = new int[in.length]; |
|
374 |
for(int i = 0; i < in.length; ++i) { |
|
375 |
out[i] = in[i]; |
|
376 |
} |
|
377 |
return out; |
|
378 |
} |
|
379 |
||
380 |
private static int[] copyArray(final char[] in) { |
|
381 |
final int[] out = new int[in.length]; |
|
382 |
for(int i = 0; i < in.length; ++i) { |
|
383 |
out[i] = in[i]; |
|
384 |
} |
|
385 |
return out; |
|
386 |
} |
|
387 |
||
388 |
private static double[] copyArray(final float[] in) { |
|
389 |
final double[] out = new double[in.length]; |
|
390 |
for(int i = 0; i < in.length; ++i) { |
|
391 |
out[i] = in[i]; |
|
392 |
} |
|
393 |
return out; |
|
394 |
} |
|
395 |
||
396 |
private static Object[] copyArray(final boolean[] in) { |
|
397 |
final Object[] out = new Object[in.length]; |
|
398 |
for(int i = 0; i < in.length; ++i) { |
|
399 |
out[i] = in[i]; |
|
400 |
} |
|
401 |
return out; |
|
402 |
} |
|
403 |
||
404 |
private static Class<?> simpleType(final String typeName) throws ClassNotFoundException { |
|
405 |
final Class<?> primClass = TypeUtilities.getPrimitiveTypeByName(typeName); |
|
18846
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
406 |
if(primClass != null) { |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
407 |
return primClass; |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
408 |
} |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
409 |
final Context ctx = Global.getThisContext(); |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
410 |
try { |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
411 |
return ctx.findClass(typeName); |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
412 |
} catch(ClassNotFoundException e) { |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
413 |
// The logic below compensates for a frequent user error - when people use dot notation to separate inner |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
414 |
// class names, i.e. "java.lang.Character.UnicodeBlock" vs."java.lang.Character$UnicodeBlock". The logic |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
415 |
// below will try alternative class names, replacing dots at the end of the name with dollar signs. |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
416 |
final StringBuilder nextName = new StringBuilder(typeName); |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
417 |
int lastDot = nextName.length(); |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
418 |
for(;;) { |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
419 |
lastDot = nextName.lastIndexOf(".", lastDot - 1); |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
420 |
if(lastDot == -1) { |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
421 |
// Exhausted the search space, class not found - rethrow the original exception. |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
422 |
throw e; |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
423 |
} |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
424 |
nextName.setCharAt(lastDot, '$'); |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
425 |
try { |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
426 |
return ctx.findClass(nextName.toString()); |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
427 |
} catch(ClassNotFoundException cnfe) { |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
428 |
// Intentionally ignored, so the loop retries with the next name |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
429 |
} |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
430 |
} |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
431 |
} |
4ef5f2321c67
8017768: allow dot as inner class name separator for Java.type
attila
parents:
18842
diff
changeset
|
432 |
|
16147 | 433 |
} |
434 |
||
435 |
private static Class<?> arrayType(final String typeName) throws ClassNotFoundException { |
|
436 |
return Array.newInstance(type(typeName.substring(0, typeName.length() - 2)), 0).getClass(); |
|
437 |
} |
|
438 |
||
439 |
/** |
|
440 |
* Returns a type object for a subclass of the specified Java class (or implementation of the specified interface) |
|
441 |
* that acts as a script-to-Java adapter for it. See {@link #type(Object, Object)} for a discussion of type objects, |
|
442 |
* and see {@link JavaAdapterFactory} for details on script-to-Java adapters. Note that you can also implement |
|
443 |
* interfaces and subclass abstract classes using {@code new} operator on a type object for an interface or abstract |
|
444 |
* class. However, to extend a non-abstract class, you will have to use this method. Example: |
|
445 |
* <pre> |
|
446 |
* var ArrayList = Java.type("java.util.ArrayList") |
|
447 |
* var ArrayListExtender = Java.extend(ArrayList) |
|
448 |
* var printSizeInvokedArrayList = new ArrayListExtender() { |
|
16212
363737d0d757
8007452: add scripting programmers doc changes for nashorn
sundar
parents:
16188
diff
changeset
|
449 |
* size: function() { print("size invoked!"); } |
16147 | 450 |
* } |
451 |
* var printAddInvokedArrayList = new ArrayListExtender() { |
|
16212
363737d0d757
8007452: add scripting programmers doc changes for nashorn
sundar
parents:
16188
diff
changeset
|
452 |
* add: function(x, y) { |
16147 | 453 |
* if(typeof(y) === "undefined") { |
454 |
* print("add(e) invoked!"); |
|
455 |
* } else { |
|
456 |
* print("add(i, e) invoked!"); |
|
457 |
* } |
|
458 |
* } |
|
459 |
* </pre> |
|
460 |
* We can see several important concepts in the above example: |
|
461 |
* <ul> |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
462 |
* <li>Every specified list of Java types will have exactly one extender subclass in Nashorn - repeated invocations |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
463 |
* of {@code extend} for the same list of types will yield the same extender type. It's a generic adapter that |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
464 |
* delegates to whatever JavaScript functions its implementation object has on a per-instance basis.</li> |
16147 | 465 |
* <li>If the Java method is overloaded (as in the above example {@code List.add()}), then your JavaScript adapter |
466 |
* must be prepared to deal with all overloads.</li> |
|
467 |
* <li>You can't invoke {@code super.*()} from adapters for now.</li> |
|
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
468 |
* <li>It is also possible to specify an ordinary JavaScript object as the last argument to {@code extend}. In that |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
469 |
* case, it is treated as a class-level override. {@code extend} will return an extender class where all instances |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
470 |
* will have the methods implemented by functions on that object, just as if that object were passed as the last |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
471 |
* argument to their constructor. Example: |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
472 |
* <pre> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
473 |
* var Runnable = Java.type("java.lang.Runnable") |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
474 |
* var R1 = Java.extend(Runnable, { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
475 |
* run: function() { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
476 |
* print("R1.run() invoked!") |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
477 |
* } |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
478 |
* }) |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
479 |
* var r1 = new R1 |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
480 |
* var t = new java.lang.Thread(r1) |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
481 |
* t.start() |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
482 |
* t.join() |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
483 |
* </pre> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
484 |
* As you can see, you don't have to pass any object when you create a new instance of {@code R1} as its |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
485 |
* {@code run()} function was defined already when extending the class. Of course, you can still provide |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
486 |
* instance-level overrides on these objects. The order of precedence is instance-level method, class-level method, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
487 |
* superclass method, or {@code UnsupportedOperationException} if the superclass method is abstract. If we continue |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
488 |
* our previous example: |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
489 |
* <pre> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
490 |
* var r2 = new R1(function() { print("r2.run() invoked!") }) |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
491 |
* r2.run() |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
492 |
* </pre> |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
493 |
* We'll see it'll print {@code "r2.run() invoked!"}, thus overriding on instance-level the class-level behavior. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
494 |
* </li> |
16272 | 495 |
* </ul> |
16147 | 496 |
* @param self not used |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
497 |
* @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
|
498 |
* 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
|
499 |
* constructor. If more than one type is specified, at most one can be a class and the rest have to be interfaces. |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
500 |
* Invoking the method twice with exactly the same types in the same order - in absence of class-level overrides - |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
501 |
* will return the same adapter class, any reordering of types or even addition or removal of redundant types (i.e. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
502 |
* interfaces that other types in the list already implement/extend, or {@code java.lang.Object} in a list of types |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
503 |
* consisting purely of interfaces) will result in a different adapter class, even though those adapter classes are |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
504 |
* functionally identical; we deliberately don't want to incur the additional processing cost of canonicalizing type |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
505 |
* lists. As a special case, the last argument can be a {@code ScriptObject} instead of a type. In this case, a |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
506 |
* separate adapter class is generated - new one for each invocation - that will use the passed script object as its |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
507 |
* implementation for all instances. Instances of such adapter classes can then be created without passing another |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
508 |
* script object in the constructor, as the class has a class-level behavior defined by the script object. However, |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
509 |
* you can still pass a script object (or if it's a SAM type, a function) to the constructor to provide further |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
510 |
* instance-level overrides. |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
511 |
* |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
512 |
* @return a new {@link StaticClass} that represents the adapter for the original types. |
16147 | 513 |
*/ |
514 |
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) |
|
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
515 |
public static Object extend(final Object self, final Object... types) { |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
516 |
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
|
517 |
throw typeError("extend.expects.at.least.one.argument"); |
16147 | 518 |
} |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
519 |
final int l = types.length; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
520 |
final int typesLen; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
521 |
final ScriptObject classOverrides; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
522 |
if(types[l - 1] instanceof ScriptObject) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
523 |
classOverrides = (ScriptObject)types[l - 1]; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
524 |
typesLen = l - 1; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
525 |
if(typesLen == 0) { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
526 |
throw typeError("extend.expects.at.least.one.type.argument"); |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
527 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
528 |
} else { |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
529 |
classOverrides = null; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
530 |
typesLen = l; |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
531 |
} |
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
532 |
final Class<?>[] stypes = new Class<?>[typesLen]; |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
533 |
try { |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
534 |
for(int i = 0; i < typesLen; ++i) { |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
535 |
stypes[i] = ((StaticClass)types[i]).getRepresentedClass(); |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
536 |
} |
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
537 |
} 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
|
538 |
throw typeError("extend.expects.java.types"); |
16171
90dcd4fc42f0
8006168: ability to generate multi-type Java adapters
attila
parents:
16151
diff
changeset
|
539 |
} |
16777
207a993adb9a
8011544: Allow subclassing Java classes from script without creating instances
attila
parents:
16522
diff
changeset
|
540 |
return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides); |
16147 | 541 |
} |
542 |
} |