-
Notifications
You must be signed in to change notification settings - Fork 53
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
Workaround bug in android 4 for JSON objects with List<String> #942
Workaround bug in android 4 for JSON objects with List<String> #942
Conversation
Codecov Report
@@ Coverage Diff @@
## main #942 +/- ##
==========================================
- Coverage 85.07% 84.45% -0.63%
==========================================
Files 165 160 -5
Lines 5824 5520 -304
Branches 801 774 -27
==========================================
- Hits 4955 4662 -293
- Misses 550 561 +11
+ Partials 319 297 -22
... and 25 files with indirect coverage changes Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
Btw, I found the similar issue we had in the past #144 |
@@ -239,6 +240,16 @@ class HTTPClient( | |||
private fun Map<String, Any?>.convert(): JSONObject { | |||
val mapWithoutInnerMaps = mapValues { (_, value) -> | |||
value.tryCast<Map<String, Any?>>(ifSuccess = { convert() }) |
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.
This would need to be removed I think?
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.
could you clarify? this was added to fix a separate but similar issue (the one that César posted, #144)
@@ -239,6 +240,16 @@ class HTTPClient( | |||
private fun Map<String, Any?>.convert(): JSONObject { | |||
val mapWithoutInnerMaps = mapValues { (_, value) -> | |||
value.tryCast<Map<String, Any?>>(ifSuccess = { convert() }) | |||
when (value) { | |||
is List<*> -> { |
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.
We should add a comment explaining this.
2a95f56
to
dd17b2b
Compare
@@ -236,30 +239,6 @@ class HTTPClient( | |||
.filterNotNullValues() | |||
} | |||
|
|||
private fun Map<String, Any?>.convert(): JSONObject { |
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.
moved to its own class to make testing easier and more focused
return JSONObject(inputMap) | ||
} | ||
|
||
/** To avoid Java type erasure, we use a Kotlin inline function with a reified parameter |
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.
this bit was moved from HTTPClient
if (inputMap == null) { | ||
return JSONObject() | ||
} |
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.
todo: make sure that this matches the previous behavior exactly.
val jsonBody = body?.convert() | ||
val jsonBody = body?.let { mapConverter.convertToJSON(body) } |
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.
just double-checking, android folks: this should be equivalent, right?
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.
I would do
val jsonBody = body?.let { mapConverter.convertToJSON(it) }
But yes. The difference is that with it
, you are not using smart casting from kotlin. But it's the same.
@@ -239,6 +240,16 @@ class HTTPClient( | |||
private fun Map<String, Any?>.convert(): JSONObject { | |||
val mapWithoutInnerMaps = mapValues { (_, value) -> | |||
value.tryCast<Map<String, Any?>>(ifSuccess = { convert() }) |
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.
could you clarify? this was added to fix a separate but similar issue (the one that César posted, #144)
I won't merge until I've managed to reproduce with an instrumented test, but it should be ready to review in the meantime. |
* (i.e.: "[\"value1\", \"value2\"]" instead of "[value1, value2]") | ||
*/ | ||
@Test | ||
fun `test map conversion fixes wrong treatment of arrays of strings in JSON library`() { |
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.
the old code fails this test
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.
LGTM!
*/ | ||
internal fun convertToJSON(inputMap: Map<String, Any?>): JSONObject { | ||
val mapWithoutInnerMaps = inputMap.mapValues { (_, value) -> | ||
value.tryCast<Map<String, Any?>>(ifSuccess = { convertToJSON(this) }) |
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.
Unless I'm reading this wrong, this line doesn't do anything. It will convert to JSON but we are ignoring the return value I think? We moved this line to the else
inside the when
, so I think this line can be removed if I'm not wrong.
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.
yes, I was thinking the same
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.
oops, leftover from refactor, thanks
.put("key1", "value1") | ||
.put("key2", JSONArray(listOf("value2", "value3"))) | ||
.put("key3", JSONObject().put("nestedKey", "nestedValue")) | ||
.put("key4", JSONArray(listOf("value4", "value5"))) |
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.
Hmm should this be a JSONObject with a JSONArray
value?
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.
ohh oops this isn't nested 😅 Great catch!
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.
updated, lmk what you think!
*/ | ||
@Test | ||
fun `test map conversion fixes wrong treatment of arrays of strings in JSON library`() { | ||
val mapConverterMock = spyk<MapConverter>() |
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.
Maybe rename to mapConverterSpy
? Since it's not technically a mock
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.
ohh spyk nice, I've never used this
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.
I'm not technically using it as a spy either, more like a partial mock, since I do modify the return value for some circumstances. Perhaps renaming it to that would be clearer?
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.
trying it this way, let me know what you think
*/ | ||
@Test | ||
fun `test map conversion fixes wrong treatment of arrays of strings in JSON library`() { | ||
val mapConverterMock = spyk<MapConverter>() |
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.
ohh spyk nice, I've never used this
*/ | ||
internal fun convertToJSON(inputMap: Map<String, Any?>): JSONObject { | ||
val mapWithoutInnerMaps = inputMap.mapValues { (_, value) -> | ||
value.tryCast<Map<String, Any?>>(ifSuccess = { convertToJSON(this) }) |
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.
yes, I was thinking the same
val jsonBody = body?.convert() | ||
val jsonBody = body?.let { mapConverter.convertToJSON(body) } |
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.
I would do
val jsonBody = body?.let { mapConverter.convertToJSON(it) }
But yes. The difference is that with it
, you are not using smart casting from kotlin. But it's the same.
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.
LGTM!
Ah linter failed. |
…s in a map would get treated as a single string instead of a JSONArray
57b8d2f
to
c2a7709
Compare
We might wanna separate that linter step so it's clearer that it's not a test failure but rather linting, very different priorities there. |
@vegaro awesome thanks!! 🙌🙌🙌 |
Is this ready to be merged? |
oops forgot about this, yeah, it's ready to go |
**This is an automatic release.** ### New Features * Support DEFERRED mode (#985) via swehner (@swehner) * Add completion callback to syncPurchases API (#1002) via Toni Rico (@tonidero) ### Bugfixes * Workaround bug in android 4 for JSON objects with List<String> (#942) via Andy Boedo (@aboedo) ### Dependency Updates * Bump fastlane-plugin-revenuecat_internal from `fe45299` to `13773d2` (#1015) via dependabot[bot] (@dependabot[bot]) ### Other Changes * Bump dokka to 1.8.10 to support Gradle 8 (#1009) via Toni Rico (@tonidero) * Disable offline entitlements temporarily (#1023) via Toni Rico (@tonidero) * Fix integration tests in CI (#1019) via Toni Rico (@tonidero) * Add offline entitlements integration tests (#1006) via Toni Rico (@tonidero) * Disable offline entitlements in observer mode (#1014) via Toni Rico (@tonidero) * Extracts setup and teardown to BasePurchasesTest (#1011) via Cesar de la Vega (@vegaro) * Support forcing server errors for tests (#1008) via Toni Rico (@tonidero) --------- Co-authored-by: revenuecat-ops <ops@revenuecat.com> Co-authored-by: Toni Rico <antonio.rico.diez@revenuecat.com>
Fixes https://linear.app/revenuecat/issue/SDK-3052/400-from-post-receipts-because-product-did-not-have-quotes
https://revenuecats.atlassian.net/browse/CSDK-681
Works around the following bug in android 4:
https://stackoverflow.com/q/37317669
http://fupeg.blogspot.com/2011/07/android-json-bug.html
Essentially, this bug means that when you get a list of product_ids, instead of sending a list of strings, it sends a list with a string in it.