Skip to content

Add unit tests and enhance error logging in GlobalExceptionHandler#39

Merged
PasinduOG merged 4 commits into
devfrom
feature/v1.5.0
May 10, 2026
Merged

Add unit tests and enhance error logging in GlobalExceptionHandler#39
PasinduOG merged 4 commits into
devfrom
feature/v1.5.0

Conversation

@PasinduOG
Copy link
Copy Markdown
Contributor

@PasinduOG PasinduOG commented May 9, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced error logging in exception handlers to include exception location information for improved troubleshooting.
  • Tests

    • Added comprehensive test coverage for exception handling, response wrapping, annotation validation, and data deserialization features.

Review Change Stack

@PasinduOG PasinduOG self-assigned this May 9, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97606696-8ac6-4606-817e-215084c03bf2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/v1.5.0

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

Copy link
Copy Markdown

@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

Caution

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

⚠️ Outside diff range comments (2)
src/main/java/io/github/og4dev/exception/GlobalExceptionHandler.java (2)

162-173: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Logged status can be incorrect for registry-mapped exceptions.

The error log always prints INTERNAL_SERVER_ERROR before registry lookup. For mapped exceptions (e.g., 4xx/5xx custom), logs will show the wrong status.

💡 Suggested fix
-        log.error("[TraceID: {}] Error in {} | Message: {} | Status: {}",
-                traceId, location, ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+        HttpStatus resolvedStatus = HttpStatus.INTERNAL_SERVER_ERROR;
+        String resolvedMessage = "Internal Server Error. Please contact technical support.";

         // Check if the exception is registered in the ApiExceptionRegistry
         if (registry != null) {
             ApiExceptionRegistry.ExceptionRule rule = registry.getRule(ex.getClass());
             if (rule != null) {
-                ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(rule.getStatus(), rule.getMessage());
+                resolvedStatus = rule.getStatus();
+                resolvedMessage = rule.getMessage();
+                log.error("[TraceID: {}] Error in {} | Message: {} | Status: {}",
+                        traceId, location, ex.getMessage(), resolvedStatus);
+                ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(resolvedStatus, resolvedMessage);
                 problemDetail.setProperty("traceId", traceId);
                 problemDetail.setProperty("timestamp", Instant.now());
                 return problemDetail;
             }
         }
+        log.error("[TraceID: {}] Error in {} | Message: {} | Status: {}",
+                traceId, location, ex.getMessage(), resolvedStatus);

         // Default Fallback
         ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
-                HttpStatus.INTERNAL_SERVER_ERROR,
-                "Internal Server Error. Please contact technical support.");
+                resolvedStatus, resolvedMessage);
🤖 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 `@src/main/java/io/github/og4dev/exception/GlobalExceptionHandler.java` around
lines 162 - 173, The log currently hardcodes HttpStatus.INTERNAL_SERVER_ERROR
before checking the ApiExceptionRegistry, causing incorrect logged status for
mapped exceptions; update GlobalExceptionHandler so it looks up
registry.getRule(ex.getClass()) first (if registry != null) to obtain the actual
HttpStatus (rule.getStatus()) and use that status value in the log.error call
(and when constructing ProblemDetail via ProblemDetail.forStatusAndDetail),
falling back to HttpStatus.INTERNAL_SERVER_ERROR only when no rule exists; refer
to ApiExceptionRegistry.ExceptionRule, registry.getRule(...),
ProblemDetail.forStatusAndDetail and the existing log.error invocation to find
and replace the status usage.

98-111: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Constructor injection regression: registry will be null with dual constructors, disabling custom exception mappings.

With both a no-arg and parameterized constructor present, Spring's constructor-resolution algorithm does not reliably select the parameterized constructor when the @Autowired annotation is only on the parameter. Spring will fall back to the no-arg constructor when it cannot satisfy the parameterized candidate, leaving registry null and effectively disabling all custom exception mapping rules at runtime.

Add @Autowired(required = false) to the parameterized constructor itself (not the parameter) to ensure deterministic constructor selection:

Suggested fix
     public GlobalExceptionHandler() {}

-    public GlobalExceptionHandler(`@Autowired`(required = false) ApiExceptionRegistry registry) {
+    `@Autowired`(required = false)
+    public GlobalExceptionHandler(ApiExceptionRegistry registry) {
         this.registry = registry;
     }
🤖 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 `@src/main/java/io/github/og4dev/exception/GlobalExceptionHandler.java` around
lines 98 - 111, The parameterized constructor in GlobalExceptionHandler is not
reliably chosen by Spring because `@Autowired` is placed on the parameter while a
no-arg constructor also exists; move the injection annotation to the constructor
itself by annotating the constructor with `@Autowired`(required = false) (and
remove the `@Autowired` from the parameter) so Spring deterministically injects
ApiExceptionRegistry into the GlobalExceptionHandler.registry field when
present.
🤖 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 `@src/test/java/io/github/og4dev/config/AdvancedStringDeserializerTest.java`:
- Around line 297-303: The test method
classTrimFieldXss_allowsHtmlOnPlainField_sinceNoXssCheck currently feeds plain
text instead of HTML; update the JSON payload string in that test so the "plain"
property contains HTML (e.g. "<b>safe</b>") and adjust the assertion on
ClassTrimFieldXssDto.result.plain to expect the exact HTML value (ensuring
objectMapper.readValue still deserializes to ClassTrimFieldXssDto and that the
"plain" field preserves the HTML).

---

Outside diff comments:
In `@src/main/java/io/github/og4dev/exception/GlobalExceptionHandler.java`:
- Around line 162-173: The log currently hardcodes
HttpStatus.INTERNAL_SERVER_ERROR before checking the ApiExceptionRegistry,
causing incorrect logged status for mapped exceptions; update
GlobalExceptionHandler so it looks up registry.getRule(ex.getClass()) first (if
registry != null) to obtain the actual HttpStatus (rule.getStatus()) and use
that status value in the log.error call (and when constructing ProblemDetail via
ProblemDetail.forStatusAndDetail), falling back to
HttpStatus.INTERNAL_SERVER_ERROR only when no rule exists; refer to
ApiExceptionRegistry.ExceptionRule, registry.getRule(...),
ProblemDetail.forStatusAndDetail and the existing log.error invocation to find
and replace the status usage.
- Around line 98-111: The parameterized constructor in GlobalExceptionHandler is
not reliably chosen by Spring because `@Autowired` is placed on the parameter
while a no-arg constructor also exists; move the injection annotation to the
constructor itself by annotating the constructor with `@Autowired`(required =
false) (and remove the `@Autowired` from the parameter) so Spring
deterministically injects ApiExceptionRegistry into the
GlobalExceptionHandler.registry field when present.
🪄 Autofix (Beta)

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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9fe33833-40d5-4ddb-84b9-52a0abcd02dd

📥 Commits

Reviewing files that changed from the base of the PR and between 770efee and 6154c7b.

📒 Files selected for processing (7)
  • pom.xml
  • src/main/java/io/github/og4dev/exception/GlobalExceptionHandler.java
  • src/test/java/io/github/og4dev/advice/GlobalResponseWrapperTest.java
  • src/test/java/io/github/og4dev/annotation/AutoResponseAnnotationTest.java
  • src/test/java/io/github/og4dev/config/AdvancedStringDeserializerTest.java
  • src/test/java/io/github/og4dev/exception/ApiExceptionRegistryTest.java
  • src/test/java/io/github/og4dev/exception/GlobalExceptionHandlerTest.java

…lerTest to use parameterized tests for better coverage
@PasinduOG PasinduOG removed the request for review from Pramudithalakshan May 10, 2026 11:48
@PasinduOG PasinduOG merged commit d57b022 into dev May 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant