1 /*
2 * Copyright (C) 2003, 2004, 2005, 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright 2010, The Android Open Source Project
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "JavaFieldJSC.h"
29
30 #if ENABLE(JAVA_BRIDGE)
31
32 #include "JNIUtilityPrivate.h"
33 #include "JavaArrayJSC.h"
34 #include "Logging.h"
35 #include "runtime_array.h"
36 #include "runtime_object.h"
37 #include <runtime/Error.h>
38
39 using namespace JSC;
40 using namespace JSC::Bindings;
41 using namespace WebCore;
42
JavaField(JNIEnv * env,jobject aField)43 JavaField::JavaField(JNIEnv* env, jobject aField)
44 {
45 // Get field type name
46 jstring fieldTypeName = 0;
47 jclass fieldType = static_cast<jclass>(callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;"));
48 if (fieldType)
49 fieldTypeName = static_cast<jstring>(callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;"));
50 if (!fieldTypeName)
51 fieldTypeName = env->NewStringUTF("<Unknown>");
52 m_typeClassName = JavaString(env, fieldTypeName);
53
54 m_type = javaTypeFromClassName(m_typeClassName.utf8());
55 env->DeleteLocalRef(fieldType);
56 env->DeleteLocalRef(fieldTypeName);
57
58 // Get field name
59 jstring fieldName = static_cast<jstring>(callJNIMethod<jobject>(aField, "getName", "()Ljava/lang/String;"));
60 if (!fieldName)
61 fieldName = env->NewStringUTF("<Unknown>");
62 m_name = JavaString(env, fieldName);
63 env->DeleteLocalRef(fieldName);
64
65 m_field = new JobjectWrapper(aField);
66 }
67
dispatchValueFromInstance(ExecState * exec,const JavaInstance * instance,const char * name,const char * sig,JavaType returnType) const68 jvalue JavaField::dispatchValueFromInstance(ExecState* exec, const JavaInstance* instance, const char* name, const char* sig, JavaType returnType) const
69 {
70 jobject jinstance = instance->javaInstance();
71 jobject fieldJInstance = m_field->m_instance;
72 JNIEnv* env = getJNIEnv();
73 jvalue result;
74
75 memset(&result, 0, sizeof(jvalue));
76 jclass cls = env->GetObjectClass(fieldJInstance);
77 if (cls) {
78 jmethodID mid = env->GetMethodID(cls, name, sig);
79 if (mid) {
80 RootObject* rootObject = instance->rootObject();
81 if (rootObject && rootObject->nativeHandle()) {
82 JSValue exceptionDescription;
83 jvalue args[1];
84
85 args[0].l = jinstance;
86 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, returnType, mid, args, result, 0, exceptionDescription);
87 if (exceptionDescription)
88 throwError(exec, createError(exec, exceptionDescription.toString(exec)));
89 }
90 }
91 }
92 return result;
93 }
94
valueFromInstance(ExecState * exec,const Instance * i) const95 JSValue JavaField::valueFromInstance(ExecState* exec, const Instance* i) const
96 {
97 const JavaInstance* instance = static_cast<const JavaInstance*>(i);
98
99 JSValue jsresult = jsUndefined();
100
101 switch (m_type) {
102 case JavaTypeArray:
103 case JavaTypeObject:
104 {
105 jvalue result = dispatchValueFromInstance(exec, instance, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", JavaTypeObject);
106 jobject anObject = result.l;
107
108 if (!anObject)
109 return jsNull();
110
111 const char* arrayType = typeClassName();
112 if (arrayType[0] == '[')
113 jsresult = JavaArray::convertJObjectToArray(exec, anObject, arrayType, instance->rootObject());
114 else if (anObject)
115 jsresult = JavaInstance::create(anObject, instance->rootObject())->createRuntimeObject(exec);
116 }
117 break;
118
119 case JavaTypeBoolean:
120 jsresult = jsBoolean(dispatchValueFromInstance(exec, instance, "getBoolean", "(Ljava/lang/Object;)Z", JavaTypeBoolean).z);
121 break;
122
123 case JavaTypeByte:
124 case JavaTypeChar:
125 case JavaTypeShort:
126
127 case JavaTypeInt:
128 {
129 jint value;
130 jvalue result = dispatchValueFromInstance(exec, instance, "getInt", "(Ljava/lang/Object;)I", JavaTypeInt);
131 value = result.i;
132 jsresult = jsNumber(static_cast<int>(value));
133 }
134 break;
135
136 case JavaTypeLong:
137 case JavaTypeFloat:
138 case JavaTypeDouble:
139 {
140 jdouble value;
141 jvalue result = dispatchValueFromInstance(exec, instance, "getDouble", "(Ljava/lang/Object;)D", JavaTypeDouble);
142 value = result.i;
143 jsresult = jsNumber(static_cast<double>(value));
144 }
145 break;
146 default:
147 break;
148 }
149
150 LOG(LiveConnect, "JavaField::valueFromInstance getting %s = %s", UString(name().impl()).utf8().data(), jsresult.toString(exec).ascii().data());
151
152 return jsresult;
153 }
154
dispatchSetValueToInstance(ExecState * exec,const JavaInstance * instance,jvalue javaValue,const char * name,const char * sig) const155 void JavaField::dispatchSetValueToInstance(ExecState* exec, const JavaInstance* instance, jvalue javaValue, const char* name, const char* sig) const
156 {
157 jobject jinstance = instance->javaInstance();
158 jobject fieldJInstance = m_field->m_instance;
159 JNIEnv* env = getJNIEnv();
160
161 jclass cls = env->GetObjectClass(fieldJInstance);
162 if (cls) {
163 jmethodID mid = env->GetMethodID(cls, name, sig);
164 if (mid) {
165 RootObject* rootObject = instance->rootObject();
166 if (rootObject && rootObject->nativeHandle()) {
167 JSValue exceptionDescription;
168 jvalue args[2];
169 jvalue result;
170
171 args[0].l = jinstance;
172 args[1] = javaValue;
173 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, JavaTypeVoid, mid, args, result, 0, exceptionDescription);
174 if (exceptionDescription)
175 throwError(exec, createError(exec, exceptionDescription.toString(exec)));
176 }
177 }
178 }
179 }
180
setValueToInstance(ExecState * exec,const Instance * i,JSValue aValue) const181 void JavaField::setValueToInstance(ExecState* exec, const Instance* i, JSValue aValue) const
182 {
183 const JavaInstance* instance = static_cast<const JavaInstance*>(i);
184 jvalue javaValue = convertValueToJValue(exec, i->rootObject(), aValue, m_type, typeClassName());
185
186 LOG(LiveConnect, "JavaField::setValueToInstance setting value %s to %s", UString(name().impl()).utf8().data(), aValue.toString(exec).ascii().data());
187
188 switch (m_type) {
189 case JavaTypeArray:
190 case JavaTypeObject:
191 {
192 dispatchSetValueToInstance(exec, instance, javaValue, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
193 }
194 break;
195
196 case JavaTypeBoolean:
197 {
198 dispatchSetValueToInstance(exec, instance, javaValue, "setBoolean", "(Ljava/lang/Object;Z)V");
199 }
200 break;
201
202 case JavaTypeByte:
203 {
204 dispatchSetValueToInstance(exec, instance, javaValue, "setByte", "(Ljava/lang/Object;B)V");
205 }
206 break;
207
208 case JavaTypeChar:
209 {
210 dispatchSetValueToInstance(exec, instance, javaValue, "setChar", "(Ljava/lang/Object;C)V");
211 }
212 break;
213
214 case JavaTypeShort:
215 {
216 dispatchSetValueToInstance(exec, instance, javaValue, "setShort", "(Ljava/lang/Object;S)V");
217 }
218 break;
219
220 case JavaTypeInt:
221 {
222 dispatchSetValueToInstance(exec, instance, javaValue, "setInt", "(Ljava/lang/Object;I)V");
223 }
224 break;
225
226 case JavaTypeLong:
227 {
228 dispatchSetValueToInstance(exec, instance, javaValue, "setLong", "(Ljava/lang/Object;J)V");
229 }
230 break;
231
232 case JavaTypeFloat:
233 {
234 dispatchSetValueToInstance(exec, instance, javaValue, "setFloat", "(Ljava/lang/Object;F)V");
235 }
236 break;
237
238 case JavaTypeDouble:
239 {
240 dispatchSetValueToInstance(exec, instance, javaValue, "setDouble", "(Ljava/lang/Object;D)V");
241 }
242 break;
243 default:
244 break;
245 }
246 }
247
248 #endif // ENABLE(JAVA_BRIDGE)
249