Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / js / src / liveconnect / jsj_field.c
blob45bebf9bd69a5a0e6c5432755f21da5bffbe6517
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 * This file is part of the Java-vendor-neutral implementation of LiveConnect
43 * It contains the code used to reflect Java fields as properties of
44 * JavaObject objects and the code to access those fields.
48 #include <stdlib.h>
50 #include "jsj_private.h" /* LiveConnect internals */
53 * Add a single field, described by java_field, to the JavaMemberDescriptor
54 * named by field_name within the given JavaClassDescriptor.
56 * Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
58 static JSBool
59 add_java_field_to_class_descriptor(JSContext *cx,
60 JNIEnv *jEnv,
61 JavaClassDescriptor *class_descriptor,
62 jstring field_name_jstr,
63 jobject java_field, /* a java.lang.reflect.Field */
64 jint modifiers)
66 jclass fieldType;
67 jfieldID fieldID;
68 jclass java_class;
70 JSBool is_static_field;
71 JavaMemberDescriptor *member_descriptor = NULL;
72 const char *sig_cstr = NULL;
73 const char *field_name = NULL;
74 JavaSignature *signature = NULL;
75 JavaFieldSpec *field_spec = NULL;
77 is_static_field = modifiers & ACC_STATIC;
78 if (is_static_field) {
79 member_descriptor = jsj_GetJavaStaticMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
80 } else {
81 member_descriptor = jsj_GetJavaMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
83 if (!member_descriptor)
84 goto error;
86 field_spec = (JavaFieldSpec*)JS_malloc(cx, sizeof(JavaFieldSpec));
87 if (!field_spec)
88 goto error;
90 field_spec->modifiers = modifiers;
92 /* Get the Java class corresponding to the type of the field */
93 fieldType = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getType);
94 if (!fieldType) {
95 jsj_UnexpectedJavaError(cx, jEnv,
96 "Unable to determine type of field using"
97 " java.lang.reflect.Field.getType()");
98 goto error;
101 signature = jsj_GetJavaClassDescriptor(cx, jEnv, fieldType);
102 (*jEnv)->DeleteLocalRef(jEnv, fieldType);
103 if (!signature)
104 goto error;
105 field_spec->signature = signature;
107 field_name = jsj_DupJavaStringUTF(cx, jEnv, field_name_jstr);
108 if (!field_name)
109 goto error;
110 field_spec->name = field_name;
112 /* Compute the JNI-style (string-based) signature of the field type */
113 sig_cstr = jsj_ConvertJavaSignatureToString(cx, signature);
114 if (!sig_cstr)
115 goto error;
117 /* Compute the JNI fieldID and cache it for quick field access */
118 java_class = class_descriptor->java_class;
119 if (is_static_field)
120 fieldID = (*jEnv)->GetStaticFieldID(jEnv, java_class, field_name, sig_cstr);
121 else
122 fieldID = (*jEnv)->GetFieldID(jEnv, java_class, field_name, sig_cstr);
123 if (!fieldID) {
124 jsj_UnexpectedJavaError(cx, jEnv,
125 "Can't get Java field ID for class %s, field %s (sig=%s)",
126 class_descriptor->name, field_name, sig_cstr);
127 goto error;
129 field_spec->fieldID = fieldID;
131 JS_free(cx, (char*)sig_cstr);
133 member_descriptor->field = field_spec;
135 /* Success */
136 return JS_TRUE;
138 error:
139 if (field_spec) {
140 JS_FREE_IF(cx, (char*)field_spec->name);
141 JS_free(cx, field_spec);
143 JS_FREE_IF(cx, (char*)sig_cstr);
144 if (signature)
145 jsj_ReleaseJavaClassDescriptor(cx, jEnv, signature);
146 return JS_FALSE;
150 * Free up a JavaFieldSpec and all its resources.
152 void
153 jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field)
155 JS_FREE_IF(cx, (char*)field->name);
156 jsj_ReleaseJavaClassDescriptor(cx, jEnv, field->signature);
157 JS_free(cx, field);
161 * Add a JavaMemberDescriptor to the collection of members in class_descriptor
162 * for every public field of the identified Java class. (A separate collection
163 * is kept in class_descriptor for static and instance members.)
164 * If reflect_only_static_fields is set, instance fields are not reflected. If
165 * it isn't set, only instance fields are reflected and static fields are not
166 * reflected.
168 * Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
170 JSBool
171 jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor,
172 JSBool reflect_only_static_fields)
174 int i;
175 JSBool ok;
176 jint modifiers;
177 jobject java_field;
178 jstring field_name_jstr;
179 jarray joFieldArray;
180 jsize num_fields;
181 jclass java_class;
183 /* Get a java array of java.lang.reflect.Field objects, by calling
184 java.lang.Class.getFields(). */
185 java_class = class_descriptor->java_class;
186 joFieldArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getFields);
187 if (!joFieldArray) {
188 jsj_UnexpectedJavaError(cx, jEnv,
189 "Can't determine Java object's fields "
190 "using java.lang.Class.getFields()");
191 return JS_FALSE;
194 /* Iterate over the class fields */
195 num_fields = (*jEnv)->GetArrayLength(jEnv, joFieldArray);
196 for (i = 0; i < num_fields; i++) {
198 /* Get the i'th reflected field */
199 java_field = (*jEnv)->GetObjectArrayElement(jEnv, joFieldArray, i);
200 if (!java_field) {
201 jsj_UnexpectedJavaError(cx, jEnv, "Can't access a Field[] array");
202 return JS_FALSE;
205 /* Get the field modifiers, e.g. static, public, private, etc. */
206 modifiers = (*jEnv)->CallIntMethod(jEnv, java_field, jlrField_getModifiers);
207 if ((*jEnv)->ExceptionOccurred(jEnv)) {
208 jsj_UnexpectedJavaError(cx, jEnv,
209 "Can't access a Field's modifiers using"
210 "java.lang.reflect.Field.getModifiers()");
211 return JS_FALSE;
214 /* Don't allow access to private or protected Java fields. */
215 if (!(modifiers & ACC_PUBLIC))
216 goto no_reflect;
218 /* Reflect all instance fields or all static fields, but not both */
219 if (reflect_only_static_fields != ((modifiers & ACC_STATIC) != 0))
220 goto no_reflect;
222 /* Determine the unqualified name of the field */
223 field_name_jstr = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getName);
224 if (!field_name_jstr) {
225 jsj_UnexpectedJavaError(cx, jEnv,
226 "Can't obtain a Field's name"
227 "java.lang.reflect.Field.getName()");
228 return JS_FALSE;
231 /* Add a JavaFieldSpec object to the JavaClassDescriptor */
232 ok = add_java_field_to_class_descriptor(cx, jEnv, class_descriptor, field_name_jstr,
233 java_field, modifiers);
234 if (!ok)
235 return JS_FALSE;
237 (*jEnv)->DeleteLocalRef(jEnv, field_name_jstr);
238 field_name_jstr = NULL;
240 no_reflect:
241 (*jEnv)->DeleteLocalRef(jEnv, java_field);
242 java_field = NULL;
245 (*jEnv)->DeleteLocalRef(jEnv, joFieldArray);
247 /* Success */
248 return JS_TRUE;
252 * Read the value of a Java field and return it as a JavaScript value.
253 * If the field is static, then java_obj is a Java class, otherwise
254 * it's a Java instance object.
256 * Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
258 JSBool
259 jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
260 jobject java_obj, jsval *vp)
262 JSBool is_static_field, success;
263 jvalue java_value;
264 JavaSignature *signature;
265 JavaSignatureChar field_type;
266 jfieldID fieldID = field_spec->fieldID;
268 is_static_field = field_spec->modifiers & ACC_STATIC;
270 #define GET_JAVA_FIELD(Type,member) \
271 JS_BEGIN_MACRO \
272 if (is_static_field) \
273 java_value.member = \
274 (*jEnv)->GetStatic##Type##Field(jEnv, (*jEnv)->GetObjectClass(jEnv, java_obj), fieldID); \
275 else \
276 java_value.member = \
277 (*jEnv)->Get##Type##Field(jEnv, java_obj, fieldID); \
278 if ((*jEnv)->ExceptionOccurred(jEnv)) { \
279 jsj_UnexpectedJavaError(cx, jEnv, "Error reading Java field"); \
280 return JS_FALSE; \
282 JS_END_MACRO
284 signature = field_spec->signature;
285 field_type = signature->type;
286 switch(field_type) {
287 case JAVA_SIGNATURE_BYTE:
288 GET_JAVA_FIELD(Byte,b);
289 break;
291 case JAVA_SIGNATURE_CHAR:
292 GET_JAVA_FIELD(Char,c);
293 break;
295 case JAVA_SIGNATURE_SHORT:
296 GET_JAVA_FIELD(Short,s);
297 break;
299 case JAVA_SIGNATURE_INT:
300 GET_JAVA_FIELD(Int,i);
301 break;
303 case JAVA_SIGNATURE_BOOLEAN:
304 GET_JAVA_FIELD(Boolean,z);
305 break;
307 case JAVA_SIGNATURE_LONG:
308 GET_JAVA_FIELD(Long,j);
309 break;
311 case JAVA_SIGNATURE_FLOAT:
312 GET_JAVA_FIELD(Float,f);
313 break;
315 case JAVA_SIGNATURE_DOUBLE:
316 GET_JAVA_FIELD(Double,d);
317 break;
319 case JAVA_SIGNATURE_UNKNOWN:
320 case JAVA_SIGNATURE_VOID:
321 JS_ASSERT(0); /* Unknown java type signature */
322 return JS_FALSE;
324 /* Non-primitive (reference) type */
325 default:
326 JS_ASSERT(IS_REFERENCE_TYPE(field_type));
327 GET_JAVA_FIELD(Object,l);
328 success = jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_value.l, vp);
329 (*jEnv)->DeleteLocalRef(jEnv, java_value.l);
330 return success;
333 #undef GET_JAVA_FIELD
335 return jsj_ConvertJavaValueToJSValue(cx, jEnv, signature, &java_value, vp);
338 JSBool
339 jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
340 jclass java_obj, jsval js_val)
342 JSBool is_static_field, is_local_ref;
343 int dummy_cost;
344 jvalue java_value;
345 JavaSignature *signature;
346 JavaSignatureChar field_type;
347 jfieldID fieldID = field_spec->fieldID;
349 is_static_field = field_spec->modifiers & ACC_STATIC;
351 #define SET_JAVA_FIELD(Type,member) \
352 JS_BEGIN_MACRO \
353 if (is_static_field) { \
354 (*jEnv)->SetStatic##Type##Field(jEnv, java_obj, fieldID, \
355 java_value.member); \
356 } else { \
357 (*jEnv)->Set##Type##Field(jEnv, java_obj, fieldID,java_value.member);\
359 if ((*jEnv)->ExceptionOccurred(jEnv)) { \
360 jsj_UnexpectedJavaError(cx, jEnv, "Error assigning to Java field"); \
361 return JS_FALSE; \
363 JS_END_MACRO
365 signature = field_spec->signature;
366 if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost,
367 &java_value, &is_local_ref))
368 return JS_FALSE;
370 field_type = signature->type;
371 switch(field_type) {
372 case JAVA_SIGNATURE_BYTE:
373 SET_JAVA_FIELD(Byte,b);
374 break;
376 case JAVA_SIGNATURE_CHAR:
377 SET_JAVA_FIELD(Char,c);
378 break;
380 case JAVA_SIGNATURE_SHORT:
381 SET_JAVA_FIELD(Short,s);
382 break;
384 case JAVA_SIGNATURE_INT:
385 SET_JAVA_FIELD(Int,i);
386 break;
388 case JAVA_SIGNATURE_BOOLEAN:
389 SET_JAVA_FIELD(Boolean,z);
390 break;
392 case JAVA_SIGNATURE_LONG:
393 SET_JAVA_FIELD(Long,j);
394 break;
396 case JAVA_SIGNATURE_FLOAT:
397 SET_JAVA_FIELD(Float,f);
398 break;
400 case JAVA_SIGNATURE_DOUBLE:
401 SET_JAVA_FIELD(Double,d);
402 break;
404 /* Non-primitive (reference) type */
405 default:
406 JS_ASSERT(IS_REFERENCE_TYPE(field_type));
407 SET_JAVA_FIELD(Object,l);
408 if (is_local_ref)
409 (*jEnv)->DeleteLocalRef(jEnv, java_value.l);
410 break;
412 case JAVA_SIGNATURE_UNKNOWN:
413 case JAVA_SIGNATURE_VOID:
414 JS_ASSERT(0); /* Unknown java type signature */
415 return JS_FALSE;
418 #undef SET_JAVA_FIELD
420 return JS_TRUE;