Skip to content

[WP14] Leaf-spec constructor validation & one-shot Iterable consumption #196

Open

Description

@shihyuho

此內容由 AI 產生(specification-mapper 全庫審查 2026-07-16.執行圖)。

Work package WP14 · findings: COR-14, MAINT-06, MAINT-07, TEST-08 · worst severity: medium · effort: S

From the 2026-07-16 whole-codebase review of branch jakarta (snapshot 7de4a33; modules mapper/ + starter/). Every finding below is CONFIRMED by independent adversarial verification. File:line coordinates are from the snapshot and may have drifted.

Findings

COR-14 — Between and In consume the value Iterable multiple times, breaking one-shot Iterables (correctness, medium)

  • File: mapper/src/main/java/tw/com/softleader/data/jpa/spec/domain/Between.java:57 (and In.java)
  • Evidence: Between's constructor streams the Iterable to count elements, then toPredicate streams it again (and again on every execution); In.toPredicate re-streams per execution. A one-shot Iterable (stream-backed, cursor-backed) is exhausted after the first traversal — later traversals silently see nothing or throw.

MAINT-06 — Between never validates elements are Comparable (maintainability, low)

  • File: mapper/src/main/java/tw/com/softleader/data/jpa/spec/domain/Between.java:67
  • Evidence: elements are cast (Comparable<?>) at query time — a bad element surfaces as a raw ClassCastException far from the mapping site, unlike the fail-fast ComparableSpecification/BooleanSpecification siblings.

MAINT-07 — LIKE family accepts any Object and silently coerces via toString (maintainability, low)

  • File: mapper/src/main/java/tw/com/softleader/data/jpa/spec/domain/Like.java:52

TEST-08 — Between constructor-validation branches largely untested (testing, medium)

Plan

  1. In Between and In constructors, materialize the incoming Iterable once into an immutable List and have toPredicate use the materialized copy (fixes COR-14; single traversal ever).
  2. Between: validate at construction that there are exactly 2 elements (existing) and that both are non-null Comparable, throwing a descriptive TypeMismatchException-style error (MAINT-06).
  3. LIKE family: validate the value is a CharSequence at construction, throwing TypeMismatchException otherwise, consistent with the type-checked siblings (MAINT-07). Release-note the tightening (previously any Object was toString-coerced).
  4. Tests (TEST-08): a stream-backed one-shot Iterable through SpecMapper.toSpec executed twice; non-Comparable Between elements fail at toSpec; LIKE with a non-CharSequence fails at toSpec; remaining constructor branches of Between/In covered.

Acceptance criteria

  • A one-shot Iterable criteria maps and executes correctly across repeated query executions.
  • Invalid values fail at toSpec with descriptive exceptions instead of ClassCastException at query time.
  • New tests from step 4 pass; regression: make test green.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: ready-for-agentFully specified and ready for an autonomous AFK agent to implementtype: bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions