feat(core): add base64 decode JSLT custom function - #126
Conversation
…object and array payloads Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
…e64-jstl-function
Signed-off-by: ferial OUKOUKAS <75682459+foukou19@users.noreply.github.com>
…e64-jstl-function
Code Coverage OverviewLanguages: Java Java / code-coverage/jacocoThe overall coverage in commit 6683b40 in the Show a code coverage summary of the most impacted files.
Updated |
There was a problem hiding this comment.
Pull request overview
Adds a custom Base64 decoder to the JSLT entity-mapping engine.
Changes:
- Registers injectable custom JSLT functions.
- Implements and tests
base64-decode. - Adds a comment-audit agent configuration.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
JsltEngine.java |
Registers custom JSLT functions. |
DecodeBase64.java |
Implements Base64 decoding. |
DecodeBase64Test.java |
Tests decoding and integration. |
JsltMappingEngineAdapterTest.java |
Updates engine construction. |
JsltEntityMappingValidatorTest.java |
Updates engine construction. |
comment-audit.agent.json |
Adds an agent configuration. |
Suppressed comments (3)
src/main/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/functions/DecodeBase64.java:93
- Do not include the supplied Base64 value in this exception.
JsltEnginepreserves the message, andApiExceptionHandlerlogs and returns it (ApiExceptionHandler.java:347-351), so malformed values—which may contain encoded credentials or tokens—are copied into application logs and API errors.
throw new IllegalArgumentException("Invalid Base64 string payload: '" + textValue + "'", e);
src/main/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/functions/DecodeBase64.java:24
- This adds a platform-specific JSLT function, but the user-facing JSLT mapping reference still only points to upstream JSLT documentation (
docs/src/features/data-integration.md:185-187), wherebase64-decodedoes not exist. Document its name, accepted input, return behavior, and failure behavior indocs/src/so mapping authors can discover and use the feature.
public static final String FUNCTION_NAME = "base64-decode";
src/main/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/functions/DecodeBase64.java:102
- The new behavior that parses decoded content as JSON is not exercised by
DecodeBase64Test; its success cases only take the plain-text fallback. Add coverage for Base64-encoded JSON (including an object or scalar) so the function's type-changing return contract is protected.
JsonNode parsed = OBJECT_MAPPER.readTree(decodedString);
// Jackson returns Java null if decodedString is empty ("")
return (parsed != null) ? parsed : TextNode.valueOf(decodedString);
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (6)
src/main/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/JsltEngine.java:19
- The constructor description is still a plain
//comment, so the JavaDoc consists only of an@paramtag. Make the description part of the contiguous///JavaDoc block.
// Creates a JSLT engine with the custom functions discovered by Spring.
src/main/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/functions/DecodeBase64.java:93
- The malformed value is propagated through
JsltEngineand is both logged and returned byApiExceptionHandler(ApiExceptionHandler.java:350-351). Because mapped fields may contain credentials or other sensitive payload data, do not embed the input value in the exception message; retain it only as the cause-free context if needed.
throw new IllegalArgumentException("Invalid Base64 string payload: '" + textValue + "'", e);
src/main/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/functions/DecodeBase64.java:20
- This adds a user-facing JSLT function, but the JSLT mapping reference in
docs/src/features/data-integration.md:185-187still only points to the upstream language documentation, which cannot describe this project-specific function. Add the function name, usage, accepted input, null behavior, and JSON/text return behavior under that reference, as required for behavior changes.
/// **Usage in JSLT:** `base64-decode(<base64-encoded-string>)`
///
/// Returns `null` if the input is absent, null, or blank.
src/main/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/functions/DecodeBase64.java:100
ObjectMapper.readTreedoes not reject trailing root-level tokens by default. A decoded non-JSON string such astrue storycan therefore become the Boolean nodetrueinstead of falling back to the original text, silently discarding content. Enable trailing-token validation so only a complete JSON document is treated as JSON.
JsonNode parsed = OBJECT_MAPPER.readTree(decodedString);
.github/agents/comment-audit.agent.md:24
- The declared output-format example ends inside an unclosed Java fence and never tells the agent to report the observed behavior, discrepancy, or correction. As a result, the agent has no complete structured output contract. Complete and close the template.
- **Existing Docstring:**
```java
<existing_docstring>
src/test/java/com/decathlon/idp_core/infrastructure/adapters/entity_mapping/jslt/functions/DecodeBase64Test.java:110
- All successful cases currently decode plain text, which takes the
JsonProcessingExceptionfallback path. The newly advertised behavior that returns structured decoded JSON is therefore untested; add a case that decodes a JSON object and asserts its structure.
JsonNode result = jsltEngine.evaluate(jsltExpression, payload);
|



PR Description
What this PR Provides
This pull request introduces support for custom JSLT functions in the
JsltEngine, and adds a newDecodeBase64function for decoding Base64-encoded strings within JSLT expressions. The implementation includes robust error handling, integration with Spring, and comprehensive unit and integration tests to ensure correctness.Key changes include:
JSLT Engine Extensibility
JsltEngineto accept a collection of custom JSLTFunctioninstances via its constructor, enabling injection and registration of custom functions. Updated thecompilemethod to use these functions when compiling expressions. Error handling invalidateExpressionandevaluatenow catches all exceptions for consistent error reporting. [1] [2]New Custom Function: DecodeBase64
DecodeBase64, a Spring component implementing the JSLTFunctioninterface. This function decodes Base64-encoded strings, gracefully returnsnullfor absent/blank inputs, parses decoded content as JSON if possible, and throws clear exceptions for invalid input types or malformed Base64.Testing and Validation
DecodeBase64Testto thoroughly test the new function, covering direct invocation, error cases, and integration withJsltEngine.JsltEntityMappingValidatorTest,JsltMappingEngineAdapterTest) to instantiateJsltEnginewith an empty list of functions, ensuring compatibility with the new constructor. [1] [2] [3] [4]Tooling
.github/agents/comment-audit.agent.jsonfor auditing code comments and docstrings for consistency with implementation.Fixes
Review
The reviewer must double-check these points:
!after the type/scope to identify the breakingchange in the release note and ensure we will release a major version.
How to test
Please refer (copy/paste) the test section from the User Story. This should include
Breaking changes (if any)
Context of the Breaking Change
For example: we redefined the component types list in the DPAC referential
Result of the Breaking Change
For example: your component of type xxx will migrate to the type yyy