When a Java class is built into a Python JType, all static+final variables are read and stored in the __dict__
|
if (isStatic && isFinal) { |
|
// Add static final values to the JPy_JType's tp_dict. |
|
// todo: Note that this is a workaround only, because the JPy_JType's tp_getattro slot is not called. |
|
if (JType_AddFieldAttribute(jenv, declaringClass, fieldKey, fieldType, fid) < 0) { |
|
return -1; |
|
} |
Non-static fields each have an instance field built for them, for when instances are interacted with:
|
} else if (!isStatic) { |
|
// Add instance field accessor to the JPy_JType's tp_dict, this will be evaluated in the JPy_JType's tp_setattro and tp_getattro slots. |
|
field = JField_New(declaringClass, fieldKey, fieldType, isStatic, isFinal, fid); |
|
if (field == NULL) { |
|
JPy_DIAG_PRINT(JPy_DIAG_F_TYPE + JPy_DIAG_F_ERR, "JType_ProcessField: WARNING: Java field '%s' rejected because an error occurred during field instantiation\n", fieldName); |
|
return -1; |
|
} |
|
|
|
if (JType_AcceptField(declaringClass, field)) { |
|
JType_AddField(declaringClass, field); |
|
} else { |
|
JField_Del(field); |
|
} |
But non-final static fields are ignored:
|
} else { |
|
JPy_DIAG_PRINT(JPy_DIAG_F_TYPE + JPy_DIAG_F_ERR, "JType_ProcessField: WARNING: Java field '%s' rejected because is is static, but not final\n", fieldName); |
|
} |
Unfortunately, final fields are not always immutable - in the JVM there are several ways to modify final fields:
- Reflection API (through Field.setAccessible())
- java.lang.invoke (through Lookup.unreflect() since there's no way to get a setter for a final field)
- JNI (SetXXXField())
- sun.misc.Unsafe (setXXX()/setXXXUnaligned())
One easy example here is System.out - while this is final, the class also has System.setOut(PrintStream), allowing runtime code to replace the out instance (presumably implemented in JNI, I haven't checked). Invoking System.setOut() has no impact on the System.out value, from the perspective of Python via jpy.
The post at https://shipilev.net/jvm/anatomy-quarks/17-trust-nonstatic-final-fields/ has more good discussion on this - the latter shows some heuristics that the JVM uses when "trusting" final fields, but the answer is mostly "don't trust them".
Instead of assigning members on the dict for fields, we probably should offer an implementation for tp_getset or some other way to let the field be read/written programmatically? I might be interpreting this wrong.
When a Java class is built into a Python JType, all
static+finalvariables are read and stored in the__dict__jpy/src/main/c/jpy_jtype.c
Lines 1467 to 1472 in a8c43da
Non-static fields each have an instance field built for them, for when instances are interacted with:
jpy/src/main/c/jpy_jtype.c
Lines 1473 to 1485 in a8c43da
But non-final
staticfields are ignored:jpy/src/main/c/jpy_jtype.c
Lines 1486 to 1488 in a8c43da
Unfortunately,
finalfields are not always immutable - in the JVM there are several ways to modify final fields:One easy example here is
System.out- while this is final, the class also hasSystem.setOut(PrintStream), allowing runtime code to replace theoutinstance (presumably implemented in JNI, I haven't checked). Invoking System.setOut() has no impact on the System.out value, from the perspective of Python via jpy.The post at https://shipilev.net/jvm/anatomy-quarks/17-trust-nonstatic-final-fields/ has more good discussion on this - the latter shows some heuristics that the JVM uses when "trusting" final fields, but the answer is mostly "don't trust them".
Instead of assigning members on the dict for fields, we probably should offer an implementation for
tp_getsetor some other way to let the field be read/written programmatically? I might be interpreting this wrong.