fix: update the SSE message parsing to not cause number exception#289
fix: update the SSE message parsing to not cause number exception#289
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the Android SDK’s Server-Sent Events (SSE) message parsing to prevent runtime number/parsing exceptions when handling realtime update messages, improving robustness of the realtime-config refresh path.
Changes:
- Extracted SSE message parsing into a dedicated
handleSSEMessagefunction and addedJSONExceptionhandling. - Made parsing tolerant to different SSE payload shapes (outer envelope with
"data"vs direct inner payload) and to mixed field types. - Updated
initEventSourceto use the new handler reference.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private fun handleSSEMessage(messageEvent: MessageEvent?) { | ||
| if (messageEvent == null) return | ||
|
|
||
| try { | ||
| val data = JSONObject(messageEvent.data) |
There was a problem hiding this comment.
Add unit tests for the new SSE parsing behavior (envelope with "data" as JSON string vs object vs missing "data", and malformed JSON) to ensure we don't regress back to runtime parsing exceptions and that "type":"refetchConfig" still triggers refetchConfig with lastModified/etag.
There was a problem hiding this comment.
see if u can add a test for this
| } catch (e: JSONException) { | ||
| DevCycleLogger.w(e, "SSE Message: Error parsing SSE message data: ${messageEvent.data}") | ||
| } |
There was a problem hiding this comment.
Avoid logging the full raw SSE payload on JSONException. messageEvent.data may be large and can include config values; logging it can leak sensitive data and create noisy logs. Consider logging only the exception plus a truncated payload, payload length, or an event id/type extracted safely via opt* calls.
| val lastModified = if (innerData.has("lastModified")) { | ||
| (innerData.get("lastModified") as Long) | ||
| innerData.optLong("lastModified", 0L).takeIf { it > 0 } | ||
| } else null | ||
|
|
||
| val type = if (innerData.has("type")) { | ||
| (innerData.get("type") as String).toLong() | ||
| innerData.optString("type", "") | ||
| } else "" |
There was a problem hiding this comment.
The has(...) checks around optLong/optString are redundant (opt* already handles missing keys/defaults). Simplifying this parsing logic would reduce branching and make future SSE changes easier to maintain.
fix to combat the SSE read error when parsing the message