Skip to content

Compare entity and property models by identity (plan item 2.7) - #4396

Merged
evanchooly merged 1 commit into
masterfrom
propertymodel-hash
Oct 15, 2026
Merged

evanchooly merged 1 commit into
masterfrom
propertymodel-hash

Conversation

@evanchooly

Copy link
Copy Markdown
Member

Plan item 2.7 (review D5).

The bug

PropertyModel.hashCode included codec, which is set lazily the first time the property is encoded or decoded. EntityModel.hashCode hashed its propertyModelsByName and propertyModelsByMappedName maps, which contain those property models. So both hashes changed after the first encode. Any model placed in a HashSet or HashMap key before then could no longer be found. The hierarchy's subtype sets are hash-based, too. The deep structural equals also cost a full comparison on every CopyOnWriteArraySet.add and wherever models were compared.

Change

The equals and hashCode overrides on EntityModel and PropertyModel are deleted, so both compare by identity. Each mapper holds exactly one model per type and one property model per property, and copied mappers build new instances. No caller compared two distinct instances structurally.

Audit

  • Main code: model comparisons, such as propertyModel.equals(idModel) in EntityEncoder, subtype sets, and IndexHelper's parentModels.contains, always compare instances from the same mapper.
  • Tests: none assert structural equality of models. TestMapper.testMapperCopying already asserts that copies are different instances, using assertNotSame.

Tests

CodecHarnessTest.modelHashesAreStableAcrossEncoding runs under both mappers. It puts HarnessScalars' entity model and its property models into HashSets, encodes and decodes a sample (which specializes every property's codec), and checks that the sets still contain them. It failed before the fix: "REFLECTION: the model's hash changed".

The core and Kotlin suites pass with -Dmorphia.mapper=critter and with reflection: 1482 + 5 tests, 0 failures.

Decisions to review

None beyond the plan. TypeData and WildCardTypeData keep their value-based equals/hashCode: they're immutable, and code compares them as values.

PropertyModel.hashCode included its lazily specialized codec, and
EntityModel.hashCode hashed its property models, so both hashes changed
the first time an entity was encoded, stranding them in hash-based
collections. Both overrides are removed, so the models compare by
identity, which is what every caller relies on.
Copilot AI balanced review requested due to automatic review settings October 15, 2026 03:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Identity semantics fit the reviewed callers, regression coverage addresses hash stability, and no blocking issues remain.

0 open findings

What changed in this PR

Fixes unstable model hashes by using identity equality for entity and property models in Morphia’s mapping layer.

Changes:

  • Removes structural equals and hashCode overrides from both model classes.
  • Adds hash-set stability coverage across encoding and decoding under both mappers.
  • Marks plan item 2.7 complete.
File Description
design/​mapping-game-plan.md Marks item 2.7 complete.
core/​src/​test/​java/​dev/​morphia/​test/​mapping/​codec/​harness/​CodecHarnessTest.java Tests model hash stability under both mappers.
core/​src/​main/​java/​dev/​morphia/​mapping/​codec/​pojo/​PropertyModel.java Switches property models to identity equality and hashing.
core/​src/​main/​java/​dev/​morphia/​mapping/​codec/​pojo/​EntityModel.java Switches entity models to identity equality and hashing.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@evanchooly
evanchooly merged commit d87e637 into master Oct 15, 2026
5 checks passed
@evanchooly
evanchooly deleted the propertymodel-hash branch October 15, 2026 03:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants