src/java.base/share/classes/java/io/ObjectStreamClass.java
Print this page
@@ -1260,10 +1260,18 @@
void setObjFieldValues(Object obj, Object[] vals) {
fieldRefl.setObjFieldValues(obj, vals);
}
/**
+ * Returns true if the field reflector has one, or more, underlying final
+ * fields.
+ */
+ boolean hasFinalField() {
+ return fieldRefl.hasFinal();
+ }
+
+ /**
* Calculates and sets serializable field offsets, as well as primitive
* data size and object field count totals. Throws InvalidClassException
* if fields are illegally ordered.
*/
private void computeFieldOffsets() throws InvalidClassException {
@@ -1884,10 +1892,12 @@
private final int[] offsets;
/** field type codes */
private final char[] typeCodes;
/** field types */
private final Class<?>[] types;
+ /** true if at least one underlying field is final */
+ private final boolean hasFinal;
/**
* Constructs FieldReflector capable of setting/getting values from the
* subset of fields whose ObjectStreamFields contain non-null
* reflective Field objects. ObjectStreamFields with null Fields are
@@ -1902,30 +1912,46 @@
offsets = new int[nfields];
typeCodes = new char[nfields];
ArrayList<Class<?>> typeList = new ArrayList<>();
Set<Long> usedKeys = new HashSet<>();
-
+ boolean hf = false;
for (int i = 0; i < nfields; i++) {
ObjectStreamField f = fields[i];
Field rf = f.getField();
- long key = (rf != null) ?
- unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
+ long key;
+ if (rf != null) {
+ key = unsafe.objectFieldOffset(rf);
+ if (!hf && isFinal(rf)) {
+ hf = true;
+ }
+ } else {
+ key = Unsafe.INVALID_FIELD_OFFSET;
+ }
readKeys[i] = key;
writeKeys[i] = usedKeys.add(key) ?
key : Unsafe.INVALID_FIELD_OFFSET;
offsets[i] = f.getOffset();
typeCodes[i] = f.getTypeCode();
if (!f.isPrimitive()) {
typeList.add((rf != null) ? rf.getType() : null);
}
}
+ hasFinal = hf;
types = typeList.toArray(new Class<?>[typeList.size()]);
numPrimFields = nfields - types.length;
}
+ private static boolean isFinal(Field field) {
+ return (field.getModifiers() & Modifier.FINAL) != 0;
+ }
+
+ public boolean hasFinal() {
+ return hasFinal;
+ }
+
/**
* Returns list of ObjectStreamFields representing fields operated on
* by this reflector. The shared/unshared values and Field objects
* contained by ObjectStreamFields in the list reflect their bindings
* to locally defined serializable fields.