2 * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #if ENABLE(JAVA_BINDINGS)
34 #include <jni_utility.h>
35 #include <jni_runtime.h>
37 #include <runtime_array.h>
38 #include <runtime_object.h>
39 #include <runtime_root.h>
42 #define JS_LOG(formatAndArgs...) ((void)0)
44 #define JS_LOG(formatAndArgs...) { \
45 fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \
46 fprintf(stderr, formatAndArgs); \
51 using namespace KJS::Bindings
;
54 JavaParameter::JavaParameter (JNIEnv
*env
, jstring type
)
56 _type
= JavaString (env
, type
);
57 _JNIType
= JNITypeFromClassName (_type
.UTF8String());
60 JavaField::JavaField (JNIEnv
*env
, jobject aField
)
63 jobject fieldType
= callJNIObjectMethod (aField
, "getType", "()Ljava/lang/Class;");
64 jstring fieldTypeName
= (jstring
)callJNIObjectMethod (fieldType
, "getName", "()Ljava/lang/String;");
65 _type
= JavaString(env
, fieldTypeName
);
66 _JNIType
= JNITypeFromClassName (_type
.UTF8String());
69 jstring fieldName
= (jstring
)callJNIObjectMethod (aField
, "getName", "()Ljava/lang/String;");
70 _name
= JavaString(env
, fieldName
);
72 _field
= new JObjectWrapper(aField
);
75 JSValue
* JavaArray::convertJObjectToArray(ExecState
* exec
, jobject anObject
, const char* type
, PassRefPtr
<RootObject
> rootObject
)
80 return new RuntimeArray(exec
, new JavaArray((jobject
)anObject
, type
, rootObject
));
83 jvalue
JavaField::dispatchValueFromInstance(ExecState
*exec
, const JavaInstance
*instance
, const char *name
, const char *sig
, JNIType returnType
) const
85 jobject jinstance
= instance
->javaInstance();
86 jobject fieldJInstance
= _field
->_instance
;
87 JNIEnv
*env
= getJNIEnv();
90 bzero (&result
, sizeof(jvalue
));
91 jclass cls
= env
->GetObjectClass(fieldJInstance
);
93 jmethodID mid
= env
->GetMethodID(cls
, name
, sig
);
96 RootObject
* rootObject
= instance
->rootObject();
97 if (rootObject
&& rootObject
->nativeHandle()) {
98 JSValue
*exceptionDescription
= NULL
;
101 args
[0].l
= jinstance
;
102 dispatchJNICall(rootObject
->nativeHandle(), fieldJInstance
, false, returnType
, mid
, args
, result
, 0, exceptionDescription
);
103 if (exceptionDescription
)
104 throwError(exec
, GeneralError
, exceptionDescription
->toString(exec
));
111 JSValue
*JavaField::valueFromInstance(ExecState
*exec
, const Instance
*i
) const
113 const JavaInstance
*instance
= static_cast<const JavaInstance
*>(i
);
115 JSValue
*jsresult
= jsUndefined();
120 jvalue result
= dispatchValueFromInstance (exec
, instance
, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", object_type
);
121 jobject anObject
= result
.l
;
123 const char *arrayType
= type();
124 if (arrayType
[0] == '[') {
125 jsresult
= JavaArray::convertJObjectToArray(exec
, anObject
, arrayType
, instance
->rootObject());
127 else if (anObject
!= 0){
128 jsresult
= Instance::createRuntimeObject(Instance::JavaLanguage
, anObject
, instance
->rootObject());
134 jsresult
= jsBoolean(dispatchValueFromInstance(exec
, instance
, "getBoolean", "(Ljava/lang/Object;)Z", boolean_type
).z
);
143 jvalue result
= dispatchValueFromInstance (exec
, instance
, "getInt", "(Ljava/lang/Object;)I", int_type
);
145 jsresult
= jsNumber((int)value
);
153 jvalue result
= dispatchValueFromInstance (exec
, instance
, "getDouble", "(Ljava/lang/Object;)D", double_type
);
155 jsresult
= jsNumber((double)value
);
162 JS_LOG ("getting %s = %s\n", name(), jsresult
->toString(exec
).ascii());
167 void JavaField::dispatchSetValueToInstance(ExecState
*exec
, const JavaInstance
*instance
, jvalue javaValue
, const char *name
, const char *sig
) const
169 jobject jinstance
= instance
->javaInstance();
170 jobject fieldJInstance
= _field
->_instance
;
171 JNIEnv
*env
= getJNIEnv();
173 jclass cls
= env
->GetObjectClass(fieldJInstance
);
175 jmethodID mid
= env
->GetMethodID(cls
, name
, sig
);
178 RootObject
* rootObject
= instance
->rootObject();
179 if (rootObject
&& rootObject
->nativeHandle()) {
180 JSValue
*exceptionDescription
= NULL
;
184 args
[0].l
= jinstance
;
186 dispatchJNICall(rootObject
->nativeHandle(), fieldJInstance
, false, void_type
, mid
, args
, result
, 0, exceptionDescription
);
187 if (exceptionDescription
)
188 throwError(exec
, GeneralError
, exceptionDescription
->toString(exec
));
194 void JavaField::setValueToInstance(ExecState
*exec
, const Instance
*i
, JSValue
*aValue
) const
196 const JavaInstance
*instance
= static_cast<const JavaInstance
*>(i
);
197 jvalue javaValue
= convertValueToJValue (exec
, aValue
, _JNIType
, type());
199 JS_LOG ("setting value %s to %s\n", name(), aValue
->toString(exec
).ascii());
204 dispatchSetValueToInstance (exec
, instance
, javaValue
, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
209 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setBoolean", "(Ljava/lang/Object;Z)V");
214 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setByte", "(Ljava/lang/Object;B)V");
219 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setChar", "(Ljava/lang/Object;C)V");
224 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setShort", "(Ljava/lang/Object;S)V");
229 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setInt", "(Ljava/lang/Object;I)V");
234 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setLong", "(Ljava/lang/Object;J)V");
239 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setFloat", "(Ljava/lang/Object;F)V");
244 dispatchSetValueToInstance (exec
, instance
, javaValue
, "setDouble", "(Ljava/lang/Object;D)V");
252 JavaMethod::JavaMethod (JNIEnv
*env
, jobject aMethod
)
255 jobject returnType
= callJNIObjectMethod (aMethod
, "getReturnType", "()Ljava/lang/Class;");
256 jstring returnTypeName
= (jstring
)callJNIObjectMethod (returnType
, "getName", "()Ljava/lang/String;");
257 _returnType
=JavaString (env
, returnTypeName
);
258 _JNIReturnType
= JNITypeFromClassName (_returnType
.UTF8String());
259 env
->DeleteLocalRef (returnType
);
260 env
->DeleteLocalRef (returnTypeName
);
263 jstring methodName
= (jstring
)callJNIObjectMethod (aMethod
, "getName", "()Ljava/lang/String;");
264 _name
= JavaString (env
, methodName
);
265 env
->DeleteLocalRef (methodName
);
268 jarray jparameters
= (jarray
)callJNIObjectMethod (aMethod
, "getParameterTypes", "()[Ljava/lang/Class;");
269 _numParameters
= env
->GetArrayLength (jparameters
);
270 _parameters
= new JavaParameter
[_numParameters
];
273 for (i
= 0; i
< _numParameters
; i
++) {
274 jobject aParameter
= env
->GetObjectArrayElement ((jobjectArray
)jparameters
, i
);
275 jstring parameterName
= (jstring
)callJNIObjectMethod (aParameter
, "getName", "()Ljava/lang/String;");
276 _parameters
[i
] = JavaParameter(env
, parameterName
);
277 env
->DeleteLocalRef (aParameter
);
278 env
->DeleteLocalRef (parameterName
);
280 env
->DeleteLocalRef (jparameters
);
286 jclass modifierClass
= env
->FindClass("java/lang/reflect/Modifier");
287 int modifiers
= callJNIIntMethod (aMethod
, "getModifiers", "()I");
288 _isStatic
= (bool)callJNIStaticBooleanMethod (modifierClass
, "isStatic", "(I)Z", modifiers
);
291 JavaMethod::~JavaMethod()
295 delete [] _parameters
;
298 // JNI method signatures use '/' between components of a class name, but
299 // we get '.' between components from the reflection API.
300 static void appendClassName(UString
& aString
, const char* className
)
302 ASSERT(JSLock::lockCount() > 0);
304 char *result
, *cp
= strdup(className
);
313 aString
.append(result
);
318 const char *JavaMethod::signature() const
323 UString
signatureBuilder("(");
324 for (int i
= 0; i
< _numParameters
; i
++) {
325 JavaParameter
* aParameter
= parameterAt(i
);
326 JNIType _JNIType
= aParameter
->getJNIType();
327 if (_JNIType
== array_type
)
328 appendClassName(signatureBuilder
, aParameter
->type());
330 signatureBuilder
.append(signatureFromPrimitiveType(_JNIType
));
331 if (_JNIType
== object_type
) {
332 appendClassName(signatureBuilder
, aParameter
->type());
333 signatureBuilder
.append(";");
337 signatureBuilder
.append(")");
339 const char *returnType
= _returnType
.UTF8String();
340 if (_JNIReturnType
== array_type
) {
341 appendClassName(signatureBuilder
, returnType
);
343 signatureBuilder
.append(signatureFromPrimitiveType(_JNIReturnType
));
344 if (_JNIReturnType
== object_type
) {
345 appendClassName(signatureBuilder
, returnType
);
346 signatureBuilder
.append(";");
350 _signature
= strdup(signatureBuilder
.ascii());
356 JNIType
JavaMethod::JNIReturnType() const
358 return _JNIReturnType
;
361 jmethodID
JavaMethod::methodID (jobject obj
) const
363 if (_methodID
== 0) {
364 _methodID
= getMethodID (obj
, name(), signature());
370 JavaArray::JavaArray(jobject array
, const char* type
, PassRefPtr
<RootObject
> rootObject
)
373 _array
= new JObjectWrapper(array
);
374 // Java array are fixed length, so we can cache length.
375 JNIEnv
*env
= getJNIEnv();
376 _length
= env
->GetArrayLength((jarray
)_array
->_instance
);
377 _type
= strdup(type
);
378 _rootObject
= rootObject
;
381 JavaArray::~JavaArray ()
383 free ((void *)_type
);
386 RootObject
* JavaArray::rootObject() const
388 return _rootObject
&& _rootObject
->isValid() ? _rootObject
.get() : 0;
391 void JavaArray::setValueAt(ExecState
*exec
, unsigned int index
, JSValue
*aValue
) const
393 JNIEnv
*env
= getJNIEnv();
394 char *javaClassName
= 0;
396 JNIType arrayType
= JNITypeFromPrimitiveType(_type
[1]);
397 if (_type
[1] == 'L'){
398 // The type of the array will be something like:
399 // "[Ljava.lang.string;". This is guaranteed, so no need
400 // for extra sanity checks.
401 javaClassName
= strdup(&_type
[2]);
402 javaClassName
[strchr(javaClassName
, ';')-javaClassName
] = 0;
404 jvalue aJValue
= convertValueToJValue (exec
, aValue
, arrayType
, javaClassName
);
408 env
->SetObjectArrayElement((jobjectArray
)javaArray(), index
, aJValue
.l
);
413 env
->SetBooleanArrayRegion((jbooleanArray
)javaArray(), index
, 1, &aJValue
.z
);
418 env
->SetByteArrayRegion((jbyteArray
)javaArray(), index
, 1, &aJValue
.b
);
423 env
->SetCharArrayRegion((jcharArray
)javaArray(), index
, 1, &aJValue
.c
);
428 env
->SetShortArrayRegion((jshortArray
)javaArray(), index
, 1, &aJValue
.s
);
433 env
->SetIntArrayRegion((jintArray
)javaArray(), index
, 1, &aJValue
.i
);
438 env
->SetLongArrayRegion((jlongArray
)javaArray(), index
, 1, &aJValue
.j
);
442 env
->SetFloatArrayRegion((jfloatArray
)javaArray(), index
, 1, &aJValue
.f
);
447 env
->SetDoubleArrayRegion((jdoubleArray
)javaArray(), index
, 1, &aJValue
.d
);
455 free ((void *)javaClassName
);
459 JSValue
*JavaArray::valueAt(ExecState
*exec
, unsigned int index
) const
461 JNIEnv
*env
= getJNIEnv();
462 JNIType arrayType
= JNITypeFromPrimitiveType(_type
[1]);
465 jobjectArray objectArray
= (jobjectArray
)javaArray();
467 anObject
= env
->GetObjectArrayElement(objectArray
, index
);
475 if (_type
[1] == '[') {
476 return JavaArray::convertJObjectToArray(exec
, anObject
, _type
+1, rootObject());
478 // or array of other object type?
479 return Instance::createRuntimeObject(Instance::JavaLanguage
, anObject
, rootObject());
483 jbooleanArray booleanArray
= (jbooleanArray
)javaArray();
485 env
->GetBooleanArrayRegion(booleanArray
, index
, 1, &aBoolean
);
486 return jsBoolean(aBoolean
);
490 jbyteArray byteArray
= (jbyteArray
)javaArray();
492 env
->GetByteArrayRegion(byteArray
, index
, 1, &aByte
);
493 return jsNumber(aByte
);
497 jcharArray charArray
= (jcharArray
)javaArray();
499 env
->GetCharArrayRegion(charArray
, index
, 1, &aChar
);
500 return jsNumber(aChar
);
505 jshortArray shortArray
= (jshortArray
)javaArray();
507 env
->GetShortArrayRegion(shortArray
, index
, 1, &aShort
);
508 return jsNumber(aShort
);
512 jintArray intArray
= (jintArray
)javaArray();
514 env
->GetIntArrayRegion(intArray
, index
, 1, &anInt
);
515 return jsNumber(anInt
);
519 jlongArray longArray
= (jlongArray
)javaArray();
521 env
->GetLongArrayRegion(longArray
, index
, 1, &aLong
);
522 return jsNumber(aLong
);
526 jfloatArray floatArray
= (jfloatArray
)javaArray();
528 env
->GetFloatArrayRegion(floatArray
, index
, 1, &aFloat
);
529 return jsNumber(aFloat
);
533 jdoubleArray doubleArray
= (jdoubleArray
)javaArray();
535 env
->GetDoubleArrayRegion(doubleArray
, index
, 1, &aDouble
);
536 return jsNumber(aDouble
);
541 return jsUndefined();
544 unsigned int JavaArray::getLength() const
549 #endif // ENABLE(JAVA_BINDINGS)