Equality Lab is a Java and Spring Boot engineering lab for one deceptively hard question: when should two objects be treated as the same Java value, and when are they only related inside the business domain?

The first scenario uses a financial party hierarchy with party, individual, employee, trader, manager, institution, and Hibernate proxy-like runtime types. The page is meant to answer the project in order: what the problem is, which domain objects create the ambiguity, how the web and Java pieces are built, and what each equality rule changes in collections and persistence.

End-to-end build scenario

User opens lab
React workbench
Next.js route
Spring Boot API
Matrices and guide

The full project is a website feature plus a Java backend service. A user opens the Equality Lab page, selects domain objects, chooses an equality strategy, and runs the evaluation. The React workbench shows the scenario and the result tables, the Next.js route keeps the demo stable with a local fallback, and the Spring Boot API owns the Java-oriented equality strategy execution when it is configured.

That means the project is not only a static article. It is an end-to-end slice: frontend explanation, API boundary, Java equality rules, collection consequences, deployable Spring Boot pod, and production delivery direction.

Problem

Java can tell whether two references are the same object, but the business has to decide whether two records mean the same party, employee, role, or persisted row.

Scenario

A financial party hierarchy with person, employee, trader, manager, institution, and Hibernate proxy-like objects exposes the equality traps.

Build Shape

The portfolio page owns the React workbench, the Next.js route owns fallback and adaptation, and the Spring Boot pod owns Java strategy execution.

Outcome

The result is a focused engineering lab that connects equality rules to collections, persistence, API boundaries, CI/CD, and Kubernetes deployment.


1. Problem: "same" is not one thing

Java gives every object identity by default. That default is safe for memory identity, but business systems usually need stronger meaning: same customer, same employee record, same legal party, same persisted row, same role, or only related records. If all of those questions are forced into oneequals method, the model becomes fragile.

Equality Lab makes the hidden decision visible. A user selects an anchor object, chooses target objects, switches equality strategies, and sees what Java would do across ==, equals, hashCode,HashMap, HashSet, and Stream.distinct().

2. Domain scenario: financial party hierarchy

Party
IndividualParty
EmployeeParty
TraderPartyManagerPartyEmployeePartyHibernateProxy
InstitutionParty

Uses legal entity keys such as tenant, country, registration number, or normalized SWIFT/BIC.

This hierarchy is useful because it exposes the real traps. A trader can be an employee. A manager can also be an employee. Two role objects can share an employee number but still represent different role records. A Hibernate proxy can represent the same row while having a different runtime class. An institution can use normalized business keys instead of generated ids.

3. Runtime boundary details

The frontend belongs in this website because it is part of the portfolio experience. The equality engine belongs in Java because the topic is Java behavior, Spring Boot production design, and JPA lifecycle safety. The final production shape is therefore a web feature plus a separate Java API pod.

The Next.js API route is intentionally more than a proxy. It keeps the demo stable with a local fallback, and when the Spring Boot service is configured it adapts the workbench payload into the backend pair-evaluation contract.

4. What the lab computes

  • Whether the selected objects are the same Java reference.
  • Whether anchor.equals(target) and target.equals(anchor) agree.
  • Whether equal objects land in the same hashCode bucket.
  • Whether HashSet, HashMap, and Stream.distinct() behave safely.
  • Whether the selected rule creates JPA id, Hibernate proxy, mutation, or inheritance risks.

5. Strategy matrix

StrategyWhen A equals BProduction risk
Java defaultOnly the same memory referenceTwo objects with the same business meaning still look different.
Business keySame tenant plus normalized party numberChanging the key after putting the object in a HashMap breaks lookup.
Role-strictSame tenant, employee number, and concrete rolePrevents Trader and Manager from collapsing into one broad employee value.
JPA idSame persisted database idNull ids on new entities must never make two transient objects equal.
Proxy-safe JPASame persistent class and id after Hibernate proxy unwrappingAvoids getClass-based false negatives when Hibernate creates proxy classes.

6. Collection behavior

Equality Lab does not stop at equals. It shows what the decision does inside everyday Java structures, because most real bugs appear when an object becomes a key, set element, cache entry, stream value, or retry marker.

StructureVisible behaviorWhy it matters
ListKeeps both objectsList does not remove duplicates unless you ask it to.
HashSetKeeps one or twoDepends on equals and hashCode together.
HashMap keyFinds or misses valueLookup needs the same hash bucket and equals match.
Stream.distinct()Merges or keeps bothUses equals through an internal distinct set.

7. Spring Boot API shape

  • GET /api/equality-lab/strategies lists strategy options.
  • GET /api/equality-lab/presets lists domain scenarios.
  • POST /api/equality-lab/evaluate returns equality, hash, collection, contract, and domain-relation results.
  • GET /actuator/health/liveness andGET /actuator/health/readiness support Kubernetes probes.
  • GET /actuator/prometheus exposes request and strategy metrics.

8. Failure modes the project exposes

  • Parent-child inheritance equality that breaks symmetry
  • Too-broad employee equality that merges different role records
  • hashCode mismatch after equals returns true
  • OR-based identity rules that break transitivity
  • Hibernate proxy equality where getClass and proxy classes disagree
  • Transient JPA entities with null ids accidentally comparing equal
  • Mutable fields used inside hashCode while objects live in HashSet or HashMap
  • Unnormalized business keys such as SWIFT code, tenant id, email, or customer number

9. Delivery plan

The deployment should match the existing Strato pattern: app repo produces an immutable image and supply-chain evidence, deploy repo owns Kustomize desired state, and Argo CD rolls the service into K3s.

  • Build and test the Spring Boot API in GitLab CI.
  • Build the container image with an immutable digest.
  • Generate SBOM with Syft and scan with Trivy.
  • Apply a release policy instead of blindly promoting every image.
  • Sign the image digest with Cosign.
  • Open a deploy repo merge request that updates the Kubernetes manifest.
  • Let Argo CD reconcile the merged desired state into K3s.

10. Kubernetes shape

  • Deployment runs equality-lab-api as a non-root Spring Boot container.
  • Service exposes the pod inside the cluster.
  • ServiceMonitor scrapes actuator metrics.
  • HPA scales under CPU and memory pressure.
  • NetworkPolicy limits which pods can call the API.
  • ArgoCD Application connects the deploy repo path to the cluster.

11. Engineering takeaways

Equality Lab is small enough to understand, but deep enough to show senior engineering judgment. It connects a core Java language feature to domain design, inheritance, JPA, collections, API contracts, CI/CD, supply-chain checks, Kubernetes deployment, and observability.