refactor(specifications): replace dynamic array creation with static empty arrays for improved performance#883
Conversation
…empty arrays for improved performance
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (4)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
📝 WalkthroughWalkthroughReplaces calls that convert collections to arrays from the explicit empty-array form ( Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (2 errors, 1 warning)
✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
backend/src/main/java/org/booklore/app/service/AppBookService.java (1)
58-58: LGTM — behavior-preserving constant extraction.The raw
Specification[]declaration mirrors the pre-existingnew Specification[0]pattern, so no new unchecked-warning surface is introduced. As a purely stylistic optional nit, you could declare it asSpecification<?>[]to be slightly more precise, but it doesn't change the generated code or the call sites.Also applies to: 1055-1055, 1122-1122
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/main/java/org/booklore/app/service/AppBookService.java` at line 58, Replace the raw Specification[] type of the constant EMPTY_SPECIFICATION_ARRAY with the more precise generic form Specification<?>[] (update the declaration of EMPTY_SPECIFICATION_ARRAY in AppBookService and the same occurrences at the other two locations referenced) so the constant expresses its wildcard element type without changing runtime behavior.backend/src/main/java/org/booklore/config/security/SecurityConfig.java (1)
50-50: LGTM — safe and targeted.No change to authorization semantics; only the empty-array allocation site is swapped. Out of scope for this PR, but since
unauthenticatedEndpointsis built fromCOMMON_UNAUTHENTICATED_ENDPOINTSand never mutated inopdsBasicAuthSecurityChain, a future cleanup could passCOMMON_UNAUTHENTICATED_ENDPOINTSdirectly torequestMatchers(...)and drop theArrayList/toArrayround-trip entirely.Also applies to: 89-89
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/main/java/org/booklore/config/security/SecurityConfig.java` at line 50, Replace the dynamic construction of unauthenticatedEndpoints and the toArray call with a direct use of the static array: where opdsBasicAuthSecurityChain builds an ArrayList from COMMON_UNAUTHENTICATED_ENDPOINTS and calls requestMatchers(unauthenticatedEndpoints.toArray(EMPTY_STRING_ARRAY)), change it to call requestMatchers(COMMON_UNAUTHENTICATED_ENDPOINTS) directly and remove the temporary ArrayList and EMPTY_STRING_ARRAY constant since COMMON_UNAUTHENTICATED_ENDPOINTS is never mutated.backend/src/main/java/org/booklore/app/service/AppSeriesService.java (1)
36-36: LGTM — consistent with the AppBookService change.Same pattern as
AppBookService.EMPTY_SPECIFICATION_ARRAY; behavior is preserved. Since this constant is duplicated acrossAppBookServiceandAppSeriesService(and aPredicate[]variant exists inAppBookSpecificationandBookRuleEvaluatorService), an optional follow-up would be to centralize them in a smallEmptyArraysutility class to enforce single-source-of-truth — but that's purely cosmetic.Also applies to: 377-377
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/src/main/java/org/booklore/app/service/AppSeriesService.java` at line 36, Duplicate empty-array constants exist (AppSeriesService.EMPTY_SPECIFICATION_ARRAY and AppBookService.EMPTY_SPECIFICATION_ARRAY, plus Predicate[] variants in AppBookSpecification and BookRuleEvaluatorService); to centralize, create a small utility class (e.g., EmptyArrays) exposing typed constants (Specification<?>[] EMPTY_SPECIFICATION_ARRAY, Predicate<?>[] EMPTY_PREDICATE_ARRAY), replace usages in AppSeriesService, AppBookService, AppBookSpecification and BookRuleEvaluatorService to reference EmptyArrays, and remove the now-redundant local constants so all code uses the single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@backend/src/main/java/org/booklore/app/service/AppBookService.java`:
- Line 58: Replace the raw Specification[] type of the constant
EMPTY_SPECIFICATION_ARRAY with the more precise generic form Specification<?>[]
(update the declaration of EMPTY_SPECIFICATION_ARRAY in AppBookService and the
same occurrences at the other two locations referenced) so the constant
expresses its wildcard element type without changing runtime behavior.
In `@backend/src/main/java/org/booklore/app/service/AppSeriesService.java`:
- Line 36: Duplicate empty-array constants exist
(AppSeriesService.EMPTY_SPECIFICATION_ARRAY and
AppBookService.EMPTY_SPECIFICATION_ARRAY, plus Predicate[] variants in
AppBookSpecification and BookRuleEvaluatorService); to centralize, create a
small utility class (e.g., EmptyArrays) exposing typed constants
(Specification<?>[] EMPTY_SPECIFICATION_ARRAY, Predicate<?>[]
EMPTY_PREDICATE_ARRAY), replace usages in AppSeriesService, AppBookService,
AppBookSpecification and BookRuleEvaluatorService to reference EmptyArrays, and
remove the now-redundant local constants so all code uses the single source of
truth.
In `@backend/src/main/java/org/booklore/config/security/SecurityConfig.java`:
- Line 50: Replace the dynamic construction of unauthenticatedEndpoints and the
toArray call with a direct use of the static array: where
opdsBasicAuthSecurityChain builds an ArrayList from
COMMON_UNAUTHENTICATED_ENDPOINTS and calls
requestMatchers(unauthenticatedEndpoints.toArray(EMPTY_STRING_ARRAY)), change it
to call requestMatchers(COMMON_UNAUTHENTICATED_ENDPOINTS) directly and remove
the temporary ArrayList and EMPTY_STRING_ARRAY constant since
COMMON_UNAUTHENTICATED_ENDPOINTS is never mutated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro
Run ID: 121744c7-eb81-4190-902e-ee31bc74b6fb
📒 Files selected for processing (5)
backend/src/main/java/org/booklore/app/service/AppBookService.javabackend/src/main/java/org/booklore/app/service/AppSeriesService.javabackend/src/main/java/org/booklore/app/specification/AppBookSpecification.javabackend/src/main/java/org/booklore/config/security/SecurityConfig.javabackend/src/main/java/org/booklore/service/BookRuleEvaluatorService.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Test Suite / Backend Tests
- GitHub Check: Test Suite / Frontend Tests
- GitHub Check: Analyze (java-kotlin)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Frontend Lint Threshold Check
🧰 Additional context used
📓 Path-based instructions (1)
backend/src/**/*.java
📄 CodeRabbit inference engine (AGENTS.md)
backend/src/**/*.java: Use 4-space indentation and match surrounding Java style in backend code
Prefer constructor injection via Lombok patterns already used in the codebase. Do not introduce@Autowiredfield injection in backend code
Use MapStruct for entity/DTO mapping in backend code
Keep JPA entities on the *Entity suffix in backend code
Files:
backend/src/main/java/org/booklore/app/service/AppSeriesService.javabackend/src/main/java/org/booklore/config/security/SecurityConfig.javabackend/src/main/java/org/booklore/service/BookRuleEvaluatorService.javabackend/src/main/java/org/booklore/app/specification/AppBookSpecification.javabackend/src/main/java/org/booklore/app/service/AppBookService.java
🧠 Learnings (4)
📚 Learning: 2026-04-04T14:03:28.295Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 372
File: frontend/src/app/features/book/service/app-books-api.service.ts:150-178
Timestamp: 2026-04-04T14:03:28.295Z
Learning: In `frontend/src/app/features/book/service/app-books-api.service.ts`, the `summaryToBook` function intentionally uses `as unknown as Book` to cast a partial object to the `Book` type. The returned object omits some required `Book` fields (e.g. `metadata.bookId`, `pdfProgress.page`) and includes an extra `bookFiles: []` property not in the `Book` interface. This is by design — consumers of `AppBooksApiService.books()` (e.g. `BookCardComponent`) only access the subset of properties that are populated from `AppBookSummary`, so no runtime issues occur. Do not flag this as a type safety error.
Applied to files:
backend/src/main/java/org/booklore/app/service/AppSeriesService.java
📚 Learning: 2026-04-04T15:36:56.558Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 372
File: booklore-api/src/main/java/org/booklore/app/service/AppBookService.java:357-359
Timestamp: 2026-04-04T15:36:56.558Z
Learning: In `booklore-api/src/main/java/org/booklore/app/service/AppBookService.java`, `shelfId` and `magicShelfId` are mutually exclusive navigation contexts in `getFilterOptions`. A request will never supply both at the same time, so the `else if (shelfId != null)` branch after the `magicBookIds != null` check is intentional and correct — there is no missing shelf-∩-magicShelf intersection case. Do not flag this pattern as a bug.
Applied to files:
backend/src/main/java/org/booklore/app/service/AppSeriesService.java
📚 Learning: 2026-04-10T08:15:37.436Z
Learnt from: imnotjames
Repo: grimmory-tools/grimmory PR: 449
File: booklore-api/src/main/java/org/booklore/service/book/BookDownloadService.java:139-145
Timestamp: 2026-04-10T08:15:37.436Z
Learning: When using Spring `ContentDisposition.builder(...).filename(name, StandardCharsets.UTF_8).build()` (i.e., explicitly providing UTF-8), the resulting header value should include both the quoted `filename="=?UTF-8?..."` and the RFC 5987 `filename*=` parameters. In this case, any extra ASCII fallback computation (e.g., deriving an ASCII `fallbackFilename` via `NON_ASCII_PATTERN` and calling `.filename(fallbackFilename)`) is likely redundant—prefer calling only `.filename(fallbackName?, StandardCharsets.UTF_8)` as appropriate and let Spring handle the UTF-8 header parameters. Verify by comparing the emitted header for `filename` and `filename*` before deciding to keep an ASCII fallback.
Applied to files:
backend/src/main/java/org/booklore/app/service/AppSeriesService.javabackend/src/main/java/org/booklore/config/security/SecurityConfig.javabackend/src/main/java/org/booklore/service/BookRuleEvaluatorService.javabackend/src/main/java/org/booklore/app/specification/AppBookSpecification.javabackend/src/main/java/org/booklore/app/service/AppBookService.java
📚 Learning: 2026-04-14T12:43:08.698Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 502
File: booklore-api/src/main/java/org/booklore/service/reader/ChapterCacheService.java:0-0
Timestamp: 2026-04-14T12:43:08.698Z
Learning: For this codebase (booklore-api), target Java 25 with `--enable-preview`, so `_` is intentionally used as an unnamed/ignored variable (e.g., lambda parameter or pattern variable) per Java’s preview feature JEP 456. Do not flag `_` in those contexts as an invalid/reserved identifier; only flag it if it’s used in a non-supported position (e.g., where an unnamed variable is not applicable for the Java preview rules).
Applied to files:
backend/src/main/java/org/booklore/app/service/AppSeriesService.javabackend/src/main/java/org/booklore/config/security/SecurityConfig.javabackend/src/main/java/org/booklore/service/BookRuleEvaluatorService.javabackend/src/main/java/org/booklore/app/specification/AppBookSpecification.javabackend/src/main/java/org/booklore/app/service/AppBookService.java
🔇 Additional comments (2)
backend/src/main/java/org/booklore/service/BookRuleEvaluatorService.java (1)
35-35: LGTM — straightforward empty-array reuse.
Predicateis non-generic (jakarta.persistence.criteria.Predicate), so no raw-type warnings are introduced, and the swap is behavior-preserving. As a tiny optional nit, you could co-locateEMPTY_PREDICATE_ARRAYwith the other static field block (NUMERIC_FIELDSat line 957) for consistency, but it's not worth a separate change.Also applies to: 92-93, 874-874
backend/src/main/java/org/booklore/app/specification/AppBookSpecification.java (1)
21-21: LGTM — broad but mechanical replacement.All 10 call sites consistently substitute
new Predicate[0]for the sharedEMPTY_PREDICATE_ARRAY, including the varargswhere(...)site at line 880, which correctly accepts the materialized array. No semantic change, andPredicatebeing non-generic avoids any raw-type concerns.Also applies to: 279-279, 586-586, 618-618, 668-668, 733-733, 757-757, 828-828, 880-880, 885-886
…array creation method for improved clarity
…empty arrays for improved performance (grimmory-tools#883)
…empty arrays for improved performance (grimmory-tools#883)
Description
Linked Issue: Fixes #
Changes
This pull request introduces a codebase-wide refactor to optimize array allocations when converting collections to arrays, especially for frequently used types like
Specification,Predicate, andString. The main change is the introduction and use of static, pre-allocated empty arrays instead of creating new empty arrays each time, which improves performance and reduces unnecessary object creation. No logic or behavior is changed.The most important changes are:
Performance improvements (array allocation):
EMPTY_SPECIFICATION_ARRAY,EMPTY_PREDICATE_ARRAY,EMPTY_STRING_ARRAY) forSpecification,Predicate, andStringtypes in their respective classes to avoid repeated allocations of empty arrays.toArray(new Type[0])withtoArray(EMPTY_TYPE_ARRAY)in methods that build specifications or predicates, across service and specification classes.These changes are purely internal optimizations and do not affect application behavior or external interfaces.
Summary by CodeRabbit