-
Notifications
You must be signed in to change notification settings - Fork 43
Feature/sync issue #156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release-3.4.0
Are you sure you want to change the base?
Feature/sync issue #156
Conversation
WalkthroughUpdates Maven version; renames a local variable in a controller; adds a transient is_high_risk field and wires repository/service logic to populate it in nurse worklists; adjusts type casting in two services and a lab mapping; introduces a Constants utility; refactors JWT filter and related utilities to use Constants and wrapped requests; hardens error handling in CHO app service. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant F as JwtUserIdValidationFilter
participant W as AuthorizationHeaderRequestWrapper
participant S as Downstream Controller
C->>F: HTTP request (cookies/headers)
alt Valid JWT from cookie/header
F->>W: Wrap request with Authorization header
W->>S: Forward wrapped request
S-->>C: Response
else Invalid/No JWT
F->>F: Check User-Agent (mobile?)
alt Mobile client with Authorization present
F->>S: Forward request (UserAgentContext set)
S-->>C: Response
F->>F: Clear UserAgentContext
else Block/handle as per existing flow
F-->>C: Error/unauthorized (unchanged messaging)
end
end
sequenceDiagram
autonumber
participant NS as CommonNurseServiceImpl
participant R as BeneficiaryFlowStatusRepo
participant DB as DB
NS->>R: getNurseWorklistNew(fromDate,...)
R->>DB: Query worklist
DB-->>R: List<BeneficiaryFlowStatus>
loop For each beneficiary
NS->>R: getIsHighrisk(ben_id)
R->>DB: SELECT is_high_risk FROM t_anc_visit
DB-->>R: Boolean
R-->>NS: Boolean
NS->>NS: set is_high_risk if non-null
end
NS-->>NS: Return enriched list
sequenceDiagram
autonumber
participant A as CHOAppSyncServiceImpl
participant Repo as Activity Repository
participant C as Caller
C->>A: getActivityById(id, auth)
A->>Repo: findById(id)
alt Found
A->>A: Convert images to Base64 if present
A-->>C: 200 OK with JSON
else Not found
A-->>C: 404 Not Found
end
note over A: Exceptions -> log and 500
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ast-grep (0.38.6)src/main/java/com/iemr/hwc/service/common/transaction/CommonNurseServiceImpl.javaTip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal). Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
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/com/iemr/hwc/service/choApp/CHOAppSyncServiceImpl.java (2)
260-266
: Root cause not fixed: robustly parse “data” to avoid ClassCastExceptionUsing getString("data") assumes a String but upstream sometimes returns a JSONArray/Boolean/Number, causing “Boolean cannot be cast to class String”. Parse defensively.
Apply this diff:
- JSONObject responseJSON = new JSONObject(response.getBody()); - JSONArray jsonArray = new JSONArray(responseJSON.getJSONObject("response").getString("data")); - - outputResponse.setResponse(jsonArray.toString()); + JSONObject responseJSON = new JSONObject(response.getBody()); + Object dataNode = responseJSON.getJSONObject("response").opt("data"); + JSONArray jsonArray; + if (dataNode instanceof JSONArray) { + jsonArray = (JSONArray) dataNode; + } else if (dataNode instanceof String) { + jsonArray = new JSONArray((String) dataNode); + } else { + jsonArray = new JSONArray(); + } + outputResponse.setResponse(jsonArray.toString());
325-329
: Same casting pitfall for count; don’t assume String“data” may be numeric/boolean. Use String.valueOf(opt(...)).
Apply this diff:
- JSONObject responseJSON = new JSONObject(response.getBody()); - String count = responseJSON.getJSONObject("response").getString("data"); - - outputResponse.setResponse(count); + JSONObject responseJSON = new JSONObject(response.getBody()); + Object dataNode = responseJSON.getJSONObject("response").opt("data"); + outputResponse.setResponse(String.valueOf(dataNode));
🧹 Nitpick comments (7)
src/main/java/com/iemr/hwc/controller/wo/LocationControllerWo.java (1)
201-215
: Avoid shadowing the controller field; use a local name and prefer removing the mutable field.The local variable ‘response’ shadows the class field ‘response’, which is confusing. Also, mutable controller fields are unsafe in Spring singletons. Use a clearly named local and consider removing the class field across this controller.
Apply within this method:
- OutputResponse response = new OutputResponse(); + OutputResponse out = new OutputResponse(); @@ - response.setResponse(resList); + out.setResponse(resList); @@ - response.setError(500, "Unable to fetch outreach list for stateId" + stateID + "Exception - " + e); + out.setError(500, "Unable to fetch outreach list for stateId" + stateID + "Exception - " + e); @@ - return new ResponseEntity<>(response.toStringWithSerializeNulls(), headers, statusCode); + return new ResponseEntity<>(out.toStringWithSerializeNulls(), headers, statusCode);Follow-up: remove the class field
private OutputResponse response;
and make all methods use locals.src/main/java/com/iemr/hwc/utils/http/HTTPRequestInterceptor.java (1)
127-129
: Post-handle guard LGTM.Only updating the session when Authorization is non-empty is correct.
Consider using a case-insensitive, prefix check for “Bearer ” in pre/post handle to avoid false positives with tokens in other header positions.
src/main/java/com/iemr/hwc/utils/Constants.java (1)
3-9
: Make the constants holder final.Prevent extension of the utility class.
-public class Constants { +public final class Constants {src/main/java/com/iemr/hwc/utils/RestTemplateUtil.java (1)
42-44
: Conditional header add is correct and safer.Good move to only forward JWT header when present.
Minor: when building the Cookie header, prefer the constant for the name to avoid drift (use
Constants.JWT_TOKEN + "=" + jwtTokenFromCookie
).src/main/java/com/iemr/hwc/data/labModule/ProcedureComponentMapping.java (1)
332-344
: Fixes the Boolean→String CCE; small follow-up nit.Using
String.valueOf(...)
and keeping booleans uncast resolves the ClassCastException. Consider storings.toString()
instead of the StringBuilder instance when puttingcompList
, for clarity during JSON serialization.Please confirm downstream JSON consumers expect booleans for
isMandatory
/isCalibration
(not strings).src/main/java/com/iemr/hwc/service/choApp/CHOAppSyncServiceImpl.java (1)
620-623
: Log the exception with stacktraceErrors are logged without the throwable, losing stack traces.
Apply this diff:
- logger.error("Error while fetching Prescription Templates userID : " + userID); + logger.error("Error while fetching Prescription Templates userID : {}", userID, e);- logger.error("Error while deleting Prescription Templates userID : " + userID + " tempID : " + tempID); + logger.error("Error while deleting Prescription Templates userID : {} tempID : {}", userID, tempID, e);- logger.error("Encountered exception while fetching activity activityId " + activityId); + logger.error("Encountered exception while fetching activity activityId {}", activityId, e);Also applies to: 638-642, 735-738
src/main/java/com/iemr/hwc/data/benFlowStatus/BeneficiaryFlowStatus.java (1)
299-311
: Expose is_high_risk for serializers and accept nulls
- Field isn’t annotated with @expose; any Gson configured with excludeFieldsWithoutExposeAnnotation will omit it.
- Setter takes primitive boolean, preventing null assignment.
Apply this diff:
- @Transient - Boolean is_high_risk; + @Transient + @Expose + private Boolean is_high_risk; @@ - public Boolean isIs_high_risk() { - return is_high_risk; - } + public Boolean isIs_high_risk() { + return is_high_risk; + } @@ - public void setIs_high_risk(boolean is_high_risk) { - this.is_high_risk = is_high_risk; - } + public void setIs_high_risk(Boolean is_high_risk) { + this.is_high_risk = is_high_risk; + }Optional: add a canonical getter to reduce “isIs_” awkwardness without breaking callers:
public Boolean getIs_high_risk() { return is_high_risk; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
pom.xml
(2 hunks)src/main/java/com/iemr/hwc/controller/wo/LocationControllerWo.java
(1 hunks)src/main/java/com/iemr/hwc/data/benFlowStatus/BeneficiaryFlowStatus.java
(2 hunks)src/main/java/com/iemr/hwc/data/labModule/ProcedureComponentMapping.java
(1 hunks)src/main/java/com/iemr/hwc/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java
(1 hunks)src/main/java/com/iemr/hwc/service/choApp/CHOAppSyncServiceImpl.java
(2 hunks)src/main/java/com/iemr/hwc/service/common/transaction/CommonNurseServiceImpl.java
(1 hunks)src/main/java/com/iemr/hwc/service/ncdscreening/NCDScreeningServiceImpl.java
(1 hunks)src/main/java/com/iemr/hwc/utils/Constants.java
(1 hunks)src/main/java/com/iemr/hwc/utils/JwtUserIdValidationFilter.java
(3 hunks)src/main/java/com/iemr/hwc/utils/RestTemplateUtil.java
(1 hunks)src/main/java/com/iemr/hwc/utils/http/HTTPRequestInterceptor.java
(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-17T14:52:46.902Z
Learnt from: vishwab1
PR: PSMRI/HWC-API#138
File: src/main/java/com/iemr/hwc/utils/JwtUserIdValidationFilter.java:39-57
Timestamp: 2025-06-17T14:52:46.902Z
Learning: In the PSMRI/HWC-API codebase, the team prefers to keep CORS header logic in the JwtUserIdValidationFilter even when CorsConfig is also present, despite potential header duplication. This is an intentional architectural decision.
Applied to files:
src/main/java/com/iemr/hwc/utils/JwtUserIdValidationFilter.java
🧬 Code graph analysis (2)
src/main/java/com/iemr/hwc/utils/RestTemplateUtil.java (1)
src/main/java/com/iemr/hwc/utils/Constants.java (1)
Constants
(3-9)
src/main/java/com/iemr/hwc/utils/JwtUserIdValidationFilter.java (3)
src/main/java/com/iemr/hwc/utils/http/AuthorizationHeaderRequestWrapper.java (1)
AuthorizationHeaderRequestWrapper
(10-42)src/main/java/com/iemr/hwc/utils/Constants.java (1)
Constants
(3-9)src/main/java/com/iemr/hwc/utils/UserAgentContext.java (1)
UserAgentContext
(3-18)
🔇 Additional comments (3)
src/main/java/com/iemr/hwc/service/choApp/CHOAppSyncServiceImpl.java (2)
621-622
: Tighten error message formattingMinor: add separators to improve readability.
[ suggest_nitpick_refactor ]
Apply this diff:- outputResponse.setError(500, "Unable to fetch Prescription Templates userID" + userID + "Exception - " + e); + outputResponse.setError(500, "Unable to fetch Prescription Templates. userID: " + userID + "; Exception: " + e);- outputResponse.setError(500, "Unable to delete Prescription Templates userID : " + userID + " tempID " - + tempID + "Exception - " + e); + outputResponse.setError(500, "Unable to delete Prescription Template. userID: " + userID + ", tempID: " + + tempID + "; Exception: " + e);Also applies to: 639-641
239-243
: Good: no token leak in response headersYou add AUTHORIZATION to response headers but remove it before returning. This avoids reflecting tokens to clients.
Please run the API manually once to ensure no Authorization headers are present in 2xx/4xx/5xx responses from these endpoints.
Also applies to: 291-293
src/main/java/com/iemr/hwc/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java (1)
461-462
: Return latest is_high_risk (order by visit sequence) and coerce DB boolean
- ORDER BY 1 DESC sorts by the boolean value (TRUE > FALSE) — it returns TRUE if any historic visit was TRUE, not the most recent visit.
- Native boolean mappings vary by DB; coerce with CASE to guarantee a Java Boolean.
- Repo search found only this query (src/main/java/com/iemr/hwc/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java:461-462) and no timestamp/PK to choose from — confirm which column to order by. Prefer an incremental visit id (ben_visit_id/BenVisitID) to reflect visit sequence; fallback to created_date DESC if no visit id exists.
Suggested replacement (adjust column name to your schema):
@Query(value = "SELECT CASE WHEN t.is_high_risk = 1 THEN TRUE ELSE FALSE END " + "FROM t_anc_visit t " + "WHERE t.ben_id = :ben_id " + "ORDER BY t.ben_visit_id DESC " + -- or ORDER BY t.created_date DESC "LIMIT 1", nativeQuery = true) Boolean getIsHighrisk(@Param("ben_id") Long ben_id);
<groupId>com.iemr.hwc</groupId> | ||
<artifactId>hwc-api</artifactId> | ||
<version>3.1.0</version> | ||
<version>3.4.0</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Version bump OK; verify repo references and release notes.
Looks good. Please ensure any hard-coded references to 3.1.0 are cleaned up and changelog/release notes are updated.
Run to spot stragglers:
🏁 Script executed:
#!/bin/bash
rg -nP '(hwc-api-)?3\.1\.0' -S
Length of output: 1511
Fix remaining 3.1.0 references before merge
- pom.xml — lines 148 and 371 contain 3.1.0.
- package-lock.json — multiple 3.1.0 occurrences (e.g. lines 469–470, 1079–1080, 1570–1571, 1630–1631, 2381–2382, 2426–2427); regenerate or update the lockfile if the version bump should apply to dependencies.
- Update changelog/release notes to reflect 3.4.0.
for (BeneficiaryFlowStatus beneficiaryFlowStatus : obj) { | ||
Boolean isHighrisk = beneficiaryFlowStatusRepo.getIsHighrisk(beneficiaryFlowStatus.getBeneficiaryID()); | ||
if(null != isHighrisk) | ||
beneficiaryFlowStatus.setIs_high_risk(isHighrisk); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid N+1 lookups and null argument to repo
- Calling getIsHighrisk per row is N+1 and may be slow.
- If beneficiaryID is null, the repo call will throw for null param.
Apply this minimal safety fix now:
- for (BeneficiaryFlowStatus beneficiaryFlowStatus : obj) {
- Boolean isHighrisk = beneficiaryFlowStatusRepo.getIsHighrisk(beneficiaryFlowStatus.getBeneficiaryID());
- if(null != isHighrisk)
- beneficiaryFlowStatus.setIs_high_risk(isHighrisk);
- }
+ for (BeneficiaryFlowStatus bfs : obj) {
+ Long benId = bfs.getBeneficiaryID();
+ if (benId == null) {
+ continue;
+ }
+ Boolean isHighrisk = beneficiaryFlowStatusRepo.getIsHighrisk(benId);
+ if (isHighrisk != null) {
+ bfs.setIs_high_risk(isHighrisk);
+ }
+ }
Then, consider batching for performance:
- Collect unique benIds from obj.
- Add a repo method returning Map<Long, Boolean> of latest flags for those IDs.
- Populate bfs.setIs_high_risk(...) from that map.
I can sketch the repo query if you confirm available columns on t_anc_visit.
📝 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.
for (BeneficiaryFlowStatus beneficiaryFlowStatus : obj) { | |
Boolean isHighrisk = beneficiaryFlowStatusRepo.getIsHighrisk(beneficiaryFlowStatus.getBeneficiaryID()); | |
if(null != isHighrisk) | |
beneficiaryFlowStatus.setIs_high_risk(isHighrisk); | |
} | |
for (BeneficiaryFlowStatus bfs : obj) { | |
Long benId = bfs.getBeneficiaryID(); | |
if (benId == null) { | |
continue; | |
} | |
Boolean isHighrisk = beneficiaryFlowStatusRepo.getIsHighrisk(benId); | |
if (isHighrisk != null) { | |
bfs.setIs_high_risk(isHighrisk); | |
} | |
} |
🤖 Prompt for AI Agents
In
src/main/java/com/iemr/hwc/service/common/transaction/CommonNurseServiceImpl.java
around lines 3548-3552, the loop calls beneficiaryFlowStatusRepo.getIsHighrisk
for each beneficiary (N+1) and will throw if beneficiaryID is null; as a minimal
safety fix, check beneficiaryFlowStatus.getBeneficiaryID() for null before
invoking the repo and skip the repo call (or set is_high_risk to a safe default)
when null, then set the result on the object only when non-null; afterwards
implement a batched approach: collect unique non-null beneficiary IDs, add a
repo method that returns a Map<Long,Boolean> of flags for those IDs, and
populate each BeneficiaryFlowStatus from that map to avoid N+1 queries.
map.put("beneficiaryRegId", obj[0] != null ? ((Long) obj[0]) : null); | ||
if (obj[1] != null && (Boolean) obj[1] == true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Robust casting to avoid ClassCastException across drivers.
(Long) obj[0]
will fail if the JPA provider returns BigInteger
/Integer
. Use Number.longValue()
instead.
- map.put("beneficiaryRegId", obj[0] != null ? ((Long) obj[0]) : null);
+ map.put("beneficiaryRegId", obj[0] != null ? ((Number) obj[0]).longValue() : null);
📝 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.
map.put("beneficiaryRegId", obj[0] != null ? ((Long) obj[0]) : null); | |
if (obj[1] != null && (Boolean) obj[1] == true) | |
map.put("beneficiaryRegId", obj[0] != null ? ((Number) obj[0]).longValue() : null); | |
if (obj[1] != null && (Boolean) obj[1] == true) |
🤖 Prompt for AI Agents
In src/main/java/com/iemr/hwc/service/ncdscreening/NCDScreeningServiceImpl.java
around lines 1700-1701, the code casts obj[0] directly to Long which can throw
ClassCastException if the JPA provider returns Integer/BigInteger; replace the
direct cast with a safe Number-based conversion: check for null, ensure obj[0]
is an instance of Number, then call ((Number) obj[0]).longValue() and put that
Long (or null) into the map; keep the existing boolean handling for obj[1]
as-is.
try { | ||
String jwtFromCookie = getJwtTokenFromCookies(request); | ||
String jwtFromHeader = request.getHeader("JwtToken"); | ||
String authHeader = request.getHeader("Authorization"); | ||
|
||
if (jwtFromCookie != null) { | ||
logger.info("Validating JWT token from cookie"); | ||
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromCookie)) { | ||
filterChain.doFilter(servletRequest, servletResponse); | ||
return; | ||
} | ||
} | ||
|
||
if (jwtFromHeader != null) { | ||
logger.info("Validating JWT token from header"); | ||
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) { | ||
filterChain.doFilter(servletRequest, servletResponse); | ||
return; | ||
} | ||
} | ||
String userAgent = request.getHeader("User-Agent"); | ||
logger.info("User-Agent: " + userAgent); | ||
|
||
if (userAgent != null && isMobileClient(userAgent) && authHeader != null) { | ||
filterChain.doFilter(servletRequest, servletResponse); | ||
return; | ||
} | ||
|
||
logger.warn("No valid authentication token found"); | ||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Invalid or missing token"); | ||
|
||
String jwtToken = getJwtTokenFromCookies(request); | ||
String jwtFromHeader = request.getHeader(Constants.JWT_TOKEN); | ||
String authHeader = request.getHeader("Authorization"); | ||
|
||
if ((jwtToken != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken)) || | ||
(jwtFromHeader != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader))) { | ||
AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(request, ""); | ||
filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse); | ||
return; | ||
} else { | ||
String userAgent = request.getHeader(Constants.USER_AGENT); | ||
logger.info("User-Agent: " + userAgent); | ||
if (userAgent != null && isMobileClient(userAgent) && authHeader != null) { | ||
try { | ||
UserAgentContext.setUserAgent(userAgent); | ||
filterChain.doFilter(servletRequest, servletResponse); | ||
} finally { | ||
UserAgentContext.clear(); | ||
} | ||
return; | ||
} | ||
} | ||
logger.warn("No valid authentication token found"); | ||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Invalid or missing token"); | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Verification inconclusive
Do not blank out the Authorization header after validation; propagate a proper Bearer value.
Wrapping the request with an empty Authorization breaks downstream components that rely on it. Propagate the validated token as “Bearer ”.
- String jwtToken = getJwtTokenFromCookies(request);
- String jwtFromHeader = request.getHeader(Constants.JWT_TOKEN);
- String authHeader = request.getHeader("Authorization");
-
- if ((jwtToken != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken)) ||
- (jwtFromHeader != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader))) {
- AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(request, "");
- filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
- return;
- } else {
+ String jwtFromCookie = getJwtTokenFromCookies(request);
+ String jwtFromHeader = request.getHeader(Constants.JWT_TOKEN);
+ String authHeader = request.getHeader("Authorization");
+ String effectiveToken = jwtFromHeader != null ? jwtFromHeader : jwtFromCookie;
+
+ if (effectiveToken != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(effectiveToken)) {
+ // Propagate Authorization for downstream usage
+ AuthorizationHeaderRequestWrapper wrapped =
+ new AuthorizationHeaderRequestWrapper(request, "Bearer " + effectiveToken);
+ filterChain.doFilter(wrapped, servletResponse);
+ return;
+ } else {
String userAgent = request.getHeader(Constants.USER_AGENT);
logger.info("User-Agent: " + userAgent);
- if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
+ if (userAgent != null && isMobileClient(userAgent) && authHeader != null && !authHeader.isEmpty()) {
try {
UserAgentContext.setUserAgent(userAgent);
filterChain.doFilter(servletRequest, servletResponse);
} finally {
UserAgentContext.clear();
}
return;
}
- }
+ }
Follow-up: confirm the “mobile bypass” path (okhttp + any Authorization) is intentional; otherwise validate authHeader
too.
Propagate Authorization header (don’t blank it)
Wrapping the request with an empty Authorization header breaks downstream consumers — set the header to "Bearer " when a JWT is validated instead of "".
- Change to use an effectiveToken (jwtFromHeader ?: jwtFromCookie) and pass AuthorizationHeaderRequestWrapper(request, "Bearer " + effectiveToken) after validation.
- Tighten the mobile-bypass: require authHeader != null && !authHeader.isEmpty(), or confirm the okhttp/mobile bypass accepting any Authorization is intentional.
Location: src/main/java/com/iemr/hwc/utils/JwtUserIdValidationFilter.java (around lines 91–116).
📋 Description
JIRA ID: MHWC -120
fix sync issue due to ClassCastException Boolean cannot be cast to class String.
✅ Type of Change
ℹ️ Additional Information
Please describe how the changes were tested, and include any relevant screenshots, logs, or other information that provides additional context.
Summary by CodeRabbit