Skip to content

[NAE-2382] Elastic bulk index fails if option fields have empty string#416

Merged
machacjozef merged 8 commits intorelease/7.0.0-rev10from
NAE-2382
Mar 2, 2026
Merged

[NAE-2382] Elastic bulk index fails if option fields have empty string#416
machacjozef merged 8 commits intorelease/7.0.0-rev10from
NAE-2382

Conversation

@renczesstefan
Copy link
Member

@renczesstefan renczesstefan commented Feb 23, 2026

Description

Fix elastic bulk fail, when translation with empty key fails + added additional logging for RestResponseErrorHandler

Fixes NAE-2382

Dependencies

No new dependencies where introduced.

Third party dependencies

No new dependencies were introduced.

Blocking Pull requests

There are no dependencies on other PR.

How Has Been This Tested?

This was tested manually and with unit tests.

Test Configuration

Name Tested on
OS macOS Tahoe 26.3
Runtime Java 21
Dependency Manager Maven 3.9.9n
Framework version Spring Boot 3.4.4
Run parameters
Other configuration

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes have been checked, personally or remotely, with @machacjozef
  • I have commented my code, particularly in hard-to-understand areas
  • I have resolved all conflicts with the target branch of the PR
  • I have updated and synced my code with the target branch
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes:
    • Lint test
    • Unit tests
    • Integration tests
  • I have checked my contribution with code analysis tools:
  • I have made corresponding changes to the documentation:
    • Developer documentation
    • User Guides
    • Migration Guides

Summary by CodeRabbit

  • Bug Fixes

    • Normalize null or blank map field keys to a consistent "none" option to prevent missing or duplicate choices.
  • Chores

    • Enhanced logging for JSON serialization errors with more detailed path descriptions and trace entries to improve troubleshooting.

- updated null or empty string key handling for elastic translation objects
- added additional logging to RestResponseExceptionHandler
@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds detailed logging and path-inspection helpers to RestResponseExceptionHandler for JsonMappingException traces, and introduces NONE_OPTION_KEY plus key-normalization and deterministic LinkedHashMap usage in MapField constructors.

Changes

Cohort / File(s) Summary
Exception Handler Logging
application-engine/src/main/java/com/netgrif/application/engine/workflow/web/RestResponseExceptionHandler.java
Adds trace/debug/error logging inside handleHttpMessageNotWritable, introduces describePath(...) and tracePathAll(...) helpers, and logs detailed JsonMappingException.Reference inspection (including guarded access to path elements and class/value logging).
Map Key Normalization
nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java
Adds public static final String NONE_OPTION_KEY = "none", a private resolveTranslationPairKey(...) helper to normalize null/blank keys to that constant, switches keyValueTranslations construction to LinkedHashMap, and applies normalized keys in constructors and entry handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: fixing a bug where Elasticsearch bulk indexing fails when option fields contain empty strings.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@coderabbitai coderabbitai bot added bugfix A change that fixes a bug Extra Small labels Feb 23, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@application-engine/src/main/java/com/netgrif/application/engine/workflow/web/RestResponseExceptionHandler.java`:
- Around line 42-45: The debug logging calls use fieldFrom.getClass() and
caseFrom.getClass() which will NPE if path.getLast().getFrom() or
path.get(path.size() - 3).getFrom() returns null; update the logging in
RestResponseExceptionHandler to be null-safe by deriving class names defensively
(e.g., use a conditional or Objects.toString/getClassName fallback) when
referencing fieldFrom and caseFrom from their getFrom() results, and log a clear
placeholder like "null" or "unknown" for the class when getFrom() is null so the
debug statements never call .getClass() on a null reference.

In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java`:
- Around line 40-44: In the loop over valueTranslationPairs, avoid calling
resolveTranslationPairKey twice for the same entry: compute String resolvedKey =
resolveTranslationPairKey(valueTranslationPair.getKey()) once, use resolvedKey
when adding to this.keyValue and when putting into this.keyValueTranslations,
and retain
values.addAll(I18nStringUtils.collectTranslations(valueTranslationPair.getValue()));
so resolveTranslationPairKey, valueTranslationPair, this.keyValue and
this.keyValueTranslations are referenced but only invoked once per iteration.
- Around line 24-26: The copy constructor for MapField uses Collectors.toMap on
field.keyValueTranslations which can throw IllegalStateException when multiple
source keys map to the same resolved key (via resolveTranslationPairKey); modify
that stream collect call to pass a merge function that keeps the last value
(e.g. (oldVal, newVal) -> newVal) so duplicate resolved keys are handled like
HashMap.put; update the expression that constructs I18nString(entry.getValue())
accordingly and keep resolveTranslationPairKey and I18nString references
unchanged.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64a0bfc and 00144dd.

📒 Files selected for processing (2)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/web/RestResponseExceptionHandler.java
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java

Retoocs
Retoocs previously approved these changes Feb 23, 2026
Updated the collector in MapField to ensure that keyValueTranslations maintains insertion order by using LinkedHashMap. Additionally, resolved potential duplicate key conflicts by explicitly handling them in the collector function.
Previously, debug logs for 'fieldFrom' and 'caseFrom' assumed non-null values, which could lead to a null pointer exception. This update adds checks to handle null values gracefully in log statements.
tuplle
tuplle previously approved these changes Feb 23, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java (1)

44-46: 🧹 Nitpick | 🔵 Trivial

resolveTranslationPairKey invoked twice for the same key — extract to a local variable.

♻️ Proposed refactor
         for (Map.Entry<String, I18nString> valueTranslationPair : valueTranslationPairs) {
-            this.keyValue.add(resolveTranslationPairKey(valueTranslationPair.getKey()));
+            String resolvedKey = resolveTranslationPairKey(valueTranslationPair.getKey());
+            this.keyValue.add(resolvedKey);
             values.addAll(I18nStringUtils.collectTranslations(valueTranslationPair.getValue()));
-            this.keyValueTranslations.put(resolveTranslationPairKey(valueTranslationPair.getKey()), valueTranslationPair.getValue());
+            this.keyValueTranslations.put(resolvedKey, valueTranslationPair.getValue());
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java`
around lines 44 - 46, In MapField, avoid calling resolveTranslationPairKey twice
for the same valueTranslationPair: compute String resolvedKey =
resolveTranslationPairKey(valueTranslationPair.getKey()) once and reuse it for
keyValue.add(...) and keyValueTranslations.put(...), leaving
values.addAll(I18nStringUtils.collectTranslations(...)) unchanged; update the
code inside the block that currently calls resolveTranslationPairKey in both
keyValue.add and keyValueTranslations.put to use the local resolvedKey variable
instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java`:
- Line 42: The list-based constructor of MapField initializes
keyValueTranslations with new HashMap<>() which breaks the insertion-order
guarantee preserved by the copy constructor (which uses LinkedHashMap::new);
update the list-based constructor to initialize keyValueTranslations with a
LinkedHashMap (consistent with the copy constructor) so key iteration order is
deterministic for Elastic indexing—look for the MapField constructor that sets
this.keyValueTranslations and replace its HashMap instantiation with
LinkedHashMap.

---

Duplicate comments:
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java`:
- Around line 44-46: In MapField, avoid calling resolveTranslationPairKey twice
for the same valueTranslationPair: compute String resolvedKey =
resolveTranslationPairKey(valueTranslationPair.getKey()) once and reuse it for
keyValue.add(...) and keyValueTranslations.put(...), leaving
values.addAll(I18nStringUtils.collectTranslations(...)) unchanged; update the
code inside the block that currently calls resolveTranslationPairKey in both
keyValue.add and keyValueTranslations.put to use the local resolvedKey variable
instead.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00144dd and 72eb842.

📒 Files selected for processing (2)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/web/RestResponseExceptionHandler.java
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java

Switched from HashMap to LinkedHashMap in keyValueTranslations to maintain the insertion order of entries. This change ensures predictable ordering when iterating over the map, which may be crucial for consistent processing or display.
Switched from HashMap to LinkedHashMap in keyValueTranslations to maintain the insertion order of entries. This change ensures predictable ordering when iterating over the map, which may be crucial for consistent processing or display.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java`:
- Around line 44-47: The constructor code in MapField is storing mutable
I18nString objects by reference into keyValueTranslations (via
this.keyValueTranslations.put(key, valueTranslationPair.getValue())), which can
leak external mutations; change the constructor to defensively copy the
I18nString before putting it into keyValueTranslations (create a new I18nString
copy from valueTranslationPair.getValue()) so MapField holds its own instance;
locate the MapField(List<...>) constructor and replace the direct put with
putting a cloned/constructed copy of the I18nString (use the same copy semantics
used elsewhere in the codebase, e.g., how ElasticCase deep-copies nested
objects) while keeping resolveTranslationPairKey(valueTranslationPair.getKey())
and existing collection logic unchanged.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8fd185f and 227bb3d.

📒 Files selected for processing (1)
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java

Previously, the code directly assigned a nullable value, which could lead to potential issues. This change ensures that the value is wrapped in an I18nString instance if not null, improving safety and consistency when managing translations.
@renczesstefan renczesstefan requested a review from Retoocs March 2, 2026 11:13
tuplle
tuplle previously approved these changes Mar 2, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java (1)

21-30: ⚠️ Potential issue | 🟠 Major

keyValue is not normalized in the copy constructor, but keyValueTranslations keys are — potential data inconsistency.

The copy constructor normalizes keys in keyValueTranslations (line 27), but copies keyValue verbatim (line 23). If the source field contains an empty-string key:

  • this.keyValue will still hold ""
  • this.keyValueTranslations will have key "none"

This breaks the invariant established by the list constructor (lines 44-50), where both collections use the same normalized key. The getValue() method (line 56-63) returns elements from keyValue, potentially returning unnormalized keys.

🛡️ Proposed fix — normalize keyValue during copy
     public MapField(MapField field) {
         super(field);
-        this.keyValue = field.keyValue == null ? null : new ArrayList<>(field.keyValue);
+        this.keyValue = field.keyValue == null ? null
+                : field.keyValue.stream()
+                .map(this::resolveTranslationPairKey)
+                .collect(Collectors.toCollection(ArrayList::new));
         this.keyValueTranslations = field.keyValueTranslations == null ? null
                 : field.keyValueTranslations.entrySet().stream()
                 .collect(Collectors.toMap(entry ->
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java`
around lines 21 - 30, The copy constructor MapField(MapField field) copies
keyValue verbatim while normalizing keys for keyValueTranslations causing
mismatch; update the constructor to normalize each key in field.keyValue using
the same resolveTranslationPairKey(...) logic (preserve null handling and
ordering) when creating this.keyValue (e.g., map each element through
resolveTranslationPairKey before collecting into the new ArrayList) so keyValue
and keyValueTranslations remain consistent with getValue() expectations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java`:
- Around line 21-30: The copy constructor MapField(MapField field) copies
keyValue verbatim while normalizing keys for keyValueTranslations causing
mismatch; update the constructor to normalize each key in field.keyValue using
the same resolveTranslationPairKey(...) logic (preserve null handling and
ordering) when creating this.keyValue (e.g., map each element through
resolveTranslationPairKey before collecting into the new ArrayList) so keyValue
and keyValueTranslations remain consistent with getValue() expectations.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 227bb3d and aa4fd40.

📒 Files selected for processing (2)
  • application-engine/src/main/java/com/netgrif/application/engine/workflow/web/RestResponseExceptionHandler.java
  • nae-object-library/src/main/java/com/netgrif/application/engine/objects/elastic/domain/MapField.java

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 2, 2026
@renczesstefan renczesstefan requested a review from tuplle March 2, 2026 11:50
Updated the log message in RestResponseExceptionHandler to specify that the JSON write failure is due to the path being smaller than 3. This improves clarity and debugging efficiency when analyzing error logs.
@machacjozef machacjozef merged commit 8a9eb74 into release/7.0.0-rev10 Mar 2, 2026
6 of 7 checks passed
@machacjozef machacjozef deleted the NAE-2382 branch March 2, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix A change that fixes a bug Extra Small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants