diff --git a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceLegacyTypeMappingResult.java b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceLegacyTypeMappingResult.java index 1bbdefc2..a0d21d33 100644 --- a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceLegacyTypeMappingResult.java +++ b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceLegacyTypeMappingResult.java @@ -109,15 +109,20 @@ public static boolean isUnchangedStructure( { final PersistenceTypeDefinitionMember legacyMember = legacy.next() ; final PersistenceTypeDefinitionMember currentMember = current.next(); - + // all legacy members must be directly mapped to their order-wise corresponding current member. - if(mapping.get(legacyMember) != currentMember) + final Similarity match = mapping.get(legacyMember); + if(match == null || match.targetElement() != currentMember) { return false; } - - // and the types must be the same, of course. Member names are sound and smoke. - if(!legacyMember.typeName().equals(currentMember.typeName())) + + // the persistent layout of the two members must match. equalsLayout handles every + // member kind (regular fields, primitive definitions, enum constants, complex generic + // fields) via polymorphic dispatch and intentionally ignores member names: the + // mapping/order check above already establishes identity, so a renamed-but-otherwise- + // unchanged member still qualifies for the unchanged-structure fast path. + if(!legacyMember.equalsLayout(currentMember)) { return false; } diff --git a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMember.java b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMember.java index 60ffbfe1..b2cf0eb4 100644 --- a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMember.java +++ b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMember.java @@ -129,16 +129,37 @@ public default boolean equalsDescription(final PersistenceTypeDescriptionMember /** * Structure means equal order of members by type name and simple name.
* Not qualifier, since that is only required for intra-type field identification - * + * * @param other the description to compare to * @return if this and the other description's structure are equal - * - * @see #equalDescription(PersistenceTypeDescriptionMember, PersistenceTypeDescriptionMember) + * + * @see #equalStructure(PersistenceTypeDescriptionMember, PersistenceTypeDescriptionMember) */ public default boolean equalsStructure(final PersistenceTypeDescriptionMember other) { return equalTypeAndName(this, other); } + + /** + * Like {@link #equalsStructure(PersistenceTypeDescriptionMember)} but ignores the member's + * simple name. Compares only the persistent layout (type name; for primitive-definition members + * the bit-layout descriptor; for complex generic fields the nested members compared again by + * layout). + *

+ * Used by the "unchanged structure" fast path in legacy-handler creation, where the identity + * correspondence between legacy and current members is already established by the refactoring + * mapping and only the on-disk layout needs to be confirmed — e.g. a renamed field whose + * type and offset are unchanged still produces the same persisted bytes. + * + * @param other the description to compare to. + * @return if this and the other description's persistent layout are equal. + * + * @see #equalLayout(PersistenceTypeDescriptionMember, PersistenceTypeDescriptionMember) + */ + public default boolean equalsLayout(final PersistenceTypeDescriptionMember other) + { + return other != null && Objects.equals(this.typeName(), other.typeName()); + } /** * Tests whether two members have the same {@link #typeName()} and {@link #name()}. The comparison @@ -203,6 +224,25 @@ public static boolean equalStructure( // must delegate to the implementation since complex fields must deep-check their nested fields return m1 == m2 || m1 != null && m1.equalsStructure(m2); } + + /** + * Static null-safe counterpart to {@link #equalsLayout(PersistenceTypeDescriptionMember)}. + * Delegation to the instance method is required so that complex (nested) member descriptions + * can deep-check their nested members by layout. + * + * @param m1 the first member. + * @param m2 the second member. + * + * @return {@code true} if both members have equal persistent layout. + */ + public static boolean equalLayout( + final PersistenceTypeDescriptionMember m1, + final PersistenceTypeDescriptionMember m2 + ) + { + // must delegate to the implementation since complex fields must deep-check their nested fields + return m1 == m2 || m1 != null && m1.equalsLayout(m2); + } /** * Static counterpart to {@link #equalsDescription(PersistenceTypeDescriptionMember)} that handles a @@ -529,6 +569,23 @@ public static boolean equalStructures( return equalMembers(members1, members2, PersistenceTypeDescriptionMember::equalStructure); } + /** + * Pairwise compares two member sequences using + * {@link #equalLayout(PersistenceTypeDescriptionMember, PersistenceTypeDescriptionMember)}. + * + * @param members1 the first sequence. + * @param members2 the second sequence. + * + * @return {@code true} if the sequences are pairwise equal in persistent layout. + */ + public static boolean equalLayouts( + final XGettingSequence members1, + final XGettingSequence members2 + ) + { + return equalMembers(members1, members2, PersistenceTypeDescriptionMember::equalLayout); + } + /** * Pairwise iterates two member sequences in lock-step and applies the passed {@link Equalator} to * every pair. The iteration intentionally proceeds while either iterator has elements, padding diff --git a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberEnumConstant.java b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberEnumConstant.java index e7b8b9f5..e37ac0b6 100644 --- a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberEnumConstant.java +++ b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberEnumConstant.java @@ -49,6 +49,15 @@ public default boolean equalsStructure(final PersistenceTypeDescriptionMember ot && equalName(this, (PersistenceTypeDescriptionMemberEnumConstant)other) ; } + + @Override + public default boolean equalsLayout(final PersistenceTypeDescriptionMember other) + { + // enum-constant entries have no layout footprint (length 0); identity lives in name(). + // Callers that pair members by mapping/order already establish identity correspondence, + // so layout equality here only confirms both members are enum-constant entries. + return other instanceof PersistenceTypeDescriptionMemberEnumConstant; + } @Override public default boolean equalsDescription(final PersistenceTypeDescriptionMember member) diff --git a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericComplex.java b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericComplex.java index 212ad916..a876f59f 100644 --- a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericComplex.java +++ b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericComplex.java @@ -71,6 +71,18 @@ public default boolean equalsStructure(final PersistenceTypeDescriptionMember ot ) ; } + + @Override + public default boolean equalsLayout(final PersistenceTypeDescriptionMember other) + { + return PersistenceTypeDescriptionMemberFieldGenericVariableLength.super.equalsLayout(other) + && other instanceof PersistenceTypeDescriptionMemberFieldGenericComplex + && PersistenceTypeDescriptionMember.equalLayouts( + this.members(), + ((PersistenceTypeDescriptionMemberFieldGenericComplex)other).members() + ) + ; + } /** * Type-specific overload of diff --git a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericVariableLength.java b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericVariableLength.java index 3153ade0..b4964be8 100644 --- a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericVariableLength.java +++ b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberFieldGenericVariableLength.java @@ -47,6 +47,15 @@ public default boolean equalsStructure(final PersistenceTypeDescriptionMember ot && PersistenceTypeDescriptionMemberFieldGeneric.super.equalsStructure(other) ; } + + @Override + public default boolean equalsLayout(final PersistenceTypeDescriptionMember other) + { + // the type check is the only specific thing here. + return other instanceof PersistenceTypeDescriptionMemberFieldGenericVariableLength + && PersistenceTypeDescriptionMemberFieldGeneric.super.equalsLayout(other) + ; + } /** * Type-specific overload of diff --git a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberPrimitiveDefinition.java b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberPrimitiveDefinition.java index 5da9cbdc..51fa1300 100644 --- a/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberPrimitiveDefinition.java +++ b/persistence/persistence/src/main/java/org/eclipse/serializer/persistence/types/PersistenceTypeDescriptionMemberPrimitiveDefinition.java @@ -65,6 +65,18 @@ public default boolean equalsDescription(final PersistenceTypeDescriptionMember && equalDescription(this, (PersistenceTypeDescriptionMemberPrimitiveDefinition)member) ; } + + @Override + public default boolean equalsLayout(final PersistenceTypeDescriptionMember other) + { + // primitive-definition members carry a null typeName; identity lives in primitiveDefinition(). + return other instanceof PersistenceTypeDescriptionMemberPrimitiveDefinition + && Objects.equals( + this.primitiveDefinition(), + ((PersistenceTypeDescriptionMemberPrimitiveDefinition)other).primitiveDefinition() + ) + ; + } /** * Tests whether two primitive-definition entries record the same {@link #primitiveDefinition()}