Skip to content

fix(qrest-crud): correct getId cast, cache Validator, bound list limit - #387

Merged
ar merged 1 commit into
jpos:mainfrom
jrfinc:fix/qrest-crud-correctness
Jul 14, 2026
Merged

fix(qrest-crud): correct getId cast, cache Validator, bound list limit#387
ar merged 1 commit into
jpos:mainfrom
jrfinc:fix/qrest-crud-correctness

Conversation

@jrfinc

@jrfinc jrfinc commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Three correctness/robustness fixes in the CRUD base participant (modules/qrest-crud).

1. getId() throws ClassCastException for Integer-typed entity ids

((long) id) on an Object holding an Integer compiles to a checkcast-to-Long plus unboxing, so it throws ClassCastException: Integer cannot be cast to Long at runtime. Reflection boxes even primitive int getters to Integer, so any entity whose id getter returns int/Integer (rather than long/Long) breaks on every POST/PUT/DELETE/GET-by-id, and the exception is swallowed into a generic abort. Fixed with ((Number) id).longValue() == 0L.

2. getAndValidateEntity() rebuilds the Bean Validation factory on every request

Validation.buildDefaultValidatorFactory() is expensive and the returned ValidatorFactory (an AutoCloseable) was never closed. Replaced with a cached static final Validator (the Validator is thread-safe).

3. List GET ?limit is unbounded and ?limit/?offset crash on non-numeric input

Integer.parseInt threw on non-numeric input, and there was no server-side ceiling on limit, so a client could request an arbitrarily large page. Added a configurable maxResults ceiling (default 1000, overridable per endpoint via <property name="maxResults" value="..."/>), clamped limit to [1, maxResults] and offset to >= 0, and made non-numeric input fall back to the existing defaults instead of throwing.

Default behavior is unchanged for callers requesting a sane page size; only requests above the ceiling are clamped.

Verification

./gradlew :modules:qrest-crud:compileJava succeeds. The module has no existing test source set, so no unit tests were added.

- getId(): use Number.longValue() instead of (long) cast, which threw
  ClassCastException for Integer-typed entity ids
- getAndValidateEntity(): reuse a cached Validator instead of building a
  ValidatorFactory on every request (and leaking it)
- prepareForGet(): clamp ?limit to a configurable maxResults ceiling
  (default 1000) and fall back to defaults on non-numeric limit/offset
@jrfinc
jrfinc requested a review from ar July 6, 2026 23:30
@ar
ar merged commit 94998e9 into jpos:main Jul 14, 2026
1 check passed
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