Skip to content

chore: fix compilation warnings from the Spring Boot 4 upgrade - #3854

Open
bdshadow wants to merge 15 commits into
mainfrom
bdshadow/spring-boot-4-warnings
Open

chore: fix compilation warnings from the Spring Boot 4 upgrade#3854
bdshadow wants to merge 15 commits into
mainfrom
bdshadow/spring-boot-4-warnings

Conversation

@bdshadow

@bdshadow bdshadow commented Aug 12, 2026

Copy link
Copy Markdown
Member

Cleans up the Kotlin compilation warnings left behind by the Spring Boot 4 / Kotlin 2.3 / Java 25 / Hibernate 7 / Jackson 3 upgrade.

388 of 433 warnings are gone across :data, :api, :ee-app, :development, :server-app and :billing-app — main and test sources. The remaining 45 are all uses of our own deliberately deprecated APIs (Project.userOwner, MtCreditBucket.extraCredits, screenshotUploadedImageIds, createUsersAndOrganizations); suppressing those was deliberately left out of this PR.

One commit per fix, so it can be reviewed group by group:

Commit What
drop lateinit Kotlin 2.2 tracks definite assignment through init blocks
drop @Temporal Deprecated in Jakarta Persistence 3.2; every usage was TIMESTAMP on a java.util.Date, which is the default, so column mapping is unchanged
Jackson 3 string accessors asText()/isTextualasString()/isString
Hibernate Timeouts LockOptions.SKIP_LOCKED/NO_WAIT moved to org.hibernate.Timeouts.*_MILLI
CriteriaQuery.multiselectselect cb.construct for projected views, cb.tuple for tuple queries, cb.array for Object[]; the unnamed JpaCteContainer.with is deprecated too, so the CTE gets an explicit name
native text[] mapping Hypersistence deprecated StringArrayType/ListArrayType — Hibernate has supported ARRAY attributes since 6
Hibernate 7 interceptor names onSave/onDeleteonPersist/onRemove
deprecated Spring APIs XML converter → JacksonXmlHttpMessageConverter, CachingConfigurerSupportCachingConfigurer, Spring Batch 6 chunk(size).transactionManager(...)
remaining third-party APIs AWS DefaultCredentialsProvider, Redisson KeysScanOptions, commons-lang3 RandomStringUtils.secure(), Sentry User.name, Spring Data getReferenceById, AssertJ isCloseTo, java.util.Date.UTC, ktlint children20
Kotlin boxed type literals java.lang.Long/Boolean::class.java::class.javaObjectType
suppressions PROPERTY_HIDES_JAVA_FIELD on the pre-commit events, and unchecked casts over erased JPA results / cache entries / reflection / parsed test JSON
test fixes duplicate lambda labels, and " in test method names (invalid in Windows report filenames)
redundant null handling safe calls, !!, elvis fallbacks and casts the compiler now proves dead

Worth a closer look

Two warnings were hiding real problems rather than noise:

  • MimeMessageParser pinned JavaMail platform types to non-null, which silently disabled its own null checks even though getRecipients and getFrom do return null. The locals are now nullable, so the checks work again.
  • ValidationError cast a vararg Array<out String> to Array<String>; the property is now Array<out String>.

Two intentional behaviour deltas:

  • ExceptionHandlerslistOf(parameterName) as List<Serializable>?listOfNotNull(...), so a null parameter name yields [] instead of [null].
  • Dead fallbacks removed where the receiver was provably non-null (MtProviderCatching's ?: 100, the two ToIcuPlaceholderConvertor escape paths) — unreachable before and after.

The WebMvcConfigurer message-converter callbacks deliberately stay on the deprecated List overload and are suppressed instead: the replacement ServerBuilder API bypasses Spring HATEOAS's HAL converter registration.

Testing

  • All 16 Kotlin compile tasks build with no errors.
  • :data 481 tests and :server-app 300 tests pass, covering the behaviour-sensitive changes: MFA recovery codes and QuickStart (the text[] mapping), export and project stats and big meta (the multiselect rewrites), activity (interceptor rename), import, translations view/cursor, format convertors, cache purging and xlsx.
  • Individual commits were not compiled in isolation, only the final state.

Summary by CodeRabbit

  • Bug Fixes

    • Improved JSON value handling across email validation, translation workflows, imports, exports, and integrations.
    • Improved XML message conversion and compatibility with current framework behavior.
    • Improved batch-job locking and retry handling for more reliable processing.
    • Corrected translation placeholder and message-format output in edge cases.
    • Improved handling of missing email recipients and validation parameters.
  • Security

    • Invitation codes now use stronger secure random generation.
  • Refactor

    • Updated persistence, cloud-provider, and framework integrations for improved compatibility and maintainability.

Kotlin 2.2 tracks definite assignment through init blocks, so properties assigned
there no longer need lateinit.
Jakarta Persistence 3.2 deprecates @TeMPOraL. Every usage here was
TemporalType.TIMESTAMP on a java.util.Date, which is the default mapping, so
removing the annotation keeps the column mapping unchanged.
Spring Boot 4 brings Jackson 3, where JsonNode.asText()/isTextual are deprecated
in favour of asString()/isString.
Hibernate 7 moved the SKIP_LOCKED / NO_WAIT magic values to org.hibernate.Timeouts.
The lock hint takes an int, so the *_MILLI constants are the direct equivalents.
Jakarta Persistence 3.2 deprecates multiselect in favour of an explicit compound
selection: cb.construct for projected views, cb.tuple for tuple queries and
cb.array for Object[] queries. Hibernate's unnamed JpaCteContainer.with is
deprecated too, so the CTE now gets an explicit name.
Hypersistence deprecated StringArrayType and ListArrayType because Hibernate has
supported ARRAY attributes natively since 6.
Interceptor.onSave/onDelete are deprecated in favour of onPersist/onRemove.
Spring 7 deprecates MappingJackson2XmlHttpMessageConverter (superseded by the
Jackson 3 JacksonXmlHttpMessageConverter), CachingConfigurerSupport (the
CachingConfigurer interface now has defaults), HttpClientErrorException.
UnprocessableEntity (422 was renamed to Unprocessable Content) and, in Spring
Batch 6, StepBuilder.chunk(size, transactionManager).

The WebMvcConfigurer message-converter callbacks stay on the deprecated List
overload: the replacement ServerBuilder API bypasses Spring HATEOAS's HAL
converter registration.
AWS DefaultCredentialsProvider.create, Redisson getKeysByPattern, commons-lang3
RandomStringUtils.randomAlphanumeric, Sentry User.name, Spring Data getOne/getById,
AssertJ isEqualToIgnoringMillis, java.util.Date.UTC and ktlint ASTNode.children().
java.lang.Long/Boolean::class.java is flagged by Kotlin; ::class.javaObjectType
yields the same Class instance for the JPA result-type argument.
The typed source property intentionally shadows ApplicationEvent's source field,
which stays reachable through getSource().
Casts over erased JPA result lists, cache entries, reflection and parsed test
JSON cannot be checked at runtime.
Nested apply/build lambdas produced two labels of the same name, so this@apply
and this@build were ambiguous.
Gradle names report files after the test method, and quotes are not valid in
Windows filenames.
Kotlin 2.2 propagates nullability further, so a number of safe calls, !!
assertions, elvis fallbacks and casts are now provably dead. Two of these
hid real problems: MimeMessageParser pinned JavaMail platform types to
non-null, which silently disabled its null checks even though getRecipients
and getFrom do return null, and ValidationError cast a vararg Array<out
String> to Array<String>.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request modernizes Spring, Hibernate, Jackson, Kotlin, AWS, Redis, JPA, and Kotlin test code. It also updates query projections, entity mappings, test fixtures, and EE integrations.

Changes

Backend modernization

Layer / File(s) Summary
API and application compatibility updates
backend/api/..., backend/app/...
Spring configuration uses current interfaces and converter types. JSON accessors, nullable handling, repository calls, and test assertions use updated Kotlin and Jackson APIs.
Data infrastructure and batch processing
backend/data/src/main/kotlin/io/tolgee/batch/..., backend/data/src/main/kotlin/io/tolgee/component/...
Batch locking uses Hibernate timeout constants. Redis key scanning and AWS credential construction use current APIs. Interceptor callbacks and related utility code are updated.
Test-data and fixture initialization
backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/...
Test-data properties remove lateinit where setup assigns values. Nested builder blocks use explicit receiver labels.
Persistence contracts and format processing
backend/data/src/main/kotlin/io/tolgee/dtos/..., backend/data/src/main/kotlin/io/tolgee/model/..., backend/data/src/main/kotlin/io/tolgee/formats/...
DTO variance, entity mappings, JSON string extraction, placeholder conversion, and Spring Batch configuration use updated declarations and APIs.
Query services, utilities, and EE integrations
backend/data/src/main/kotlin/io/tolgee/service/..., backend/testing/..., backend/ktlint/..., ee/backend/...
Criteria projections, CTE construction, nullability, compiler suppressions, lint traversal, fixtures, and EE JSON and query handling are updated.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: cleaning up compilation warnings from the Spring Boot 4 upgrade.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bdshadow/spring-boot-4-warnings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@bdshadow
bdshadow requested review from Anty0 and JanCizmar August 12, 2026 12:34
@bdshadow
bdshadow marked this pull request as ready for review August 12, 2026 12:34
@bdshadow
bdshadow requested a review from dkrizan August 12, 2026 12:34

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🧹 Nitpick comments (3)
backend/app/src/main/kotlin/io/tolgee/configuration/RestTemplateConfiguration.kt (1)

32-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move removeXmlConverter below both callers.

webhookRestTemplate at Line 38 calls removeXmlConverter, but the helper is declared at Line 31. Move the helper below both bean methods so each caller appears before the function it calls.

Proposed reorder
-  private fun RestTemplate.removeXmlConverter(): RestTemplate {
-    messageConverters.removeIf { it is JacksonXmlHttpMessageConverter }
-    return this
-  }
-
   `@Bean`(name = ["webhookRestTemplate"])
   fun webhookRestTemplate(): RestTemplate {
     return RestTemplate(getClientHttpRequestFactory()).removeXmlConverter()
   }
+
+  private fun RestTemplate.removeXmlConverter(): RestTemplate {
+    messageConverters.removeIf { it is JacksonXmlHttpMessageConverter }
+    return this
+  }

As per path instructions: “Functions should be ordered so that a caller appears before the functions it calls.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/app/src/main/kotlin/io/tolgee/configuration/RestTemplateConfiguration.kt`
at line 32, Move the removeXmlConverter helper below both bean methods that call
it, including webhookRestTemplate, while leaving its implementation unchanged.
Preserve the caller-before-callee ordering throughout the configuration.

Source: Path instructions

backend/data/src/main/kotlin/io/tolgee/batch/state/RedisBatchJobStateStorage.kt (1)

212-213: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move getCachedJobIds below clearUnusedStates.

clearUnusedStates at Line 220 calls getCachedJobIds at Line 212. This violates the Stepdown Rule. Move getCachedJobIds below clearUnusedStates so the caller appears before the callee.

As per path instructions, “Functions should be ordered so that a caller appears before the functions it calls.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/data/src/main/kotlin/io/tolgee/batch/state/RedisBatchJobStateStorage.kt`
around lines 212 - 213, Reorder the methods in RedisBatchJobStateStorage so
clearUnusedStates appears before getCachedJobIds, keeping both implementations
unchanged and ensuring the caller precedes the callee.

Source: Path instructions

ee/backend/tests/src/test/kotlin/io/tolgee/ee/WebhookAutomationTest.kt (1)

133-170: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reorder helpers to satisfy the Stepdown Rule.

verifyWebhookExecuted calls getWebhookRestTemplateInvocationCount and verifyWebhookSignature, which are declared before it. Tests at Lines 174-212 and Lines 214-231 call verifyWebhookExecuted after its declaration. Move the private helpers below all test methods so every caller appears before the functions it calls.

As per path instructions: “Functions should be ordered so that a caller appears before the functions it calls.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ee/backend/tests/src/test/kotlin/io/tolgee/ee/WebhookAutomationTest.kt`
around lines 133 - 170, Reorder the private helper methods in
WebhookAutomationTest so all test methods calling verifyWebhookExecuted appear
before it, and verifyWebhookExecuted appears before the lower-level helpers
getWebhookRestTemplateInvocationCount and verifyWebhookSignature. Preserve each
helper’s implementation and ensure every caller precedes the functions it
invokes.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/data/src/main/kotlin/io/tolgee/batch/BatchJobService.kt`:
- Around line 354-357: Update getAllUnlockedChunksForJobs to avoid relying on a
lock hint with its DTO constructor projection; use an entity-returning or native
query that applies FOR UPDATE SKIP LOCKED, then map the selected rows to
JobUnlockedChunk. Ensure getInitialJobId cannot treat database-locked chunks as
unlocked, and add a concurrency test covering two jobs contending for the same
project.

In `@backend/data/src/main/kotlin/io/tolgee/formats/MessagePatternUtil.kt`:
- Line 426: Update the rendering logic around simpleStyle so the comma is
appended only when style is non-null, preserving `{0,number}` for arguments
without a style while retaining styled output.

In
`@ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketHandler.kt`:
- Line 130: Update the text extraction in the QA preview update handler around
the text JSON field: validate that text is scalar before converting it, and
return a QaCheckPreviewError for object or array values instead of calling
asString() on them. Preserve the existing empty/default behavior and add
coverage for both object and array text updates alongside the existing scalar
tests.

In
`@ee/backend/app/src/main/kotlin/io/tolgee/ee/service/prompt/PromptResultParser.kt`:
- Around line 17-18: Update PromptResultParser.parse() to validate output and
contextDescription are scalar JSON values before calling asString(), mapping
object and array values to the existing provider-response error instead of
allowing JsonNodeException to escape. Preserve the current missing-output
behavior, and add parser tests covering object and array values for both fields.

---

Nitpick comments:
In
`@backend/app/src/main/kotlin/io/tolgee/configuration/RestTemplateConfiguration.kt`:
- Line 32: Move the removeXmlConverter helper below both bean methods that call
it, including webhookRestTemplate, while leaving its implementation unchanged.
Preserve the caller-before-callee ordering throughout the configuration.

In
`@backend/data/src/main/kotlin/io/tolgee/batch/state/RedisBatchJobStateStorage.kt`:
- Around line 212-213: Reorder the methods in RedisBatchJobStateStorage so
clearUnusedStates appears before getCachedJobIds, keeping both implementations
unchanged and ensuring the caller precedes the callee.

In `@ee/backend/tests/src/test/kotlin/io/tolgee/ee/WebhookAutomationTest.kt`:
- Around line 133-170: Reorder the private helper methods in
WebhookAutomationTest so all test methods calling verifyWebhookExecuted appear
before it, and verifyWebhookExecuted appears before the lower-level helpers
getWebhookRestTemplateInvocationCount and verifyWebhookSignature. Preserve each
helper’s implementation and ensure every caller precedes the functions it
invokes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: eb8dfeed-5cb3-48c2-9bdc-633bfe7c9073

📥 Commits

Reviewing files that changed from the base of the PR and between dd7f597 and 0060d4f.

📒 Files selected for processing (147)
  • backend/api/src/main/kotlin/io/tolgee/configuration/CacheConfiguration.kt
  • backend/api/src/main/kotlin/io/tolgee/configuration/OctetStreamSupportConfiguration.kt
  • backend/api/src/main/kotlin/io/tolgee/controllers/PublicController.kt
  • backend/api/src/main/kotlin/io/tolgee/hateoas/invitation/OrganizationInvitationModelAssembler.kt
  • backend/api/src/main/kotlin/io/tolgee/hateoas/organization/SimpleOrganizationModelAssembler.kt
  • backend/api/src/main/kotlin/io/tolgee/hateoas/translations/suggestions/TranslationSuggestionModelAssembler.kt
  • backend/app/src/main/kotlin/io/tolgee/ExceptionHandlers.kt
  • backend/app/src/main/kotlin/io/tolgee/component/TolgeeSentryUserProvider.kt
  • backend/app/src/main/kotlin/io/tolgee/configuration/EventStreamConfig.kt
  • backend/app/src/main/kotlin/io/tolgee/configuration/RestTemplateConfiguration.kt
  • backend/app/src/main/kotlin/io/tolgee/configuration/WebMvcConfiguration.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/NullTypedActivityRevisionStorageTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/administration/ProjectExportImportControllerTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationFloorAccessTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translationSuggestionController/TranslationSuggestionControllerMtTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerHistoryTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImportController/V2ImportControllerAddFilesTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2KeyController/KeySoftDeleteNamespaceTest.kt
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerTest.kt
  • backend/app/src/test/kotlin/io/tolgee/batch/AbstractBatchJobsGeneralTest.kt
  • backend/app/src/test/kotlin/io/tolgee/controllers/ExportControllerTest.kt
  • backend/app/src/test/kotlin/io/tolgee/jobs/migration/allOrganizationOwner/AllOrganizationOwnerJobTest.kt
  • backend/app/src/test/kotlin/io/tolgee/mcp/tools/McpBatchToolsTest.kt
  • backend/app/src/test/kotlin/io/tolgee/mcp/tools/McpKeyToolsTest.kt
  • backend/app/src/test/kotlin/io/tolgee/mcp/tools/McpLanguageToolsTest.kt
  • backend/app/src/test/kotlin/io/tolgee/mcp/tools/McpProjectToolsTest.kt
  • backend/app/src/test/kotlin/io/tolgee/mcp/tools/McpTagToolsTest.kt
  • backend/app/src/test/kotlin/io/tolgee/mcp/tools/McpTranslationToolsTest.kt
  • backend/app/src/test/kotlin/io/tolgee/repository/ProjectRepositoryTest.kt
  • backend/app/src/test/kotlin/io/tolgee/repository/dataImport/ImportFileRepositoryTest.kt
  • backend/app/src/test/kotlin/io/tolgee/repository/dataImport/ImportRepositoryTest.kt
  • backend/app/src/test/kotlin/io/tolgee/service/ActivityVIewByRevisionsProviderTest.kt
  • backend/app/src/test/kotlin/io/tolgee/service/KeyTrashPurgeSchedulerTest.kt
  • backend/app/src/test/kotlin/io/tolgee/websocket/WebsocketTestHelper.kt
  • backend/data/src/main/kotlin/io/tolgee/MtServicesConfiguration.kt
  • backend/data/src/main/kotlin/io/tolgee/activity/iterceptor/ActivityDatabaseInterceptor.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/BatchJobActionService.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/BatchJobCancellationManager.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/BatchJobService.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/ChunkProcessingUtil.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/MtProviderCatching.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/cleaning/ScheduledJobCleaner.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/processors/TagKeysChunkProcessor.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/processors/UntagKeysChunkProcessor.kt
  • backend/data/src/main/kotlin/io/tolgee/batch/state/RedisBatchJobStateStorage.kt
  • backend/data/src/main/kotlin/io/tolgee/component/fileStorage/S3ClientProvider.kt
  • backend/data/src/main/kotlin/io/tolgee/component/machineTranslation/providers/AzureCognitiveApiService.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/builders/InvitationBuilder.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/BatchJobsTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/BigMetaTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/CommunityContributionE2eData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ConcurrentBatchJobsTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ContributorsTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/GlossaryGuestAccessTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/KeyTrashTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/KeysTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/OrganizationStatsTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectExportImportTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectImportBranchedSourceTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectImportTargetTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectLeavingTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/QaE2eTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ResolvableImportTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ScopedSearchTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SlackTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SoftDeleteBranchingTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SoftDeleteKeysTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TaskTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TmSuggestionsE2eTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TranslationMemoryTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TranslationSourceChangeStateTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TranslationsSnapshotTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/dataImport/SingleStepImportBranchTestData.kt
  • backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/OrganizationView.kt
  • backend/data/src/main/kotlin/io/tolgee/dtos/request/validators/ValidationError.kt
  • backend/data/src/main/kotlin/io/tolgee/events/OnEntityCollectionPreUpdate.kt
  • backend/data/src/main/kotlin/io/tolgee/events/OnEntityPreDelete.kt
  • backend/data/src/main/kotlin/io/tolgee/events/OnEntityPrePersist.kt
  • backend/data/src/main/kotlin/io/tolgee/events/OnEntityPreUpdate.kt
  • backend/data/src/main/kotlin/io/tolgee/formats/MessagePatternUtil.kt
  • backend/data/src/main/kotlin/io/tolgee/formats/apple/in/xcstrings/XcstringsFileProcessor.kt
  • backend/data/src/main/kotlin/io/tolgee/formats/nestedStructureModel/StructureModelBuilder.kt
  • backend/data/src/main/kotlin/io/tolgee/formats/paramConvertors/in/BaseToIcuPlaceholderConvertor.kt
  • backend/data/src/main/kotlin/io/tolgee/formats/paramConvertors/in/I18nextToIcuPlaceholderConvertor.kt
  • backend/data/src/main/kotlin/io/tolgee/formats/paramConvertors/out/BaseToCLikePlaceholderConvertor.kt
  • backend/data/src/main/kotlin/io/tolgee/formats/paramConvertors/out/IcuToPythonBracePlaceholderConvertor.kt
  • backend/data/src/main/kotlin/io/tolgee/jobs/migration/allOrganizationOwner/AllOrganizationOwnerJobConfiguration.kt
  • backend/data/src/main/kotlin/io/tolgee/jobs/migration/translationStats/TranslationStatsJobConfiguration.kt
  • backend/data/src/main/kotlin/io/tolgee/model/ApiKey.kt
  • backend/data/src/main/kotlin/io/tolgee/model/AuditModel.kt
  • backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt
  • backend/data/src/main/kotlin/io/tolgee/model/LanguageStats.kt
  • backend/data/src/main/kotlin/io/tolgee/model/Pat.kt
  • backend/data/src/main/kotlin/io/tolgee/model/QuickStart.kt
  • backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt
  • backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt
  • backend/data/src/main/kotlin/io/tolgee/service/bigMeta/BigMetaService.kt
  • backend/data/src/main/kotlin/io/tolgee/service/export/dataProvider/ExportDataProvider.kt
  • backend/data/src/main/kotlin/io/tolgee/service/invitation/InvitationService.kt
  • backend/data/src/main/kotlin/io/tolgee/service/key/KeyMetaService.kt
  • backend/data/src/main/kotlin/io/tolgee/service/key/ResolvingKeyImporter.kt
  • backend/data/src/main/kotlin/io/tolgee/service/key/utils/KeyInfoProvider.kt
  • backend/data/src/main/kotlin/io/tolgee/service/language/LanguageService.kt
  • backend/data/src/main/kotlin/io/tolgee/service/project/ProjectStatsService.kt
  • backend/data/src/main/kotlin/io/tolgee/service/queryBuilders/LanguageStatsProvider.kt
  • backend/data/src/main/kotlin/io/tolgee/service/queryBuilders/ProjectStatsProvider.kt
  • backend/data/src/main/kotlin/io/tolgee/service/queryBuilders/translationViewBuilder/CursorPredicateProvider.kt
  • backend/data/src/main/kotlin/io/tolgee/service/queryBuilders/translationViewBuilder/QueryGlobalFiltering.kt
  • backend/data/src/main/kotlin/io/tolgee/service/queryBuilders/translationViewBuilder/StateFilterBuilder.kt
  • backend/data/src/main/kotlin/io/tolgee/service/queryBuilders/translationViewBuilder/TranslationsViewQueryBuilder.kt
  • backend/data/src/main/kotlin/io/tolgee/service/translation/AutoTranslationService.kt
  • backend/data/src/main/kotlin/io/tolgee/service/translation/TranslationService.kt
  • backend/data/src/main/kotlin/io/tolgee/util/entityPreCommitEventUsageUtil.kt
  • backend/data/src/main/kotlin/io/tolgee/util/transactionUtil.kt
  • backend/data/src/main/kotlin/io/tolgee/util/updateStringsInJson.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/cachePurging/AzureContentStorageConfigCachePurgingTest.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/cachePurging/BunnyContentStorageConfigCachePurgingTest.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/cachePurging/CloudflareContentStorageConfigCachePurgingTest.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/formats/properties/out/PropertiesFileExporterTest.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/formats/resx/out/ResxExporterTest.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/formats/xliff/out/XliffFileExporterTest.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/formats/yaml/out/YamlExportTestData.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/xlsx/out/XlsxFileExporterTest.kt
  • backend/development/src/main/kotlin/io/tolgee/facade/InternalPropertiesSetterFacade.kt
  • backend/ktlint/src/main/kotlin/io/tolgee/testing/ktlint/rules/JakartaTransientInEntities.kt
  • backend/testing/src/main/kotlin/io/tolgee/fixtures/MachineTranslationTest.kt
  • backend/testing/src/main/kotlin/io/tolgee/fixtures/MimeMessageParser.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketHandler.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/TaskModelAssembler.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/hateoas/assemblers/TaskWithProjectModelAssembler.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/component/llm/OpenaiApiService.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/component/llm/TolgeeApiService.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/development/QaLanguageStatsBranchTestData.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/security/thirdParty/SsoDelegateEe.kt
  • ee/backend/app/src/main/kotlin/io/tolgee/ee/service/prompt/PromptResultParser.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/WebhookAutomationTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/activity/ProjectActivityBranchingTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchControllerMergingTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerActivityTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/translationMemory/SharedTranslationMemoryControllerTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/data/qa/QaPreviewWsSessionStateTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/mcp/McpBranchToolsTest.kt
  • ee/backend/tests/src/test/kotlin/io/tolgee/ee/projectExportImport/ProjectExportImportImporterTest.kt
💤 Files with no reviewable changes (8)
  • backend/app/src/main/kotlin/io/tolgee/component/TolgeeSentryUserProvider.kt
  • backend/data/src/main/kotlin/io/tolgee/model/ForcedServerDateTime.kt
  • backend/data/src/main/kotlin/io/tolgee/model/QuickStart.kt
  • backend/data/src/main/kotlin/io/tolgee/model/LanguageStats.kt
  • backend/data/src/main/kotlin/io/tolgee/model/activity/ActivityRevision.kt
  • backend/data/src/main/kotlin/io/tolgee/model/ApiKey.kt
  • backend/data/src/main/kotlin/io/tolgee/model/Pat.kt
  • backend/data/src/main/kotlin/io/tolgee/model/AuditModel.kt

Comment on lines 354 to 357
.setHint(
"jakarta.persistence.lock.timeout",
LockOptions.SKIP_LOCKED,
Timeouts.SKIP_LOCKED_MILLI,
).resultList

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -u

rg -n -C 12 '\bgetAllUnlockedChunksForJobs\s*\(' backend --glob '*.kt' || true
rg -n -C 8 'SKIP_LOCKED_MILLI|PESSIMISTIC_WRITE|jakarta\.persistence\.lock\.timeout' \
  backend/data/src/main/kotlin/io/tolgee/batch --glob '*.kt' || true

Repository: tolgee/tolgee-platform

Length of output: 13302


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- BatchJobService imports and target method ---'
sed -n '1,70p' backend/data/src/main/kotlin/io/tolgee/batch/BatchJobService.kt
sed -n '320,365p' backend/data/src/main/kotlin/io/tolgee/batch/BatchJobService.kt

printf '%s\n' '--- Caller and surrounding workflow ---'
sed -n '130,215p' backend/data/src/main/kotlin/io/tolgee/batch/BatchJobProjectLockingManager.kt

printf '%s\n' '--- Chunk execution entity and status transitions ---'
rg -n -C 10 'class BatchJobChunkExecution|`@Version`|BatchJobChunkExecutionStatus|status\s*=' \
  backend --glob '*.kt' | head -n 260

printf '%s\n' '--- Existing query-lock tests and related method tests ---'
rg -n -C 8 'getAllUnlockedChunksForJobs|SKIP_LOCKED|PESSIMISTIC_WRITE|lock\.timeout|BatchJobProjectLockingManager' \
  backend --glob '*Test*.kt' --glob '*.kt' | head -n 320

printf '%s\n' '--- Hibernate/JPA versions ---'
rg -n 'hibernate|jakarta\.persistence|spring-boot' \
  build.gradle* settings.gradle* gradle.properties backend --glob '*.gradle*' --glob '*.kts' --glob '*.properties' | head -n 180

printf '%s\n' '--- Static verifier for the target query chain ---'
python3 - <<'PY'
from pathlib import Path
p = Path("backend/data/src/main/kotlin/io/tolgee/batch/BatchJobService.kt")
s = p.read_text()
start = s.index("fun getAllUnlockedChunksForJobs")
end = s.index("\n  }", start) + 4
method = s[start:end]
print("target_method_has_setLockMode=", ".setLockMode(" in method)
print("target_method_has_lock_timeout_hint=", '"jakarta.persistence.lock.timeout"' in method)
print("target_method_uses_constructor_projection=", "select new " in method)
print("target_method_result_type=", method.split("):", 1)[1].split("{", 1)[0].strip())
PY

Repository: tolgee/tolgee-platform

Length of output: 50378


🌐 Web query:

Hibernate ORM 7 user guide jakarta.persistence.lock.timeout -2 SKIP LOCKED pessimistic lock constructor expression DTO projection setLockMode

💡 Result:

In Hibernate ORM 7, the use of SKIP LOCKED with pessimistic locking is supported and can be managed through both Hibernate-specific mechanisms and standard Jakarta Persistence (JPA) configurations [1][2]. SKIP LOCKED Configuration To achieve a SKIP LOCKED behavior, you can use the Hibernate-specific LockMode.UPGRADE_SKIPLOCKED, which explicitly signals a SELECT... FOR UPDATE SKIP LOCKED statement [2][3]. Alternatively, you can use the combination of a pessimistic lock mode (such as PESSIMISTIC_WRITE) and a specific timeout value of -2, which corresponds to the magic value for SKIP_LOCKED [1][4][5]. In Hibernate 7, Timeouts.SKIP_LOCKED is the preferred mechanism for specifying this timeout value programmatically [4]. The property jakarta.persistence.lock.timeout can also be set to -2 in configuration or query hints to achieve this behavior [1][6][5]. DTO Projections and Locking When using constructor expressions (DTO projections), you are typically performing a read-only projection rather than fetching managed entities [7]. Because DTO projections are not managed entities, they do not participate in the Hibernate persistence context lifecycle [7]. Consequently, applying a lock mode (such as setLockMode) directly to a query returning a DTO projection is generally ineffective or unsupported because the underlying SQL projection (e.g., SELECT new com.example.MyDTO(...)) does not map to a database entity that can be locked via SELECT FOR UPDATE [7]. Pessimistic locking is designed for entities, and if you attempt to use it on a DTO projection, Hibernate cannot translate the lock request into the corresponding FOR UPDATE clause on the projected columns [8][7]. To lock records while retrieving data into a DTO: 1. First, select the entities or their primary keys using a query that applies the desired lock mode (e.g., PESSIMISTIC_WRITE with SKIP_LOCKED) [1][5]. 2. Then, perform the transformation to your DTO using the retrieved entities [7]. Summary of Key APIs in Hibernate 7 - LockMode.UPGRADE_SKIPLOCKED: Provides the explicit lock mode for SKIP LOCKED [2]. - Timeouts.SKIP_LOCKED: The helper constant for the SKIP LOCKED timeout [4]. - SelectionQuery.setLockMode(String alias, LockMode lockMode): Used for alias-specific locking in queries [9]. - SelectionQuery.setHibernateLockMode(LockMode lockMode): Preferred method for applying Hibernate-specific lock modes to a query [10][9]. Note: The legacy LockOptions class is considered obsolete in Hibernate 7 and is moving to an internal SPI package; modern applications should favor the methods on SelectionQuery [10][11].

Citations:


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- Exact dependency declarations ---'
rg -n -i --glob '*.gradle' --glob '*.gradle.kts' --glob '*.properties' \
  'hibernate-core|hibernateVersion|hibernate.version|spring-boot' \
  . | head -n 120

printf '%s\n' '--- Locking manager entry points and call sites ---'
rg -n -C 18 \
  'fun (getInitialJobId|tryLock|lock|computeFnBody)|getInitialJobId\(|getAllUnlockedChunksForJobs\(' \
  backend/data/src/main/kotlin/io/tolgee/batch/BatchJobProjectLockingManager.kt \
  backend --glob '*.kt' | head -n 360

printf '%s\n' '--- Chunk execution reads, claims, and status updates ---'
rg -n -C 12 \
  'BatchJobChunkExecution|ChunkExecution|status\s*=\s*BatchJobChunkExecutionStatus|PESSIMISTIC|SKIP_LOCKED|lock\.timeout' \
  backend/data/src/main/kotlin/io/tolgee/batch \
  backend/data/src/main/kotlin/io/tolgee/model/batch --glob '*.kt' | head -n 420

printf '%s\n' '--- Target method structural verifier ---'
python3 - <<'PY'
from pathlib import Path
p = Path("backend/data/src/main/kotlin/io/tolgee/batch/BatchJobService.kt")
s = p.read_text()
start = s.index("fun getAllUnlockedChunksForJobs")
body = s[start:s.index("\n  }", start) + 4]
checks = {
    "has_constructor_projection": "select new " in body,
    "has_lock_timeout_hint": '"jakarta.persistence.lock.timeout"' in body,
    "has_jpa_lock_mode": ".setLockMode(" in body,
    "has_hibernate_lock_mode": ".setHibernateLockMode(" in body,
    "returns_dto": "List<JobUnlockedChunk>" in body,
}
for k, v in checks.items():
    print(f"{k}={v}")
print("--- method ---")
print(body)
PY

printf '%s\n' '--- Relevant test names only ---'
rg -l \
  'getAllUnlockedChunksForJobs|BatchJobProjectLockingManager|project.*lock|locked.*chunk|chunk.*lock' \
  backend --glob '*Test*.kt' | sort

Repository: tolgee/tolgee-platform

Length of output: 50378


🌐 Web query:

site:docs.hibernate.org/orm Hibernate query constructor expression setLockMode pessimistic lock DTO projection

💡 Result:

Applying a pessimistic lock to a query that uses a DTO projection (via constructor expression) is generally not supported or valid in JPA and Hibernate, as pessimistic locks require an entity alias to be locked at the database level [1][2]. When you use a constructor expression (e.g., SELECT NEW com.example.MyDTO(e.name, e.price) FROM Entity e), the query projects scalar values into a DTO [3]. Because these projections do not return managed entities, Hibernate cannot associate the result set with a database row to apply a lock [1][2]. ### Key Considerations: * Pessimistic Locking Requirements: Pessimistic locking (e.g., PESSIMISTIC_WRITE) targets managed entity instances to issue a SELECT FOR UPDATE statement [4]. A DTO projection creates an unmanaged object, rendering it incompatible with this mechanism [1]. * Alias-Specific Locking: In HQL/JPQL, you can specify alias-specific lock modes using SelectionQuery.setLockMode(String alias, LockMode lockMode) [1][2]. However, this requires the alias to refer to a mapped entity in the FROM clause, not a projected DTO [1][2]. * Alternatives: 1. Lock the entities first: If you need to perform operations on entities and return a DTO, fetch and lock the required entity instances first (e.g., using session.find with LockModeType or a separate entity-returning query), then transform them into DTOs in application memory. 2. Native SQL: If locking logic is strictly required for the projection, you may need to use a native SQL query that includes the FOR UPDATE clause manually, though this is database-specific and bypasses Hibernate's abstraction [4]. In modern Hibernate (version 6+), ensure you are using the SelectionQuery interface for all locking configurations rather than the deprecated LockOptions class where applicable [1][2].

Citations:


Make locked-chunk detection skip database-locked rows.

getAllUnlockedChunksForJobs uses a DTO constructor projection, so adding a JPA lock mode directly to this query is not a reliable fix. Use an entity-returning or native query with FOR UPDATE SKIP LOCKED, then map the results to JobUnlockedChunk. Otherwise, getInitialJobId can count locked chunks as unlocked and allow another job for the project. Add a concurrency test for this case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/data/src/main/kotlin/io/tolgee/batch/BatchJobService.kt` around lines
354 - 357, Update getAllUnlockedChunksForJobs to avoid relying on a lock hint
with its DTO constructor projection; use an entity-returning or native query
that applies FOR UPDATE SKIP LOCKED, then map the selected rows to
JobUnlockedChunk. Ensure getInitialJobId cannot treat database-locked chunks as
unlocked, and add a concurrency test covering two jobs contending for the same
project.

if (simpleStyle != null) {
sb.append(',').append(simpleStyle)
}
sb.append(',').append(simpleStyle)

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the no-style rendering.

simpleStyle returns "" when no style exists. This line therefore renders {0,number} as {0,number,}. Keep the previous style != null check so arguments without a style do not gain a trailing comma.

Proposed fix
-          sb.append(',').append(simpleStyle)
+          if (style != null) {
+            sb.append(',').append(simpleStyle)
+          }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sb.append(',').append(simpleStyle)
if (style != null) {
sb.append(',').append(simpleStyle)
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/data/src/main/kotlin/io/tolgee/formats/MessagePatternUtil.kt` at line
426, Update the rendering logic around simpleStyle so the comma is appended only
when style is non-null, preserving `{0,number}` for arguments without a style
while retaining styled output.

}

val text = json.get("text")?.asText() ?: ""
val text = json.get("text")?.asString() ?: ""

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail
rg -n -C 6 'handleTextUpdate|asString\(\)|asText\(\)|QaCheckPreviewError' ee/backend backend

Repository: tolgee/tolgee-platform

Length of output: 50378


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file='ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketHandler.kt'
echo '--- outline ---'
ast-grep outline "$file" --lang kotlin || true

echo '--- handler ---'
cat -n "$file" | sed -n '1,290p'

echo '--- related files ---'
git ls-files | rg -i 'qa.*(preview|websocket)|websocket.*qa|QaCheckPreview'

Repository: tolgee/tolgee-platform

Length of output: 13841


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo '--- exact related test references ---'
rg -n -i -C 8 'QaCheckPreview|qa.?check.?preview|handleTextUpdate|WebSocket' \
  ee/backend/tests ee/backend/app/src/test backend 2>/dev/null \
  | rg -i -C 8 'QaCheckPreview|qa.?check.?preview|handleTextUpdate|WebSocket' \
  | head -n 500

echo '--- Jackson dependency/version declarations ---'
rg -n -i -C 3 'jackson.*databind|tools.jackson|jacksonVersion|jackson.version' \
  --glob '!*build*' --glob '!*.lock' --glob '*.gradle*' --glob 'gradle.properties' \
  . | head -n 300

Repository: tolgee/tolgee-platform

Length of output: 50380


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail
file='ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketHandler.kt'
cat -n "$file" | sed -n '1,290p'
git ls-files | rg -i 'qa.*(preview|websocket)|websocket.*qa|QaCheckPreview'
rg -n -i -C 8 'QaCheckPreview|qa.?check.?preview|handleTextUpdate|WebSocket' ee/backend/tests ee/backend/app/src/test 2>/dev/null | head -n 500

Repository: tolgee/tolgee-platform

Length of output: 29918


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

test='ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketTest.kt'
helper='ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaPreviewWebSocketTestHelper.kt'

echo '--- test outline and size ---'
wc -l "$test" "$helper"
ast-grep outline "$test" --lang kotlin || true

echo '--- test methods and update assertions ---'
rg -n -C 5 'fun |sendText|sendInit|waitForDone|ERROR|error|message|closeStatus' "$test" "$helper"

echo '--- handler send path ---'
cat -n ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketHandler.kt | sed -n '287,320p'

Repository: tolgee/tolgee-platform

Length of output: 47718


🌐 Web query:

Jackson 3.0 JsonNode asString object array throws javadoc

💡 Result:

In Jackson 3.0, the JsonNode.asString() method is designed for coercing scalar values to a String [1][2]. When called on structured types—specifically ObjectNode (JSON objects) or ArrayNode (JSON arrays)—the method throws a tools.jackson.databind.exc.JsonNodeException [3][1]. This behavior differs from typical patterns in Jackson 2.x, where similar methods (like asText()) often returned an empty string or null for structured nodes instead of throwing an exception [4][5]. The JsonNodeException explicitly states that the value type is not coercible to a String [4][5]. To handle nodes that might be structured types without triggering this exception, you should: 1. Check the node type before calling asString() using methods like isTextual(), isObject(), or isArray() [1]. 2. Use non-coercing accessors such as stringValue() if you specifically require a String value and wish to handle non-string nodes differently (e.g., by returning null or a default) [1][6]. If you are migrating code from Jackson 2 to 3, be aware that asString() replaced the deprecated asText() [1][7]. If your existing logic relied on asText() to return a default string for complex objects or arrays, you may need to update your code to explicitly verify the node type or use the appropriate stringValue variants to avoid the JsonNodeException [4][5].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

test='ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketTest.kt'
helper='ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaPreviewWebSocketTestHelper.kt'

wc -l "$test" "$helper"
rg -n -C 5 'fun |sendText|sendInit|waitForDone|ERROR|error|message|closeStatus' "$test" "$helper"
cat -n "$helper" | sed -n '67,180p'

Repository: tolgee/tolgee-platform

Length of output: 48186


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

handler = Path("ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketHandler.kt").read_text()
test = Path("ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketTest.kt").read_text()
helper = Path("ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaPreviewWebSocketTestHelper.kt").read_text()

checks = {
    "update calls asString": 'json.get("text")?.asString()' in handler,
    "update has no local try/catch": not bool(re.search(
        r'private fun handleTextUpdate\b.*?\n\s*}\n\s*\n\s*private fun handleInit',
        handler, re.S
    )) or 'try {' not in re.search(
        r'private fun handleTextUpdate\b.*?\n\s*}\n\s*\n\s*private fun handleInit',
        handler, re.S
    ).group(0),
    "handleTextMessage calls update without catch": bool(re.search(
        r'override fun handleTextMessage\b.*?handleTextUpdate\(session, state, json\)',
        handler, re.S
    )),
    "tests send only scalar text values": not bool(re.search(
        r'send\(\s*(?:mapOf|mutableMapOf).*?"text"\s+to\s+(?!text\b)',
        test + helper, re.S
    )),
    "no non-scalar update test": not bool(re.search(
        r'(object|array|non.?scalar|invalid.*text|text.*invalid)',
        test, re.I
    )),
}

for name, value in checks.items():
    print(f"{name}: {value}")

assert all(checks.values())
PY

Repository: tolgee/tolgee-platform

Length of output: 348


Handle non-scalar text values in updates.

JsonNode.asString() throws for object and array nodes. Validate text before conversion and return a QaCheckPreviewError. Add tests for object and array values; current tests cover only scalar updates.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/qa/QaCheckPreviewWebSocketHandler.kt`
at line 130, Update the text extraction in the QA preview update handler around
the text JSON field: validate that text is scalar before converting it, and
return a QaCheckPreviewError for object or array values instead of calling
asString() on them. Preserve the existing empty/default behavior and add
coverage for both object and array text updates alongside the existing scalar
tests.

Source: MCP tools

Comment on lines +17 to +18
val output = json?.get("output")?.asString() ?: throw LlmProviderNotReturnedJsonException()
val contextDescription = json.get("contextDescription")?.asString()

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Expect parser tests to cover non-scalar output and contextDescription values.
rg -n -C 4 'PromptResultParser|LlmProviderNotReturnedJsonException|contextDescription|output' ee/backend

Repository: tolgee/tolgee-platform

Length of output: 50380


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- parser ---'
cat -n ee/backend/app/src/main/kotlin/io/tolgee/ee/service/prompt/PromptResultParser.kt

printf '%s\n' '--- parser references and tests ---'
rg -n -C 3 'PromptResultParser|LlmProviderNotReturnedJsonException' ee/backend/app ee/backend/tests

printf '%s\n' '--- Jackson dependency declarations ---'
rg -n -C 3 'jackson|tools.jackson' gradle*.kts gradle* libs.versions.toml ee/backend --glob '*.gradle' --glob '*.gradle.kts' --glob '*.toml' --glob '*.kt' | head -250

printf '%s\n' '--- relevant service flow ---'
sed -n '185,225p' ee/backend/app/src/main/kotlin/io/tolgee/ee/service/prompt/PromptServiceEeImpl.kt

Repository: tolgee/tolgee-platform

Length of output: 33636


🌐 Web query:

Jackson 3.1.4 JsonNode asString object array behavior JsonNodeException javadoc

💡 Result:

In Jackson 3.x, including version 3.1.4, the JsonNode.asString method is designed to return the string representation of a node if it is a scalar type [1][2]. When called on structured types like ObjectNode (JSON objects) or ArrayNode (JSON arrays), the asString method will throw a JsonNodeException [1][2]. This exception is a standard, unchecked exception introduced in Jackson 3 to handle issues specifically related to JsonNode operations [3][4]. Key behaviors for asString include: - Scalar Types: JSON strings map naturally, and other scalars (like numbers or booleans) are mapped to their string representations [1][2]. - Null and Missing Nodes: JSON null nodes and "missing nodes" are coerced into an empty string ("") [1][2]. - Structured Types: Calling asString on an ArrayNode or ObjectNode triggers a JsonNodeException because these types cannot be coerced into a simple string representation [1][2]. Note that asString is the successor to the Jackson 2.x asText method, which was deprecated in 3.0 as part of a broader effort to unify naming conventions (replacing "Text" with "String" in API method names) [5][6]. If you need to avoid the exception, you can use asString(String defaultValue), which returns the provided default value instead of throwing an exception for non-coercible types [1][2].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- provider-response exception ---'
rg -n -C 5 'class LlmProviderNotReturnedJsonException|LlmProviderNotReturnedJsonException' --glob '*.kt' --glob '*.java' .

printf '%s\n' '--- parser-related test files ---'
find ee/backend/tests ee/backend/app -type f \( -name '*Prompt*Test.kt' -o -name '*Parser*Test.kt' \) -print

printf '%s\n' '--- exception handlers ---'
rg -n -C 4 'LlmProviderNotReturnedJsonException|JsonNodeException|JacksonException|ExceptionHandler|ResponseStatus' backend ee --glob '*.kt' --glob '*.java' 2>/dev/null | head -300

Repository: tolgee/tolgee-platform

Length of output: 45019


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- exception hierarchy and status ---'
cat -n backend/data/src/main/kotlin/io/tolgee/exceptions/LlmProviderNotReturnedJsonException.kt
rg -n -C 4 'open class FailedDependencyException|class FailedDependencyException|open class ErrorException|class ErrorException' backend/data backend/app --glob '*.kt'

printf '%s\n' '--- generic exception handling ---'
sed -n '150,190p' backend/app/src/main/kotlin/io/tolgee/ExceptionHandlers.kt
rg -n -C 3 '`@ExceptionHandler`\\(Exception::class|`@ExceptionHandler`\\(Throwable::class|Exception::class|Throwable::class' backend/app/src/main/kotlin/io/tolgee --glob '*.kt' | head -120

printf '%s\n' '--- source-level asString implementation ---'
python3 - <<'PY'
from urllib.request import urlopen
url = "https://raw.githubusercontent.com/FasterXML/jackson-databind/3.1/src/main/java/tools/jackson/databind/JsonNode.java"
try:
    text = urlopen(url, timeout=10).read().decode()
except Exception as exc:
    print(f"fetch failed: {exc}")
else:
    lines = text.splitlines()
    for i, line in enumerate(lines):
        if "String asString" in line:
            print("\n".join(f"{j+1}: {lines[j]}" for j in range(max(0, i-4), min(len(lines), i+18))))
PY

Repository: tolgee/tolgee-platform

Length of output: 4024


🏁 Script executed:

#!/usr/bin/env bash
set -u

printf '%s\n' '--- exception status definitions ---'
cat -n backend/data/src/main/kotlin/io/tolgee/exceptions/FailedDependencyException.kt
cat -n backend/data/src/main/kotlin/io/tolgee/exceptions/ErrorException.kt | head -80

printf '%s\n' '--- generic exception handlers ---'
rg -n -F '`@ExceptionHandler`(Exception::class)' backend/app/src/main/kotlin/io/tolgee --glob '*.kt' || true
rg -n -F '`@ExceptionHandler`(Throwable::class)' backend/app/src/main/kotlin/io/tolgee --glob '*.kt' || true

printf '%s\n' '--- source-level asString implementation ---'
python3 - <<'PY'
from urllib.request import urlopen
urls = [
    "https://raw.githubusercontent.com/FasterXML/jackson-databind/3.1/src/main/java/tools/jackson/databind/JsonNode.java",
    "https://raw.githubusercontent.com/FasterXML/jackson-databind/3.x/src/main/java/tools/jackson/databind/JsonNode.java",
]
for url in urls:
    print(f"URL: {url}")
    try:
        text = urlopen(url, timeout=10).read().decode()
    except Exception as exc:
        print(f"fetch failed: {exc}")
        continue
    lines = text.splitlines()
    found = False
    for i, line in enumerate(lines):
        if "String asString" in line:
            found = True
            print("\n".join(f"{j+1}: {lines[j]}" for j in range(max(0, i-5), min(len(lines), i+20))))
    if not found:
        print("asString declaration not found")
PY

Repository: tolgee/tolgee-platform

Length of output: 2487


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

sed -n '260,305p' backend/app/src/main/kotlin/io/tolgee/ExceptionHandlers.kt

Repository: tolgee/tolgee-platform

Length of output: 1873


Handle non-scalar provider fields before conversion.

JsonNode.asString() throws JsonNodeException for object and array values. Since PromptServiceEeImpl calls PromptResultParser.parse() outside its RestClientException handler, malformed fields reach the generic Throwable handler and return 500 unexpected_error_occurred instead of the provider-response error. Validate both fields before conversion and add parser tests for object and array values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ee/backend/app/src/main/kotlin/io/tolgee/ee/service/prompt/PromptResultParser.kt`
around lines 17 - 18, Update PromptResultParser.parse() to validate output and
contextDescription are scalar JSON values before calling asString(), mapping
object and array values to the existing provider-response error instead of
allowing JsonNodeException to escape. Preserve the current missing-output
behavior, and add parser tests covering object and array values for both fields.

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.

1 participant