Using JSONObject in Kotlin always throws an error - android

I know that this question is asked hundreds of time, I've checked more than 30 answer and none worked for me.
I'm running a unit test in android studio using Kotlin. I'm trying to build a JSONObject using a String.
The method I'm using to build a simple json object is always throwing Cannot evaluate org.json.JSONObject.toString().
The string I'm using definitely have a valid Json format.
Is this a bug in android or what??
Here's the method I'm using:
fun createTaskJson(): JSONObject {
val jsonString =
"{\"id\":138,\"title\":\"G0102-025\",\"type\":\"New Land Evaluation\",\"taskCreationDate\":\"28/01/2020\",\"taskDeliveryDate\":\"02/02/2020\",\"taskCreationTime\":\"05:15 AM\"}"
val realJson = JSONObject(jsonString)
return realJson
}
UPDATE 1:
Please note that also creating an empty JSONObject will throw the same error !!
UPDATE 2:
After checking the stacktrace, I've found the following error:
Method toString in org.json.JSONObject not mocked.
I've googled it and the solution was to add the following configuration into my build.gradle file:
testOptions {
unitTests.returnDefaultValues = true
}
But adding this made the returned JSONObject null instead of throwing an exception, even though my string is formatted correctly.

After the updates mentioned in the question above. And after lots of searching. I found out the following:
The solution was in adding the following line into build.gradle file:
implementation group: 'org.json', name: 'json', version: '20190722'
I don't know why, but it's like android have an object with names JSONArray and JSONObject but when adding the implementation to the build.gradlefile. It handles JSONObject and JSONArray in another way.
Because after adding the statement to the gradle file, the following warning will be giving by android:
json define classes that conflict with classes now provided by Android

Related

Cannot set the value of read-only property 'group' for DefaultExternalModuleDependency

I am solving duplicate issue due build process caused by a new library. There are some duplicate classes or a whole package of bouncycastle. The issue is the default way to exclude a class or a whole group brings this issue:
Caused by: groovy.lang.GroovyRuntimeException: Cannot set the value of read-only property 'group' for DefaultExternalModuleDependency{group='org.web3j', name='core', version='4.8.7-android', configuration='default'} of type org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
Code itself:
implementation('org.web3j:core:4.8.7-android') {
exclude(group = 'org.bouncycastle')
}
Is there some changes in exclude usage over the past few years?
It's just a syntax issue, the exclude method expects a Map parameter. it looks like you are using the Groovy DSL, and in Groovy maps are created using : character ( in Kotlin DSL you would use = as you did)
So just replace = assignement by : as follows:
implementation('org.web3j:core:4.8.7-android') {
exclude(group : 'org.bouncycastle')
}
See some examples here https://docs.gradle.org/current/userguide/dependency_downgrade_and_exclude.html#sec:excluding-transitive-deps

how to throw an HttpException in Kotlin - retrofit 2 - unit test

I am writing a unit test and I want to throw an HttpException with an error code 409.
This is what I tried but it gives me an error
Using 'parse(String): MediaType?' is an error. moved to extension function
This is a kotlin file and Retrofit 2.6.0, and ResponseBody is okhttp3 - 3.12.12
What I have tried
every(call.execute()).thenThrow(HttpException(
Response.error<Any>(409, ResponseBody.create(
MediaType.parse("plain/text"), ""
))
))
how can i solve this please
thanks
R
For Kotlin:
currently ResponseBody.create methods are deprecated (at least in OkHttp3 ver. 4.9.1). Following extension method can be used:
"raw response body as string".toResponseBody("plain/text".toMediaTypeOrNull())
i just throw this:
throw HttpException(Response.error<ResponseBody>(500 ,ResponseBody.create(MediaType.parse("plain/text"),"some content")))
I've encountered this before. At some point, some dependencies of OkHttp3 changed, and the resulting error message isn't super helpful. What I believe you are looking for is the new .toMediaType() Kotlin extension function. So instead of:
ResponseBody.create(MediaType.parse("plain/text"), "")
Please try:
ResponseBody.create("plain/text".toMediaType(), "")
You'll likely need to import this extension. If your IDE doesn't automatically suggest it, please try importing via import okhttp3.MediaType.Companion.toMediaType.

Error with using json classes from within kotlin REPL and scratch files

I'm working on an Android project that needs to process json data retrieved from a web API. From within the project I successfully used the classes JSONObject and JSONArray (package org.json) without any problems.
Always running compiling, running and navigating the app each time I want to try some json processing is annoying, so I decided to give scratch files a try.
My scratch file looks like this:
import org.json.JSONObject
val jsonObject = JSONObject(
"""
{
"data": [
...
]
}
"""
)
println(jsonObject["data"])
When I try to run the file, I get an error stating that the import wasn't successful:
error: unresolved reference: json (scratch.kts:1:12)
error: unresolved reference: JSONObject (scratch.kts:3:18)
scratch.kts:1:12: error: unresolved reference: json
import org.json.JSONObject
^
scratch.kts:3:18: error: unresolved reference: JSONObject
val jsonObject = JSONObject(
^
Process finished with exit code 1
From my understanding this is because the org.json classes are now part of Android, and the Android framework isn't available from a scratch file. But how can I solve this? Shouldn't I be able to import the org.json package apart from the Android framework somehow?
In order to use import android.* in your scratch file, you have to connect to the classpath of your Android-module (see example-screenshot below). Anyhow, this comes with the drawback that you have to have a runnable project.

How to convert `project.android` Groovy syntax to Kotlin within a Gradle plugin

I have a gradle plugin written in Groovy and want to convert it to Kotlin.
In the plugin class I have a function:
private static getAndroidVariants(Project project) {
(project.android.hasProperty("libraryVariants") ? project.android.libraryVariants : project.android.applicationVariants)
}
which returns the build variants of an android application/library.
How would I convert project.android to Kotlin syntax?
project.extensions.getByName("android") as LibraryExtension).libraryVariants
always returns an empty array from Kotlin but actually a filled list from groovy.
Problem solved.
I used the wrong iterator on the returned value when moving to Kotlin.
Instead of foreach, one needs to use all for those type of containers.

PackageNameSuffix breaks test - Robolectric

When I add a packageNameSuffix to my build.gradle debug build type (see https://plus.google.com/108967384991768947849/posts/XGXH3arvbrK), all of my Robolectric tests are failing due to the following:
Caused by: android.content.res.Resources$NotFoundException: Unable to find resource ID #0x7f050000
at org.robolectric.shadows.ShadowResources.getResName(ShadowResources.java:354)
at org.robolectric.shadows.ShadowResources.openRawResource(ShadowResources.java:387)
at android.content.res.Resources.openRawResource(Resources.java)
at com.myapp.utilities.CSVUtility.parseRawResourceCSV(CSVUtility.java:38)
The problem seems to be that the raw folder src/main/res/main no longer being found. This folder contains a csv which is parsed at application start... which is where the tests go boom.
Architecture/data restructuring suggestions aside (I know CSV may not be the best way to get this data loaded at app start), does anyone know how I might remedy this problem?
Edit: I tried moving the file to the assets folder instead, and then my tests failed on a Context.getString() call. Resources look to be getting completely hosed when adding packageNameSuffixes.
Edit: tmurakami posted on the github issue - https://github.com/robolectric/robolectric/issues/1001#issuecomment-42740897
I've copied the full response:
Try using this gradle snippet.
This works fine in my environment.
def hasLibraryVariants = android.hasProperty('libraryVariants')
def variants = hasLibraryVariants ? android.libraryVariants : android.applicationVariants
tasks.withType(Test).whenTaskAdded {
it.systemProperty 'android.package', variants.iterator().next().processResources.packageForR
}
The original package name has been stored in the following fields of any variant:
variantData.variantConfiguration.originalPackageName
processResources.packageForR
generateBuildConfig.buildConfigPackageName
However these are internal only, so might become inaccessible in the future.
If you don't want to use these fields, try the following snippet:
tasks.withType(Test).whenTaskAdded {
it.systemProperty 'android.package', android.defaultConfig.packageName
}
To use this, you need to add the main package name in the 'android.defaultConfig' section.
android {
defaultConfig {
packageName 'main.package.name'
}
}
Looks like I need to add an android.package system property for the package name. See this issue conversation on Github - https://github.com/robolectric/robolectric/issues/1001

Categories

Resources