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.