1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
\r
3 * The contents of this file are subject to the Netscape Public
\r
4 * License Version 1.1 (the "License"); you may not use this file
\r
5 * except in compliance with the License. You may obtain a copy of
\r
6 * the License at http://www.mozilla.org/NPL/
\r
8 * Software distributed under the License is distributed on an "AS
\r
9 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
\r
10 * implied. See the License for the specific language governing
\r
11 * rights and limitations under the License.
\r
13 * The Original Code is Rhino code, released
\r
16 * The Initial Developer of the Original Code is Netscape
\r
17 * Communications Corporation. Portions created by Netscape are
\r
18 * Copyright (C) 1997-2000 Netscape Communications Corporation. All
\r
27 * Alternatively, the contents of this file may be used under the
\r
28 * terms of the GNU Public License (the "GPL"), in which case the
\r
29 * provisions of the GPL are applicable instead of those above.
\r
30 * If you wish to allow use of your version of this file only
\r
31 * under the terms of the GPL and not to allow others to use your
\r
32 * version of this file under the NPL, indicate your decision by
\r
33 * deleting the provisions above and replace them with the notice
\r
34 * and other provisions required by the GPL. If you do not delete
\r
35 * the provisions above, a recipient may use your version of this
\r
36 * file under either the NPL or the GPL.
\r
39 package org.mozilla.javascript;
\r
41 import java.lang.reflect.*;
\r
42 import java.util.Hashtable;
\r
43 import java.util.Enumeration;
\r
46 * This class reflects non-Array Java objects into the JavaScript environment. It
\r
47 * reflect fields directly, and uses NativeJavaMethod objects to reflect (possibly
\r
48 * overloaded) methods.<p>
\r
50 * @author Mike Shaver
\r
51 * @see NativeJavaArray
\r
52 * @see NativeJavaPackage
\r
53 * @see NativeJavaClass
\r
56 public class NativeJavaObject implements Scriptable, Wrapper {
\r
58 public NativeJavaObject(Scriptable scope, Object javaObject,
\r
59 JavaMembers members)
\r
61 this.parent = scope;
\r
62 this.javaObject = javaObject;
\r
63 this.members = members;
\r
66 public NativeJavaObject(Scriptable scope, Object javaObject,
\r
69 this.parent = scope;
\r
70 this.javaObject = javaObject;
\r
71 Class dynamicType = javaObject != null ? javaObject.getClass()
\r
73 members = JavaMembers.lookupClass(scope, dynamicType, staticType);
\r
74 fieldAndMethods = members.getFieldAndMethodsObjects(this, javaObject, false);
\r
77 public boolean has(String name, Scriptable start) {
\r
78 return members.has(name, false);
\r
81 public boolean has(int index, Scriptable start) {
\r
85 public Object get(String name, Scriptable start) {
\r
86 if (fieldAndMethods != null) {
\r
87 Object result = fieldAndMethods.get(name);
\r
88 if (result != null) {
\r
92 // TODO: passing 'this' as the scope is bogus since it has
\r
94 return members.get(this, name, javaObject, false);
\r
97 public Object get(int index, Scriptable start) {
\r
98 throw members.reportMemberNotFound(Integer.toString(index));
\r
101 public void put(String name, Scriptable start, Object value) {
\r
102 // We could be asked to modify the value of a property in the
\r
103 // prototype. Since we can't add a property to a Java object,
\r
104 // we modify it in the prototype rather than copy it down.
\r
105 if (prototype == null || members.has(name, false))
\r
106 members.put(this, name, javaObject, value, false);
\r
108 prototype.put(name, prototype, value);
\r
111 public void put(int index, Scriptable start, Object value) {
\r
112 throw members.reportMemberNotFound(Integer.toString(index));
\r
115 public boolean hasInstance(Scriptable value) {
\r
116 // This is an instance of a Java class, so always return false
\r
120 public void delete(String name) {
\r
123 public void delete(int index) {
\r
126 public Scriptable getPrototype() {
\r
127 if (prototype == null && javaObject.getClass() == ScriptRuntime.StringClass) {
\r
128 return ScriptableObject.getClassPrototype(parent, "String");
\r
134 * Sets the prototype of the object.
\r
136 public void setPrototype(Scriptable m) {
\r
141 * Returns the parent (enclosing) scope of the object.
\r
143 public Scriptable getParentScope() {
\r
148 * Sets the parent (enclosing) scope of the object.
\r
150 public void setParentScope(Scriptable m) {
\r
154 public Object[] getIds() {
\r
155 return members.getIds(false);
\r
158 public static Object wrap(Scriptable scope, Object obj, Class staticType)
\r
162 Context cx = Context.getCurrentContext();
\r
163 if (cx != null && cx.wrapHandler != null) {
\r
164 Object result = cx.wrapHandler.wrap(scope, obj, staticType);
\r
165 if (result != null)
\r
168 Class cls = obj.getClass();
\r
169 if (staticType != null && staticType.isPrimitive()) {
\r
170 if (staticType == Void.TYPE)
\r
171 return Undefined.instance;
\r
172 if (staticType == Character.TYPE)
\r
173 return new Integer((int) ((Character) obj).charValue());
\r
177 return NativeJavaArray.wrap(scope, obj);
\r
178 if (obj instanceof Scriptable)
\r
180 if (Context.useJSObject && jsObjectClass != null &&
\r
181 staticType != jsObjectClass && jsObjectClass.isInstance(obj))
\r
184 return jsObjectGetScriptable.invoke(obj, ScriptRuntime.emptyArgs);
\r
186 catch (InvocationTargetException e) {
\r
187 // Just abandon conversion from JSObject
\r
189 catch (IllegalAccessException e) {
\r
190 // Just abandon conversion from JSObject
\r
193 return new NativeJavaObject(scope, obj, staticType);
\r
196 public Object unwrap() {
\r
200 public String getClassName() {
\r
201 return "JavaObject";
\r
204 Function getConverter(String converterName) {
\r
205 Object converterFunction = get(converterName, this);
\r
206 if (converterFunction instanceof Function) {
\r
207 return (Function) converterFunction;
\r
212 Object callConverter(Function converterFunction)
\r
213 throws JavaScriptException
\r
215 Function f = (Function) converterFunction;
\r
216 return f.call(Context.getContext(), f.getParentScope(),
\r
217 this, ScriptRuntime.emptyArgs);
\r
220 Object callConverter(String converterName)
\r
221 throws JavaScriptException
\r
223 Function converter = getConverter(converterName);
\r
224 if (converter == null) {
\r
225 return javaObject.toString();
\r
227 return callConverter(converter);
\r
230 public Object getDefaultValue(Class hint) {
\r
231 if (hint == null || hint == ScriptRuntime.StringClass)
\r
232 return javaObject.toString();
\r
234 if (hint == ScriptRuntime.BooleanClass)
\r
235 return callConverter("booleanValue");
\r
236 if (hint == ScriptRuntime.NumberClass) {
\r
237 return callConverter("doubleValue");
\r
239 // fall through to error message
\r
240 } catch (JavaScriptException jse) {
\r
241 // fall through to error message
\r
243 throw Context.reportRuntimeError0("msg.default.value");
\r
248 * Determine whether we can/should convert between the given type and the
\r
249 * desired one. This should be superceded by a conversion-cost calculation
\r
250 * function, but for now I'll hide behind precedent.
\r
252 public static boolean canConvert(Object fromObj, Class to) {
\r
253 int weight = NativeJavaObject.getConversionWeight(fromObj, to);
\r
255 return (weight < CONVERSION_NONE);
\r
258 static final int JSTYPE_UNDEFINED = 0; // undefined type
\r
259 static final int JSTYPE_NULL = 1; // null
\r
260 static final int JSTYPE_BOOLEAN = 2; // boolean
\r
261 static final int JSTYPE_NUMBER = 3; // number
\r
262 static final int JSTYPE_STRING = 4; // string
\r
263 static final int JSTYPE_JAVA_CLASS = 5; // JavaClass
\r
264 static final int JSTYPE_JAVA_OBJECT = 6; // JavaObject
\r
265 static final int JSTYPE_JAVA_ARRAY = 7; // JavaArray
\r
266 static final int JSTYPE_OBJECT = 8; // Scriptable
\r
268 public static final byte CONVERSION_TRIVIAL = 1;
\r
269 public static final byte CONVERSION_NONTRIVIAL = 0;
\r
270 public static final byte CONVERSION_NONE = 99;
\r
273 * Derive a ranking based on how "natural" the conversion is.
\r
274 * The special value CONVERSION_NONE means no conversion is possible,
\r
275 * and CONVERSION_NONTRIVIAL signals that more type conformance testing
\r
278 * <a href="http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html">
\r
279 * "preferred method conversions" from Live Connect 3</a>
\r
281 public static int getConversionWeight(Object fromObj, Class to) {
\r
282 int fromCode = NativeJavaObject.getJSTypeCode(fromObj);
\r
284 int result = CONVERSION_NONE;
\r
286 switch (fromCode) {
\r
288 case JSTYPE_UNDEFINED:
\r
289 if (to == ScriptRuntime.StringClass ||
\r
290 to == ScriptRuntime.ObjectClass) {
\r
296 if (!to.isPrimitive()) {
\r
301 case JSTYPE_BOOLEAN:
\r
303 if (to == Boolean.TYPE) {
\r
306 else if (to == ScriptRuntime.BooleanClass) {
\r
309 else if (to == ScriptRuntime.ObjectClass) {
\r
312 else if (to == ScriptRuntime.StringClass) {
\r
317 case JSTYPE_NUMBER:
\r
318 if (to.isPrimitive()) {
\r
319 if (to == Double.TYPE) {
\r
322 else if (to != Boolean.TYPE) {
\r
323 result = 1 + NativeJavaObject.getSizeRank(to);
\r
327 if (to == ScriptRuntime.StringClass) {
\r
328 // native numbers are #1-8
\r
331 else if (to == ScriptRuntime.ObjectClass) {
\r
334 else if (ScriptRuntime.NumberClass.isAssignableFrom(to)) {
\r
341 case JSTYPE_STRING:
\r
342 if (to == ScriptRuntime.StringClass) {
\r
345 else if (to == ScriptRuntime.ObjectClass) {
\r
348 else if (to.isPrimitive() && to != Boolean.TYPE) {
\r
349 if (to == Character.TYPE) {
\r
358 case JSTYPE_JAVA_CLASS:
\r
359 if (to == ScriptRuntime.ClassClass) {
\r
362 else if (Context.useJSObject && jsObjectClass != null &&
\r
363 jsObjectClass.isAssignableFrom(to)) {
\r
366 else if (to == ScriptRuntime.ObjectClass) {
\r
369 else if (to == ScriptRuntime.StringClass) {
\r
374 case JSTYPE_JAVA_OBJECT:
\r
375 case JSTYPE_JAVA_ARRAY:
\r
376 if (to == ScriptRuntime.StringClass) {
\r
379 else if (to.isPrimitive() && to != Boolean.TYPE) {
\r
381 (fromCode == JSTYPE_JAVA_ARRAY) ?
\r
382 CONVERSION_NONTRIVIAL :
\r
383 2 + NativeJavaObject.getSizeRank(to);
\r
386 Object javaObj = fromObj;
\r
387 if (javaObj instanceof Wrapper) {
\r
388 javaObj = ((Wrapper)javaObj).unwrap();
\r
390 if (to.isInstance(javaObj)) {
\r
391 result = CONVERSION_NONTRIVIAL;
\r
396 case JSTYPE_OBJECT:
\r
397 // Other objects takes #1-#3 spots
\r
398 if (Context.useJSObject && jsObjectClass != null &&
\r
399 jsObjectClass.isAssignableFrom(to)) {
\r
402 else if (fromObj instanceof NativeArray && to.isArray()) {
\r
403 // This is a native array conversion to a java array
\r
404 // Array conversions are all equal, and preferable to object
\r
405 // and string conversion, per LC3.
\r
408 else if (to == ScriptRuntime.ObjectClass) {
\r
411 else if (to == ScriptRuntime.StringClass) {
\r
414 else if (to.isPrimitive() || to != Boolean.TYPE) {
\r
415 result = 3 + NativeJavaObject.getSizeRank(to);
\r
424 static int getSizeRank(Class aType) {
\r
425 if (aType == Double.TYPE) {
\r
428 else if (aType == Float.TYPE) {
\r
431 else if (aType == Long.TYPE) {
\r
434 else if (aType == Integer.TYPE) {
\r
437 else if (aType == Short.TYPE) {
\r
440 else if (aType == Character.TYPE) {
\r
443 else if (aType == Byte.TYPE) {
\r
446 else if (aType == Boolean.TYPE) {
\r
447 return CONVERSION_NONE;
\r
454 static int getJSTypeCode(Object value) {
\r
455 if (value == null) {
\r
456 return JSTYPE_NULL;
\r
458 else if (value == Undefined.instance) {
\r
459 return JSTYPE_UNDEFINED;
\r
461 else if (value instanceof Scriptable) {
\r
462 if (value instanceof NativeJavaClass) {
\r
463 return JSTYPE_JAVA_CLASS;
\r
465 else if (value instanceof NativeJavaArray) {
\r
466 return JSTYPE_JAVA_ARRAY;
\r
468 else if (value instanceof NativeJavaObject) {
\r
469 return JSTYPE_JAVA_OBJECT;
\r
472 return JSTYPE_OBJECT;
\r
476 Class valueClass = value.getClass();
\r
478 if (valueClass == ScriptRuntime.StringClass) {
\r
479 return JSTYPE_STRING;
\r
481 else if (valueClass == ScriptRuntime.BooleanClass) {
\r
482 return JSTYPE_BOOLEAN;
\r
484 else if (value instanceof Number) {
\r
485 return JSTYPE_NUMBER;
\r
487 else if (valueClass == ScriptRuntime.ClassClass) {
\r
488 return JSTYPE_JAVA_CLASS;
\r
490 else if (valueClass.isArray()) {
\r
491 return JSTYPE_JAVA_ARRAY;
\r
494 return JSTYPE_JAVA_OBJECT;
\r
500 * Type-munging for field setting and method invocation.
\r
501 * Conforms to LC3 specification
\r
503 public static Object coerceType(Class type, Object value) {
\r
504 if (value != null && value.getClass() == type) {
\r
508 switch (NativeJavaObject.getJSTypeCode(value)) {
\r
511 // raise error if type.isPrimitive()
\r
512 if (type.isPrimitive()) {
\r
513 reportConversionError(value, type);
\r
517 case JSTYPE_UNDEFINED:
\r
518 if (type == ScriptRuntime.StringClass ||
\r
519 type == ScriptRuntime.ObjectClass) {
\r
520 return "undefined";
\r
523 reportConversionError("undefined", type);
\r
527 case JSTYPE_BOOLEAN:
\r
528 // Under LC3, only JS Booleans can be coerced into a Boolean value
\r
529 if (type == Boolean.TYPE ||
\r
530 type == ScriptRuntime.BooleanClass ||
\r
531 type == ScriptRuntime.ObjectClass) {
\r
534 else if (type == ScriptRuntime.StringClass) {
\r
535 return value.toString();
\r
538 reportConversionError(value, type);
\r
542 case JSTYPE_NUMBER:
\r
543 if (type == ScriptRuntime.StringClass) {
\r
544 return ScriptRuntime.toString(value);
\r
546 else if (type == ScriptRuntime.ObjectClass) {
\r
547 return coerceToNumber(Double.TYPE, value);
\r
549 else if ((type.isPrimitive() && type != Boolean.TYPE) ||
\r
550 ScriptRuntime.NumberClass.isAssignableFrom(type)) {
\r
551 return coerceToNumber(type, value);
\r
554 reportConversionError(value, type);
\r
558 case JSTYPE_STRING:
\r
559 if (type == ScriptRuntime.StringClass ||
\r
560 type == ScriptRuntime.ObjectClass) {
\r
563 else if (type == Character.TYPE ||
\r
564 type == ScriptRuntime.CharacterClass) {
\r
565 // Special case for converting a single char string to a
\r
567 // Placed here because it applies *only* to JS strings,
\r
568 // not other JS objects converted to strings
\r
569 if (((String)value).length() == 1) {
\r
570 return new Character(((String)value).charAt(0));
\r
573 return coerceToNumber(type, value);
\r
576 else if ((type.isPrimitive() && type != Boolean.TYPE) ||
\r
577 ScriptRuntime.NumberClass.isAssignableFrom(type)) {
\r
578 return coerceToNumber(type, value);
\r
581 reportConversionError(value, type);
\r
585 case JSTYPE_JAVA_CLASS:
\r
586 if (Context.useJSObject && jsObjectClass != null &&
\r
587 (type == ScriptRuntime.ObjectClass ||
\r
588 jsObjectClass.isAssignableFrom(type))) {
\r
589 return coerceToJSObject(type, (Scriptable)value);
\r
592 if (value instanceof Wrapper) {
\r
593 value = ((Wrapper)value).unwrap();
\r
596 if (type == ScriptRuntime.ClassClass ||
\r
597 type == ScriptRuntime.ObjectClass) {
\r
600 else if (type == ScriptRuntime.StringClass) {
\r
601 return value.toString();
\r
604 reportConversionError(value, type);
\r
609 case JSTYPE_JAVA_OBJECT:
\r
610 case JSTYPE_JAVA_ARRAY:
\r
611 if (type.isPrimitive()) {
\r
612 if (type == Boolean.TYPE) {
\r
613 reportConversionError(value, type);
\r
615 return coerceToNumber(type, value);
\r
618 if (value instanceof Wrapper) {
\r
619 value = ((Wrapper)value).unwrap();
\r
621 if (type == ScriptRuntime.StringClass) {
\r
622 return value.toString();
\r
625 if (type.isInstance(value)) {
\r
629 reportConversionError(value, type);
\r
635 case JSTYPE_OBJECT:
\r
636 if (Context.useJSObject && jsObjectClass != null &&
\r
637 (type == ScriptRuntime.ObjectClass ||
\r
638 jsObjectClass.isAssignableFrom(type))) {
\r
639 return coerceToJSObject(type, (Scriptable)value);
\r
641 else if (type == ScriptRuntime.StringClass) {
\r
642 return ScriptRuntime.toString(value);
\r
644 else if (type.isPrimitive()) {
\r
645 if (type == Boolean.TYPE) {
\r
646 reportConversionError(value, type);
\r
648 return coerceToNumber(type, value);
\r
650 else if (type.isInstance(value)) {
\r
653 else if (type.isArray() && value instanceof NativeArray) {
\r
654 // Make a new java array, and coerce the JS array components
\r
655 // to the target (component) type.
\r
656 NativeArray array = (NativeArray) value;
\r
657 long length = array.jsGet_length();
\r
658 Class arrayType = type.getComponentType();
\r
659 Object Result = Array.newInstance(arrayType, (int)length);
\r
660 for (int i = 0 ; i < length ; ++i) {
\r
662 Array.set(Result, i, coerceType(arrayType,
\r
663 array.get(i, array)));
\r
665 catch (EvaluatorException ee) {
\r
666 reportConversionError(value, type);
\r
672 else if (value instanceof Wrapper) {
\r
673 value = ((Wrapper)value).unwrap();
\r
674 if (type.isInstance(value))
\r
676 reportConversionError(value, type);
\r
679 reportConversionError(value, type);
\r
687 static Object coerceToJSObject(Class type, Scriptable value) {
\r
688 // If JSObject compatibility is enabled, and the method wants it,
\r
689 // wrap the Scriptable value in a JSObject.
\r
691 if (ScriptRuntime.ScriptableClass.isAssignableFrom(type))
\r
695 Object ctorArgs[] = { value };
\r
696 return jsObjectCtor.newInstance(ctorArgs);
\r
697 } catch (InstantiationException instEx) {
\r
698 throw new EvaluatorException("error generating JSObject wrapper for " +
\r
700 } catch (IllegalArgumentException argEx) {
\r
701 throw new EvaluatorException("JSObject constructor doesn't want [Scriptable]!");
\r
702 } catch (InvocationTargetException e) {
\r
703 throw WrappedException.wrapException(e.getTargetException());
\r
704 } catch (IllegalAccessException accessEx) {
\r
705 throw new EvaluatorException("JSObject constructor is protected/private!");
\r
709 static Object coerceToNumber(Class type, Object value) {
\r
710 Class valueClass = value.getClass();
\r
713 if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) {
\r
714 if (valueClass == ScriptRuntime.CharacterClass) {
\r
717 return new Character((char)toInteger(value,
\r
718 ScriptRuntime.CharacterClass,
\r
719 (double)Character.MIN_VALUE,
\r
720 (double)Character.MAX_VALUE));
\r
724 if (type == ScriptRuntime.ObjectClass ||
\r
725 type == ScriptRuntime.DoubleClass || type == Double.TYPE) {
\r
726 return valueClass == ScriptRuntime.DoubleClass
\r
728 : new Double(toDouble(value));
\r
731 if (type == ScriptRuntime.FloatClass || type == Float.TYPE) {
\r
732 if (valueClass == ScriptRuntime.FloatClass) {
\r
736 double number = toDouble(value);
\r
737 if (Double.isInfinite(number) || Double.isNaN(number)
\r
738 || number == 0.0) {
\r
739 return new Float((float)number);
\r
742 double absNumber = Math.abs(number);
\r
743 if (absNumber < (double)Float.MIN_VALUE) {
\r
744 return new Float((number > 0.0) ? +0.0 : -0.0);
\r
746 else if (absNumber > (double)Float.MAX_VALUE) {
\r
747 return new Float((number > 0.0) ?
\r
748 Float.POSITIVE_INFINITY :
\r
749 Float.NEGATIVE_INFINITY);
\r
752 return new Float((float)number);
\r
758 // Integer, Long, Short, Byte
\r
759 if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE) {
\r
760 if (valueClass == ScriptRuntime.IntegerClass) {
\r
764 return new Integer((int)toInteger(value,
\r
765 ScriptRuntime.IntegerClass,
\r
766 (double)Integer.MIN_VALUE,
\r
767 (double)Integer.MAX_VALUE));
\r
771 if (type == ScriptRuntime.LongClass || type == Long.TYPE) {
\r
772 if (valueClass == ScriptRuntime.LongClass) {
\r
776 /* Long values cannot be expressed exactly in doubles.
\r
777 * We thus use the largest and smallest double value that
\r
778 * has a value expressible as a long value. We build these
\r
779 * numerical values from their hexidecimal representations
\r
780 * to avoid any problems caused by attempting to parse a
\r
781 * decimal representation.
\r
783 final double max = Double.longBitsToDouble(0x43dfffffffffffffL);
\r
784 final double min = Double.longBitsToDouble(0xc3e0000000000000L);
\r
785 return new Long(toInteger(value,
\r
786 ScriptRuntime.LongClass,
\r
792 if (type == ScriptRuntime.ShortClass || type == Short.TYPE) {
\r
793 if (valueClass == ScriptRuntime.ShortClass) {
\r
797 return new Short((short)toInteger(value,
\r
798 ScriptRuntime.ShortClass,
\r
799 (double)Short.MIN_VALUE,
\r
800 (double)Short.MAX_VALUE));
\r
804 if (type == ScriptRuntime.ByteClass || type == Byte.TYPE) {
\r
805 if (valueClass == ScriptRuntime.ByteClass) {
\r
809 return new Byte((byte)toInteger(value,
\r
810 ScriptRuntime.ByteClass,
\r
811 (double)Byte.MIN_VALUE,
\r
812 (double)Byte.MAX_VALUE));
\r
816 return new Double(toDouble(value));
\r
820 static double toDouble(Object value) {
\r
821 if (value instanceof Number) {
\r
822 return ((Number)value).doubleValue();
\r
824 else if (value instanceof String) {
\r
825 return ScriptRuntime.toNumber((String)value);
\r
827 else if (value instanceof Scriptable) {
\r
828 if (value instanceof Wrapper) {
\r
829 // XXX: optimize tail-recursion?
\r
830 return toDouble(((Wrapper)value).unwrap());
\r
833 return ScriptRuntime.toNumber(value);
\r
839 meth = value.getClass().getMethod("doubleValue", null);
\r
841 catch (NoSuchMethodException e) {
\r
844 catch (SecurityException e) {
\r
847 if (meth != null) {
\r
849 return ((Number)meth.invoke(value, null)).doubleValue();
\r
851 catch (IllegalAccessException e) {
\r
852 // XXX: ignore, or error message?
\r
853 reportConversionError(value, Double.TYPE);
\r
855 catch (InvocationTargetException e) {
\r
856 // XXX: ignore, or error message?
\r
857 reportConversionError(value, Double.TYPE);
\r
860 return ScriptRuntime.toNumber(value.toString());
\r
864 static long toInteger(Object value, Class type, double min, double max) {
\r
865 double d = toDouble(value);
\r
867 if (Double.isInfinite(d) || Double.isNaN(d)) {
\r
868 // Convert to string first, for more readable message
\r
869 reportConversionError(ScriptRuntime.toString(value), type);
\r
879 if (d < min || d > max) {
\r
880 // Convert to string first, for more readable message
\r
881 reportConversionError(ScriptRuntime.toString(value), type);
\r
886 static void reportConversionError(Object value, Class type) {
\r
887 throw Context.reportRuntimeError2
\r
888 ("msg.conversion.not.allowed",
\r
889 value.toString(), NativeJavaMethod.javaSignature(type));
\r
892 public static void initJSObject() {
\r
893 // if netscape.javascript.JSObject is in the CLASSPATH, enable JSObject
\r
894 // compatability wrappers
\r
895 jsObjectClass = null;
\r
897 jsObjectClass = Class.forName("netscape.javascript.JSObject");
\r
898 Class ctorParms[] = { ScriptRuntime.ScriptableClass };
\r
899 jsObjectCtor = jsObjectClass.getConstructor(ctorParms);
\r
900 jsObjectGetScriptable = jsObjectClass.getMethod("getScriptable",
\r
902 } catch (ClassNotFoundException classEx) {
\r
903 // jsObjectClass already null
\r
904 } catch (NoSuchMethodException methEx) {
\r
905 // jsObjectClass already null
\r
910 * The prototype of this object.
\r
912 protected Scriptable prototype;
\r
915 * The parent scope of this object.
\r
917 protected Scriptable parent;
\r
919 protected Object javaObject;
\r
920 protected JavaMembers members;
\r
921 private Hashtable fieldAndMethods;
\r
922 static Class jsObjectClass;
\r
923 static Constructor jsObjectCtor;
\r
924 static Method jsObjectGetScriptable;
\r