You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2026/07/30 11:06:52 UTC

(commons-beanutils) branch 1.X updated: Sort members

This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch 1.X
in repository https://gitbox.apache.org/repos/asf/commons-beanutils.git


The following commit(s) were added to refs/heads/1.X by this push:
     new cd7afd96 Sort members
cd7afd96 is described below

commit cd7afd96e0f98f83db61b01483319d911dee6d54
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Thu Jul 30 07:06:28 2026 -0400

    Sort members
---
 .../beanutils/DynaPropertySerializationTest.java   | 450 ++++++++++-----------
 1 file changed, 225 insertions(+), 225 deletions(-)

diff --git a/src/test/java/org/apache/commons/beanutils/DynaPropertySerializationTest.java b/src/test/java/org/apache/commons/beanutils/DynaPropertySerializationTest.java
index a8dff23a..214ac700 100644
--- a/src/test/java/org/apache/commons/beanutils/DynaPropertySerializationTest.java
+++ b/src/test/java/org/apache/commons/beanutils/DynaPropertySerializationTest.java
@@ -51,13 +51,17 @@ import org.junit.jupiter.api.Test;
 class DynaPropertySerializationTest {
 
     /**
-     * Serializes {@code prop} to a byte array.
+     * Assert that a round-tripped {@link DynaProperty} is equal to the original and is a distinct object.
      */
-    private static byte[] serialize(final DynaProperty prop) throws IOException {
-        try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) {
-            oos.writeObject(prop);
-            return bos.toByteArray();
-        }
+    private static void assertRoundTrip(final DynaProperty original) throws IOException, ClassNotFoundException {
+        final DynaProperty copy = roundTrip(original);
+        assertNotNull(copy);
+        assertNotSame(original, copy, "Deserialized instance must be a new object");
+        assertEquals(original.getName(), copy.getName(), "name must be preserved");
+        assertEquals(original.getType(), copy.getType(), "type must be preserved");
+        assertEquals(original.getContentType(), copy.getContentType(), "contentType must be preserved");
+        assertEquals(original, copy, "equals() must hold after round-trip");
+        assertEquals(original.hashCode(), copy.hashCode(), "hashCode() must hold after round-trip");
     }
 
     /**
@@ -69,6 +73,21 @@ class DynaPropertySerializationTest {
         }
     }
 
+    /**
+     * Returns the byte-offset of the first occurrence of {@code needle} inside {@code haystack}, or {@code -1} if not found.
+     */
+    private static int findSequence(final byte[] haystack, final byte[] needle) {
+        outer: for (int i = 0; i <= haystack.length - needle.length; i++) {
+            for (int j = 0; j < needle.length; j++) {
+                if (haystack[i + j] != needle[j]) {
+                    continue outer;
+                }
+            }
+            return i;
+        }
+        return -1;
+    }
+
     /**
      * Full round-trip: serialize then deserialize and return the reconstructed instance.
      */
@@ -77,38 +96,116 @@ class DynaPropertySerializationTest {
     }
 
     /**
-     * Assert that a round-tripped {@link DynaProperty} is equal to the original and is a distinct object.
+     * Serializes {@code prop} to a byte array.
      */
-    private static void assertRoundTrip(final DynaProperty original) throws IOException, ClassNotFoundException {
-        final DynaProperty copy = roundTrip(original);
-        assertNotNull(copy);
-        assertNotSame(original, copy, "Deserialized instance must be a new object");
-        assertEquals(original.getName(), copy.getName(), "name must be preserved");
-        assertEquals(original.getType(), copy.getType(), "type must be preserved");
-        assertEquals(original.getContentType(), copy.getContentType(), "contentType must be preserved");
-        assertEquals(original, copy, "equals() must hold after round-trip");
-        assertEquals(original.hashCode(), copy.hashCode(), "hashCode() must hold after round-trip");
+    private static byte[] serialize(final DynaProperty prop) throws IOException {
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+            oos.writeObject(prop);
+            return bos.toByteArray();
+        }
     }
 
     @Test
-    void testRoundTripNameOnly() throws Exception {
-        // DynaProperty(String) uses Object.class as the type
-        assertRoundTrip(new DynaProperty("nameOnly"));
+    void testContentTypeIsNullForSimpleProperty() throws Exception {
+        final DynaProperty copy = roundTrip(new DynaProperty("simple", String.class));
+        assertNull(copy.getContentType(), "Simple (non-indexed, non-mapped) property must have null contentType");
     }
 
     @Test
-    void testRoundTripStringType() throws Exception {
-        assertRoundTrip(new DynaProperty("strProp", String.class));
+    void testIsIndexedPreservedAfterRoundTrip() throws Exception {
+        final DynaProperty indexed = new DynaProperty("idx", List.class, String.class);
+        final DynaProperty copy = roundTrip(indexed);
+        assertEquals(indexed.isIndexed(), copy.isIndexed());
     }
 
     @Test
-    void testRoundTripIntegerWrapperType() throws Exception {
-        assertRoundTrip(new DynaProperty("integerProp", Integer.class));
+    void testIsMappedPreservedAfterRoundTrip() throws Exception {
+        final DynaProperty mapped = new DynaProperty("map", Map.class, Integer.class);
+        final DynaProperty copy = roundTrip(mapped);
+        assertEquals(mapped.isMapped(), copy.isMapped());
     }
 
     @Test
-    void testRoundTripObjectType() throws Exception {
-        assertRoundTrip(new DynaProperty("objProp", Object.class));
+    void testMultipleSerializationsProduceSameResult() throws Exception {
+        final DynaProperty prop = new DynaProperty("multi", Integer.TYPE);
+        final DynaProperty copy1 = roundTrip(prop);
+        final DynaProperty copy2 = roundTrip(prop);
+        assertEquals(copy1, copy2);
+        assertEquals(copy1.hashCode(), copy2.hashCode());
+    }
+
+    @Test
+    void testNameIsPreservedAfterRoundTrip() throws Exception {
+        final String uniqueName = "uniquePropertyName_42";
+        final DynaProperty copy = roundTrip(new DynaProperty(uniqueName, String.class));
+        assertEquals(uniqueName, copy.getName());
+    }
+
+    /**
+     * Variant of the corruption test using a <em>mapped</em> property so that the second {@code readAnyClass} call (for contentType) is the one that receives
+     * the bad constant.
+     */
+    @Test
+    void testReadObjectThrowsStreamCorruptedExceptionForInvalidContentTypePrimitiveConstant() throws Exception {
+        // serialize Map<String, Boolean> vs Map<String, Byte> – the type (Map.class)
+        // is written as a non-primitive class object; the contentType is written as a
+        // primitive-type constant.
+        final byte[] boolContentBytes = serialize(new DynaProperty("corruptContent", Map.class, Boolean.TYPE));
+        final byte[] byteContentBytes = serialize(new DynaProperty("corruptContent", Map.class, Byte.TYPE));
+        int diffIndex = -1;
+        for (int i = 0; i < boolContentBytes.length; i++) {
+            if (boolContentBytes[i] != byteContentBytes[i]) {
+                diffIndex = i;
+                break;
+            }
+        }
+        assertNotNull(Integer.valueOf(diffIndex), "Streams must differ at the contentType primitive-type int");
+        final byte[] corrupted = boolContentBytes.clone();
+        corrupted[diffIndex - 3] = 0x00;
+        corrupted[diffIndex - 2] = 0x00;
+        corrupted[diffIndex - 1] = 0x00;
+        corrupted[diffIndex] = (byte) 99;
+        final IOException thrown = assertThrows(IOException.class, () -> deserialize(corrupted),
+                "Expected StreamCorruptedException for unrecognised primitive contentType constant");
+        assertInstanceOf(StreamCorruptedException.class, thrown, "Root cause must be StreamCorruptedException");
+    }
+
+    /**
+     * Verifies that {@link DynaProperty#readObject(ObjectInputStream)} throws a {@link StreamCorruptedException} when the stream contains an unrecognised
+     * primitive-type constant (i.e. an integer that is not in the range 1–8).
+     * <p>
+     * Strategy: serialize two {@code DynaProperty} instances whose types differ only in the primitive-type constant written by {@code writeAnyClass}
+     * (BOOLEAN_TYPE=1 vs BYTE_TYPE=2). Find the first differing byte (the last byte of the 4-byte int), then replace those 4 bytes with the invalid constant 99
+     * before attempting deserialisation.
+     * </p>
+     */
+    @Test
+    void testReadObjectThrowsStreamCorruptedExceptionForInvalidPrimitiveTypeConstant() throws Exception {
+        // serialize a DynaProperty whose type is stored as BOOLEAN_TYPE (int 1)
+        final byte[] booleanBytes = serialize(new DynaProperty("corrupt", Boolean.TYPE));
+        // serialize the same name/class but with BYTE_TYPE (int 2) to locate the int
+        final byte[] byteBytes = serialize(new DynaProperty("corrupt", Byte.TYPE));
+        // The two streams should be identical except for the last byte of the 4-byte
+        // primitive-type int (0x01 vs 0x02). Find the first (and only) differing byte.
+        int diffIndex = -1;
+        for (int i = 0; i < booleanBytes.length; i++) {
+            if (booleanBytes[i] != byteBytes[i]) {
+                diffIndex = i;
+                break;
+            }
+        }
+        assertNotNull(Integer.valueOf(diffIndex), "Streams must differ at the primitive-type int");
+        // The 4-byte int starts 3 bytes before the differing byte (big-endian).
+        // Overwrite all 4 bytes with the invalid constant 99 (0x00_00_00_63).
+        final byte[] corrupted = booleanBytes.clone();
+        corrupted[diffIndex - 3] = 0x00;
+        corrupted[diffIndex - 2] = 0x00;
+        corrupted[diffIndex - 1] = 0x00;
+        corrupted[diffIndex] = (byte) 99;
+        // Deserialising the corrupted stream must throw StreamCorruptedException.
+        final IOException thrown = assertThrows(IOException.class, () -> deserialize(corrupted),
+                "Expected StreamCorruptedException for unrecognised primitive-type constant");
+        assertInstanceOf(StreamCorruptedException.class, thrown, "Root cause must be StreamCorruptedException");
     }
 
     @Test
@@ -127,44 +224,41 @@ class DynaPropertySerializationTest {
     }
 
     @Test
-    void testRoundTripDoublePrimitiveType() throws Exception {
-        assertRoundTrip(new DynaProperty("doubleProp", Double.TYPE));
+    void testRoundTripConcreteListSubtype() throws Exception {
+        // ArrayList also satisfies isIndexed()
+        assertRoundTrip(new DynaProperty("arrayListProp", ArrayList.class, String.class));
     }
 
     @Test
-    void testRoundTripFloatPrimitiveType() throws Exception {
-        assertRoundTrip(new DynaProperty("floatProp", Float.TYPE));
+    void testRoundTripConcreteMapSubtype() throws Exception {
+        // HashMap also satisfies isMapped()
+        assertRoundTrip(new DynaProperty("hashMapProp", HashMap.class, Double.TYPE));
     }
 
     @Test
-    void testRoundTripIntPrimitiveType() throws Exception {
-        assertRoundTrip(new DynaProperty("intProp", Integer.TYPE));
+    void testRoundTripDoublePrimitiveType() throws Exception {
+        assertRoundTrip(new DynaProperty("doubleProp", Double.TYPE));
     }
 
     @Test
-    void testRoundTripLongPrimitiveType() throws Exception {
-        assertRoundTrip(new DynaProperty("longProp", Long.TYPE));
+    void testRoundTripFloatPrimitiveType() throws Exception {
+        assertRoundTrip(new DynaProperty("floatProp", Float.TYPE));
     }
 
     @Test
-    void testRoundTripShortPrimitiveType() throws Exception {
-        assertRoundTrip(new DynaProperty("shortProp", Short.TYPE));
+    void testRoundTripIntegerWrapperType() throws Exception {
+        assertRoundTrip(new DynaProperty("integerProp", Integer.class));
     }
 
     @Test
-    void testRoundTripObjectArrayType() throws Exception {
-        // String[] – contentType is String.class (non-primitive)
-        assertRoundTrip(new DynaProperty("strArrayProp", String[].class));
+    void testRoundTripIntPrimitiveType() throws Exception {
+        assertRoundTrip(new DynaProperty("intProp", Integer.TYPE));
     }
 
     @Test
-    void testRoundTripPrimitiveArrayType() throws Exception {
-        // int[] – constructor sets contentType = Integer.TYPE (primitive)
-        final DynaProperty prop = new DynaProperty("intArrayProp", int[].class);
-        assertRoundTrip(prop);
-        // Verify contentType is correctly restored as the primitive type
-        final DynaProperty copy = roundTrip(prop);
-        assertEquals(Integer.TYPE, copy.getContentType());
+    void testRoundTripListTypeWithExplicitContentType() throws Exception {
+        // List<String> – explicit contentType is an object class
+        assertRoundTrip(new DynaProperty("typedListProp", List.class, String.class));
     }
 
     @Test
@@ -173,12 +267,6 @@ class DynaPropertySerializationTest {
         assertRoundTrip(new DynaProperty("listProp", List.class));
     }
 
-    @Test
-    void testRoundTripListTypeWithExplicitContentType() throws Exception {
-        // List<String> – explicit contentType is an object class
-        assertRoundTrip(new DynaProperty("typedListProp", List.class, String.class));
-    }
-
     @Test
     void testRoundTripListTypeWithPrimitiveContentType() throws Exception {
         // List<int> – explicit contentType is a primitive type
@@ -186,9 +274,8 @@ class DynaPropertySerializationTest {
     }
 
     @Test
-    void testRoundTripConcreteListSubtype() throws Exception {
-        // ArrayList also satisfies isIndexed()
-        assertRoundTrip(new DynaProperty("arrayListProp", ArrayList.class, String.class));
+    void testRoundTripLongPrimitiveType() throws Exception {
+        assertRoundTrip(new DynaProperty("longProp", Long.TYPE));
     }
 
     @Test
@@ -210,61 +297,40 @@ class DynaPropertySerializationTest {
     }
 
     @Test
-    void testRoundTripConcreteMapSubtype() throws Exception {
-        // HashMap also satisfies isMapped()
-        assertRoundTrip(new DynaProperty("hashMapProp", HashMap.class, Double.TYPE));
-    }
-
-    @Test
-    void testNameIsPreservedAfterRoundTrip() throws Exception {
-        final String uniqueName = "uniquePropertyName_42";
-        final DynaProperty copy = roundTrip(new DynaProperty(uniqueName, String.class));
-        assertEquals(uniqueName, copy.getName());
-    }
-
-    @Test
-    void testTypeIsPreservedAfterRoundTripForEveryPrimitive() throws Exception {
-        final Class<?>[] primitives = { Boolean.TYPE, Byte.TYPE, Character.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE, Short.TYPE };
-        for (final Class<?> primitive : primitives) {
-            final DynaProperty copy = roundTrip(new DynaProperty("p", primitive));
-            assertEquals(primitive, copy.getType(), () -> "type must be preserved for primitive " + primitive.getName());
-        }
+    void testRoundTripNameOnly() throws Exception {
+        // DynaProperty(String) uses Object.class as the type
+        assertRoundTrip(new DynaProperty("nameOnly"));
     }
 
     @Test
-    void testContentTypeIsNullForSimpleProperty() throws Exception {
-        final DynaProperty copy = roundTrip(new DynaProperty("simple", String.class));
-        assertNull(copy.getContentType(), "Simple (non-indexed, non-mapped) property must have null contentType");
+    void testRoundTripObjectArrayType() throws Exception {
+        // String[] – contentType is String.class (non-primitive)
+        assertRoundTrip(new DynaProperty("strArrayProp", String[].class));
     }
 
     @Test
-    void testIsIndexedPreservedAfterRoundTrip() throws Exception {
-        final DynaProperty indexed = new DynaProperty("idx", List.class, String.class);
-        final DynaProperty copy = roundTrip(indexed);
-        assertEquals(indexed.isIndexed(), copy.isIndexed());
+    void testRoundTripObjectType() throws Exception {
+        assertRoundTrip(new DynaProperty("objProp", Object.class));
     }
 
     @Test
-    void testIsMappedPreservedAfterRoundTrip() throws Exception {
-        final DynaProperty mapped = new DynaProperty("map", Map.class, Integer.class);
-        final DynaProperty copy = roundTrip(mapped);
-        assertEquals(mapped.isMapped(), copy.isMapped());
+    void testRoundTripPrimitiveArrayType() throws Exception {
+        // int[] – constructor sets contentType = Integer.TYPE (primitive)
+        final DynaProperty prop = new DynaProperty("intArrayProp", int[].class);
+        assertRoundTrip(prop);
+        // Verify contentType is correctly restored as the primitive type
+        final DynaProperty copy = roundTrip(prop);
+        assertEquals(Integer.TYPE, copy.getContentType());
     }
 
     @Test
-    void testToStringAfterRoundTrip() throws Exception {
-        final DynaProperty original = new DynaProperty("myProp", List.class, String.class);
-        final DynaProperty copy = roundTrip(original);
-        assertEquals(original.toString(), copy.toString());
+    void testRoundTripShortPrimitiveType() throws Exception {
+        assertRoundTrip(new DynaProperty("shortProp", Short.TYPE));
     }
 
     @Test
-    void testMultipleSerializationsProduceSameResult() throws Exception {
-        final DynaProperty prop = new DynaProperty("multi", Integer.TYPE);
-        final DynaProperty copy1 = roundTrip(prop);
-        final DynaProperty copy2 = roundTrip(prop);
-        assertEquals(copy1, copy2);
-        assertEquals(copy1.hashCode(), copy2.hashCode());
+    void testRoundTripStringType() throws Exception {
+        assertRoundTrip(new DynaProperty("strProp", String.class));
     }
 
     @Test
@@ -276,129 +342,59 @@ class DynaPropertySerializationTest {
         assertEquals(original, copy2);
     }
 
-    /**
-     * Verifies that {@link DynaProperty#readObject(ObjectInputStream)} throws a {@link StreamCorruptedException} when the stream contains an unrecognised
-     * primitive-type constant (i.e. an integer that is not in the range 1–8).
-     * <p>
-     * Strategy: serialize two {@code DynaProperty} instances whose types differ only in the primitive-type constant written by {@code writeAnyClass}
-     * (BOOLEAN_TYPE=1 vs BYTE_TYPE=2). Find the first differing byte (the last byte of the 4-byte int), then replace those 4 bytes with the invalid constant 99
-     * before attempting deserialisation.
-     * </p>
-     */
     @Test
-    void testReadObjectThrowsStreamCorruptedExceptionForInvalidPrimitiveTypeConstant() throws Exception {
-        // serialize a DynaProperty whose type is stored as BOOLEAN_TYPE (int 1)
-        final byte[] booleanBytes = serialize(new DynaProperty("corrupt", Boolean.TYPE));
-        // serialize the same name/class but with BYTE_TYPE (int 2) to locate the int
-        final byte[] byteBytes = serialize(new DynaProperty("corrupt", Byte.TYPE));
-        // The two streams should be identical except for the last byte of the 4-byte
-        // primitive-type int (0x01 vs 0x02). Find the first (and only) differing byte.
-        int diffIndex = -1;
-        for (int i = 0; i < booleanBytes.length; i++) {
-            if (booleanBytes[i] != byteBytes[i]) {
-                diffIndex = i;
-                break;
-            }
-        }
-        assertNotNull(Integer.valueOf(diffIndex), "Streams must differ at the primitive-type int");
-        // The 4-byte int starts 3 bytes before the differing byte (big-endian).
-        // Overwrite all 4 bytes with the invalid constant 99 (0x00_00_00_63).
-        final byte[] corrupted = booleanBytes.clone();
-        corrupted[diffIndex - 3] = 0x00;
-        corrupted[diffIndex - 2] = 0x00;
-        corrupted[diffIndex - 1] = 0x00;
-        corrupted[diffIndex] = (byte) 99;
-        // Deserialising the corrupted stream must throw StreamCorruptedException.
-        final IOException thrown = assertThrows(IOException.class, () -> deserialize(corrupted),
-                "Expected StreamCorruptedException for unrecognised primitive-type constant");
-        assertInstanceOf(StreamCorruptedException.class, thrown, "Root cause must be StreamCorruptedException");
+    void testToStringAfterRoundTrip() throws Exception {
+        final DynaProperty original = new DynaProperty("myProp", List.class, String.class);
+        final DynaProperty copy = roundTrip(original);
+        assertEquals(original.toString(), copy.toString());
     }
 
-    /**
-     * Variant of the corruption test using a <em>mapped</em> property so that the second {@code readAnyClass} call (for contentType) is the one that receives
-     * the bad constant.
-     */
     @Test
-    void testReadObjectThrowsStreamCorruptedExceptionForInvalidContentTypePrimitiveConstant() throws Exception {
-        // serialize Map<String, Boolean> vs Map<String, Byte> – the type (Map.class)
-        // is written as a non-primitive class object; the contentType is written as a
-        // primitive-type constant.
-        final byte[] boolContentBytes = serialize(new DynaProperty("corruptContent", Map.class, Boolean.TYPE));
-        final byte[] byteContentBytes = serialize(new DynaProperty("corruptContent", Map.class, Byte.TYPE));
-        int diffIndex = -1;
-        for (int i = 0; i < boolContentBytes.length; i++) {
-            if (boolContentBytes[i] != byteContentBytes[i]) {
-                diffIndex = i;
-                break;
-            }
-        }
-        assertNotNull(Integer.valueOf(diffIndex), "Streams must differ at the contentType primitive-type int");
-        final byte[] corrupted = boolContentBytes.clone();
-        corrupted[diffIndex - 3] = 0x00;
-        corrupted[diffIndex - 2] = 0x00;
-        corrupted[diffIndex - 1] = 0x00;
-        corrupted[diffIndex] = (byte) 99;
-        final IOException thrown = assertThrows(IOException.class, () -> deserialize(corrupted),
-                "Expected StreamCorruptedException for unrecognised primitive contentType constant");
-        assertInstanceOf(StreamCorruptedException.class, thrown, "Root cause must be StreamCorruptedException");
-    }
-
-    /**
-     * Returns the byte-offset of the first occurrence of {@code needle} inside {@code haystack}, or {@code -1} if not found.
-     */
-    private static int findSequence(final byte[] haystack, final byte[] needle) {
-        outer: for (int i = 0; i <= haystack.length - needle.length; i++) {
-            for (int j = 0; j < needle.length; j++) {
-                if (haystack[i + j] != needle[j]) {
-                    continue outer;
-                }
-            }
-            return i;
+    void testTypeIsPreservedAfterRoundTripForEveryPrimitive() throws Exception {
+        final Class<?>[] primitives = { Boolean.TYPE, Byte.TYPE, Character.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE, Short.TYPE };
+        for (final Class<?> primitive : primitives) {
+            final DynaProperty copy = roundTrip(new DynaProperty("p", primitive));
+            assertEquals(primitive, copy.getType(), () -> "type must be preserved for primitive " + primitive.getName());
         }
-        return -1;
     }
 
     /**
-     * Proves that {@link DynaProperty#writeObject(ObjectOutputStream)} calls {@code writeAnyClass} (which encodes the {@code type} field) <em>before</em>
-     * {@code defaultWriteObject} (which encodes the {@code name} field) for <strong>primitive types</strong>.
+     * Proves that for <strong>indexed and mapped properties</strong> the second {@code writeAnyClass} call (for {@code contentType}) also appears in the byte
+     * stream <em>before</em> the {@code name} field written by {@code defaultWriteObject}.
      * <p>
-     * Strategy: serialise two {@link DynaProperty} instances that have an identical {@code name} but different primitive types. Because the name is identical,
-     * both byte streams are the same from the class-descriptor through to the end of the default-field data. The streams diverge only at the
-     * {@code writeAnyClass} output (the primitive-type integer constant). If that divergence point is located <em>before</em> the name bytes in the stream, it
-     * proves that {@code writeAnyClass} is called first.
+     * Two mapped properties share the same name and the same {@code Map.class} type but differ in their {@code contentType} ({@code Boolean.TYPE} vs
+     * {@code Byte.TYPE}). Because the type ({@code Map.class}) is identical, the streams are the same through the first {@code writeAnyClass} call. They
+     * diverge at the second {@code writeAnyClass} call (contentType constant), which must still precede the name.
      * </p>
      */
     @Test
-    void testWireFormatPrimitiveTypeDataPrecedesNameField() throws Exception {
-        final String sharedName = "sharedPrimitiveName";
-        // Boolean.TYPE encodes as writeBoolean(true) + writeInt(BOOLEAN_TYPE=1).
-        // Byte.TYPE encodes as writeBoolean(true) + writeInt(BYTE_TYPE=2).
-        // The two streams are byte-for-byte identical except at the primitive-type int.
-        final byte[] boolBytes = serialize(new DynaProperty(sharedName, Boolean.TYPE));
-        final byte[] byteBytes = serialize(new DynaProperty(sharedName, Byte.TYPE));
-        // Locate the shared name in the boolean-type stream.
+    void testWireFormatContentTypeDataPrecedesNameFieldForMappedProperty() throws Exception {
+        final String sharedName = "sharedMappedName";
+        // Both use Map.class as the type (identical first writeAnyClass output).
+        // They differ only in contentType: Boolean.TYPE (constant 1) vs Byte.TYPE (constant 2).
+        final byte[] boolContentBytes = serialize(new DynaProperty(sharedName, Map.class, Boolean.TYPE));
+        final byte[] byteContentBytes = serialize(new DynaProperty(sharedName, Map.class, Byte.TYPE));
         final byte[] nameBytes = sharedName.getBytes(StandardCharsets.UTF_8);
-        final int namePosition = findSequence(boolBytes, nameBytes);
-        assertTrue(namePosition > 0, "Property name must be present in the serialized stream");
-        // The name must occupy the same position in both streams (identical name, identical class).
-        assertEquals(namePosition, findSequence(byteBytes, nameBytes), "Name must be at the same byte position in both streams");
-        // Find the first byte where the two streams diverge: this is inside the
-        // writeAnyClass output (the primitive-type integer constant differs: 1 vs 2).
+        final int namePosition = findSequence(boolContentBytes, nameBytes);
+        assertTrue(namePosition > 0, "Name must be present in the serialized stream");
+        assertEquals(namePosition, findSequence(byteContentBytes, nameBytes), "Name must be at the same byte position in both streams");
+        // The streams are identical up to (and including) the type encoding of Map.class.
+        // They diverge at the contentType constant written by the second writeAnyClass call.
         int firstDiff = -1;
-        for (int i = 0; i < boolBytes.length; i++) {
-            if (boolBytes[i] != byteBytes[i]) {
+        for (int i = 0; i < boolContentBytes.length; i++) {
+            if (boolContentBytes[i] != byteContentBytes[i]) {
                 firstDiff = i;
                 break;
             }
         }
-        assertTrue(firstDiff >= 0, "Streams must diverge at the primitive-type constant");
-        // CRITICAL assertion: the divergence point (type data from writeAnyClass) must
-        // come BEFORE the name field (from defaultWriteObject).
-        assertTrue(firstDiff < namePosition, "writeAnyClass must be invoked before defaultWriteObject: " + "type-data divergence at byte " + firstDiff
-                + " must precede name field at byte " + namePosition);
-        // Sanity-check: both properties still round-trip correctly.
-        assertRoundTrip(new DynaProperty(sharedName, Boolean.TYPE));
-        assertRoundTrip(new DynaProperty(sharedName, Byte.TYPE));
+        assertTrue(firstDiff >= 0, "Streams must diverge at the contentType primitive-type constant");
+        // The second writeAnyClass output (contentType) must still precede the name
+        // (defaultWriteObject), confirming that both writeAnyClass calls happen before
+        // defaultWriteObject is invoked.
+        assertTrue(firstDiff < namePosition, "The second writeAnyClass call (contentType) must precede defaultWriteObject: "
+                + "content-type divergence at byte " + firstDiff + " must precede name at byte " + namePosition);
+        assertRoundTrip(new DynaProperty(sharedName, Map.class, Boolean.TYPE));
+        assertRoundTrip(new DynaProperty(sharedName, Map.class, Byte.TYPE));
     }
 
     /**
@@ -444,41 +440,45 @@ class DynaPropertySerializationTest {
     }
 
     /**
-     * Proves that for <strong>indexed and mapped properties</strong> the second {@code writeAnyClass} call (for {@code contentType}) also appears in the byte
-     * stream <em>before</em> the {@code name} field written by {@code defaultWriteObject}.
+     * Proves that {@link DynaProperty#writeObject(ObjectOutputStream)} calls {@code writeAnyClass} (which encodes the {@code type} field) <em>before</em>
+     * {@code defaultWriteObject} (which encodes the {@code name} field) for <strong>primitive types</strong>.
      * <p>
-     * Two mapped properties share the same name and the same {@code Map.class} type but differ in their {@code contentType} ({@code Boolean.TYPE} vs
-     * {@code Byte.TYPE}). Because the type ({@code Map.class}) is identical, the streams are the same through the first {@code writeAnyClass} call. They
-     * diverge at the second {@code writeAnyClass} call (contentType constant), which must still precede the name.
+     * Strategy: serialise two {@link DynaProperty} instances that have an identical {@code name} but different primitive types. Because the name is identical,
+     * both byte streams are the same from the class-descriptor through to the end of the default-field data. The streams diverge only at the
+     * {@code writeAnyClass} output (the primitive-type integer constant). If that divergence point is located <em>before</em> the name bytes in the stream, it
+     * proves that {@code writeAnyClass} is called first.
      * </p>
      */
     @Test
-    void testWireFormatContentTypeDataPrecedesNameFieldForMappedProperty() throws Exception {
-        final String sharedName = "sharedMappedName";
-        // Both use Map.class as the type (identical first writeAnyClass output).
-        // They differ only in contentType: Boolean.TYPE (constant 1) vs Byte.TYPE (constant 2).
-        final byte[] boolContentBytes = serialize(new DynaProperty(sharedName, Map.class, Boolean.TYPE));
-        final byte[] byteContentBytes = serialize(new DynaProperty(sharedName, Map.class, Byte.TYPE));
+    void testWireFormatPrimitiveTypeDataPrecedesNameField() throws Exception {
+        final String sharedName = "sharedPrimitiveName";
+        // Boolean.TYPE encodes as writeBoolean(true) + writeInt(BOOLEAN_TYPE=1).
+        // Byte.TYPE encodes as writeBoolean(true) + writeInt(BYTE_TYPE=2).
+        // The two streams are byte-for-byte identical except at the primitive-type int.
+        final byte[] boolBytes = serialize(new DynaProperty(sharedName, Boolean.TYPE));
+        final byte[] byteBytes = serialize(new DynaProperty(sharedName, Byte.TYPE));
+        // Locate the shared name in the boolean-type stream.
         final byte[] nameBytes = sharedName.getBytes(StandardCharsets.UTF_8);
-        final int namePosition = findSequence(boolContentBytes, nameBytes);
-        assertTrue(namePosition > 0, "Name must be present in the serialized stream");
-        assertEquals(namePosition, findSequence(byteContentBytes, nameBytes), "Name must be at the same byte position in both streams");
-        // The streams are identical up to (and including) the type encoding of Map.class.
-        // They diverge at the contentType constant written by the second writeAnyClass call.
+        final int namePosition = findSequence(boolBytes, nameBytes);
+        assertTrue(namePosition > 0, "Property name must be present in the serialized stream");
+        // The name must occupy the same position in both streams (identical name, identical class).
+        assertEquals(namePosition, findSequence(byteBytes, nameBytes), "Name must be at the same byte position in both streams");
+        // Find the first byte where the two streams diverge: this is inside the
+        // writeAnyClass output (the primitive-type integer constant differs: 1 vs 2).
         int firstDiff = -1;
-        for (int i = 0; i < boolContentBytes.length; i++) {
-            if (boolContentBytes[i] != byteContentBytes[i]) {
+        for (int i = 0; i < boolBytes.length; i++) {
+            if (boolBytes[i] != byteBytes[i]) {
                 firstDiff = i;
                 break;
             }
         }
-        assertTrue(firstDiff >= 0, "Streams must diverge at the contentType primitive-type constant");
-        // The second writeAnyClass output (contentType) must still precede the name
-        // (defaultWriteObject), confirming that both writeAnyClass calls happen before
-        // defaultWriteObject is invoked.
-        assertTrue(firstDiff < namePosition, "The second writeAnyClass call (contentType) must precede defaultWriteObject: "
-                + "content-type divergence at byte " + firstDiff + " must precede name at byte " + namePosition);
-        assertRoundTrip(new DynaProperty(sharedName, Map.class, Boolean.TYPE));
-        assertRoundTrip(new DynaProperty(sharedName, Map.class, Byte.TYPE));
+        assertTrue(firstDiff >= 0, "Streams must diverge at the primitive-type constant");
+        // CRITICAL assertion: the divergence point (type data from writeAnyClass) must
+        // come BEFORE the name field (from defaultWriteObject).
+        assertTrue(firstDiff < namePosition, "writeAnyClass must be invoked before defaultWriteObject: " + "type-data divergence at byte " + firstDiff
+                + " must precede name field at byte " + namePosition);
+        // Sanity-check: both properties still round-trip correctly.
+        assertRoundTrip(new DynaProperty(sharedName, Boolean.TYPE));
+        assertRoundTrip(new DynaProperty(sharedName, Byte.TYPE));
     }
 }