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
16 * The Original Code is Mozilla Communicator client code, released
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.
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.
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.
59 add_java_field_to_class_descriptor(JSContext
*cx
,
61 JavaClassDescriptor
*class_descriptor
,
62 jstring field_name_jstr
,
63 jobject java_field
, /* a java.lang.reflect.Field */
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
);
81 member_descriptor
= jsj_GetJavaMemberDescriptor(cx
, jEnv
, class_descriptor
, field_name_jstr
);
83 if (!member_descriptor
)
86 field_spec
= (JavaFieldSpec
*)JS_malloc(cx
, sizeof(JavaFieldSpec
));
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
);
95 jsj_UnexpectedJavaError(cx
, jEnv
,
96 "Unable to determine type of field using"
97 " java.lang.reflect.Field.getType()");
101 signature
= jsj_GetJavaClassDescriptor(cx
, jEnv
, fieldType
);
102 (*jEnv
)->DeleteLocalRef(jEnv
, fieldType
);
105 field_spec
->signature
= signature
;
107 field_name
= jsj_DupJavaStringUTF(cx
, jEnv
, field_name_jstr
);
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
);
117 /* Compute the JNI fieldID and cache it for quick field access */
118 java_class
= class_descriptor
->java_class
;
120 fieldID
= (*jEnv
)->GetStaticFieldID(jEnv
, java_class
, field_name
, sig_cstr
);
122 fieldID
= (*jEnv
)->GetFieldID(jEnv
, java_class
, field_name
, sig_cstr
);
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
);
129 field_spec
->fieldID
= fieldID
;
131 JS_free(cx
, (char*)sig_cstr
);
133 member_descriptor
->field
= 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
);
145 jsj_ReleaseJavaClassDescriptor(cx
, jEnv
, signature
);
150 * Free up a JavaFieldSpec and all its resources.
153 jsj_DestroyFieldSpec(JSContext
*cx
, JNIEnv
*jEnv
, JavaFieldSpec
*field
)
155 JS_FREE_IF(cx
, (char*)field
->name
);
156 jsj_ReleaseJavaClassDescriptor(cx
, jEnv
, field
->signature
);
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
168 * Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
171 jsj_ReflectJavaFields(JSContext
*cx
, JNIEnv
*jEnv
, JavaClassDescriptor
*class_descriptor
,
172 JSBool reflect_only_static_fields
)
178 jstring field_name_jstr
;
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
);
188 jsj_UnexpectedJavaError(cx
, jEnv
,
189 "Can't determine Java object's fields "
190 "using java.lang.Class.getFields()");
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
);
201 jsj_UnexpectedJavaError(cx
, jEnv
, "Can't access a Field[] array");
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()");
214 /* Don't allow access to private or protected Java fields. */
215 if (!(modifiers
& ACC_PUBLIC
))
218 /* Reflect all instance fields or all static fields, but not both */
219 if (reflect_only_static_fields
!= ((modifiers
& ACC_STATIC
) != 0))
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()");
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
);
237 (*jEnv
)->DeleteLocalRef(jEnv
, field_name_jstr
);
238 field_name_jstr
= NULL
;
241 (*jEnv
)->DeleteLocalRef(jEnv
, java_field
);
245 (*jEnv
)->DeleteLocalRef(jEnv
, joFieldArray
);
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.
259 jsj_GetJavaFieldValue(JSContext
*cx
, JNIEnv
*jEnv
, JavaFieldSpec
*field_spec
,
260 jobject java_obj
, jsval
*vp
)
262 JSBool is_static_field
, success
;
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) \
272 if (is_static_field) \
273 java_value.member = \
274 (*jEnv)->GetStatic##Type##Field(jEnv, (*jEnv)->GetObjectClass(jEnv, java_obj), fieldID); \
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"); \
284 signature
= field_spec
->signature
;
285 field_type
= signature
->type
;
287 case JAVA_SIGNATURE_BYTE
:
288 GET_JAVA_FIELD(Byte
,b
);
291 case JAVA_SIGNATURE_CHAR
:
292 GET_JAVA_FIELD(Char
,c
);
295 case JAVA_SIGNATURE_SHORT
:
296 GET_JAVA_FIELD(Short
,s
);
299 case JAVA_SIGNATURE_INT
:
300 GET_JAVA_FIELD(Int
,i
);
303 case JAVA_SIGNATURE_BOOLEAN
:
304 GET_JAVA_FIELD(Boolean
,z
);
307 case JAVA_SIGNATURE_LONG
:
308 GET_JAVA_FIELD(Long
,j
);
311 case JAVA_SIGNATURE_FLOAT
:
312 GET_JAVA_FIELD(Float
,f
);
315 case JAVA_SIGNATURE_DOUBLE
:
316 GET_JAVA_FIELD(Double
,d
);
319 case JAVA_SIGNATURE_UNKNOWN
:
320 case JAVA_SIGNATURE_VOID
:
321 JS_ASSERT(0); /* Unknown java type signature */
324 /* Non-primitive (reference) type */
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
);
333 #undef GET_JAVA_FIELD
335 return jsj_ConvertJavaValueToJSValue(cx
, jEnv
, signature
, &java_value
, vp
);
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
;
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) \
353 if (is_static_field) { \
354 (*jEnv)->SetStatic##Type##Field(jEnv, java_obj, fieldID, \
355 java_value.member); \
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"); \
365 signature
= field_spec
->signature
;
366 if (!jsj_ConvertJSValueToJavaValue(cx
, jEnv
, js_val
, signature
, &dummy_cost
,
367 &java_value
, &is_local_ref
))
370 field_type
= signature
->type
;
372 case JAVA_SIGNATURE_BYTE
:
373 SET_JAVA_FIELD(Byte
,b
);
376 case JAVA_SIGNATURE_CHAR
:
377 SET_JAVA_FIELD(Char
,c
);
380 case JAVA_SIGNATURE_SHORT
:
381 SET_JAVA_FIELD(Short
,s
);
384 case JAVA_SIGNATURE_INT
:
385 SET_JAVA_FIELD(Int
,i
);
388 case JAVA_SIGNATURE_BOOLEAN
:
389 SET_JAVA_FIELD(Boolean
,z
);
392 case JAVA_SIGNATURE_LONG
:
393 SET_JAVA_FIELD(Long
,j
);
396 case JAVA_SIGNATURE_FLOAT
:
397 SET_JAVA_FIELD(Float
,f
);
400 case JAVA_SIGNATURE_DOUBLE
:
401 SET_JAVA_FIELD(Double
,d
);
404 /* Non-primitive (reference) type */
406 JS_ASSERT(IS_REFERENCE_TYPE(field_type
));
407 SET_JAVA_FIELD(Object
,l
);
409 (*jEnv
)->DeleteLocalRef(jEnv
, java_value
.l
);
412 case JAVA_SIGNATURE_UNKNOWN
:
413 case JAVA_SIGNATURE_VOID
:
414 JS_ASSERT(0); /* Unknown java type signature */
418 #undef SET_JAVA_FIELD