Converting an JSON string to Gson object - android

I have an JSONObject which is creating in the following way.
For a special reason, I have to convert it to Gson in this way, as i can modify only extractDataToString() method. But I do not get proper value after conversion.
fun createJsonString() {
val headerJson = JSONObject()
headerJson.put("typ1", "value1")
headerJson.put("typ2", "value2")
extractData(headerJson.toString())
}
fun extractDataToString(jsonString: String) {
val headerJson = Gson().fromJson(jsonString, JsonObject::class.java)
val resultType1 = headerJson.remove("typ1")?.toString() // Here, resultType1 becomes
"value1", but it should be
value1 that is extra qutomation
mark is being added.
}
Why extra quotation mark is being added? Can anyone please help? I am a newbie.

Call
.getAsString()
Instead of
toString()
at the end
ref : docs

Related

How to parse a JSON response with retrofit

So, I have given an API that returns this on a POST call
{
"JHK":"One piece",
"LKJ":"Two pieces",
"OEN":"Three pieces"
}
And since this is a list but is not good formated from the backend I dont know how to get it from Android, this is what I have tried
WebService
#POST("get_user_codes.php")
suspend fun getUserCodesByMemberId(#Body member_id:String): CodesResponse
CodesResponse
data class CodesResponse(val data: List<Code>)
data class Code(val code_id:String,val name:String)
Repository
suspend fun getUserCodes(memberId:String):Result<CodesResponse>{
return Result.Success(webService.getUserCodesByMemberId(memberId))
}
But his is outping Null as the response, I really dont know how to bring those different objects that are supposed to be an array of object but instead they are all inside one object
Any idea ?
API INPUTS
member_id as text string
Example of input:
{ "member_id": "1"}
API OUTPUTS
code_id: as a String
name: as a String
{
"JHK":"One piece",
"LKJ":"Two pieces",
"OEN":"Three pieces"
}
EDIT
the values can be more than those 3 I posted, it depends on how many the response returns
suppose you have response like that
String json = {
"JHK":"One piece",
"LKJ":"Two pieces",
"OEN":"Three pieces"
}
then you can get a list of values ignoring keys like:
ArrayList<String> arr = new ArrayList<>();
try {
JSONObject response = new JSONObject(json);
Iterator keys = response.keys();
while (keys.hasNext()) {
// loop to get the dynamic key
String currentKey = (String) keys.next();
// get the value of the dynamic key
String value = response.getJSONObject(currentKey).toString();
arr.add(value);
}
} catch (Throwable t) {
Log.e("My App", "Could not parse malformed JSON: \"" + json + "\"");
}
Are field names JHK LKJ OEN always the same? You said there can be more than 3, what will be the other name when it's more than 3?
AbdelraZek posted a great solution to this problem: https://stackoverflow.com/a/64246981/14259754
My version of it in Kotlin with Retrofit in mind:
Retrofit:
// Here we use ScalarsConverter to be able to return String as a response.
Retrofit.Builder()
.baseUrl("http://YourURL")
.addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(YourInterfaceClass::class.java)
// Then you can proceed to your POST function
suspend fun getUserCodesByMemberId(#Body member_id:String): String
// I suggest using Response<String> so you can check the response code and process it if needed.
Then, wherever you need, just do the following:
val response = getUserCodesByMemberId
val json = JSONObject(response.body()!!)
val array = mutableListOf<String>()
val keys: Iterator<String> = json.keys()
while (keys.hasNext()) {
val key = keys.next()
array.add(json[key].toString())
}
This way you can work with Json response that is unknown to you.
It will return null because the JSON inside has different keys("JHK", "LKJ" etc).
As Retrofit uses GSON, you need to create a variable with the same name as JSON keys. You will have to use JSONObject and parse the response.
Instead of using
#POST("get_user_codes.php")
suspend fun getUserCodesByMemberId(#Body member_id:String): CodesResponse
use
#POST("get_user_codes.php")
suspend fun getUserCodesByMemberId(#Body member_id:String): JSONObject

How to parse a JSON string into a JSONObject in Kotlin?

I'm really new in programming, and recently started a project in Kotlin with Android Studio.
So, I have a problem with a JSON object. I get data from an BroadcastReceiver object, a String to be more specific, with the next format:
{"s1":1}
This, is a simple string. So I took in a function call toJson and I do this.
private fun toJson(data:String): JSONObject {
var newData: String = data.replace("\"","")
newData = newData.replace("{","")
newData = newData.replace("}","")
val newObject = newData.split(":")
val name = newObject[0]
val value = newObject[1]
val rootObject = JSONObject()
rootObject.put(name,value)
return rootObject
}
Im doing this the right way?, how can I improve my code?
Thanks for your help, and sorry for my english!
Welcome to StackOverflow!
In 2019 no-one is really parsing JSON manually. It's much easier to use Gson library. It takes as an input your object and spits out JSON string and vice-versa.
Example:
data class MyClass(#SerializedName("s1") val s1: Int)
val myClass: MyClass = Gson().fromJson(data, MyClass::class.java)
val outputJson: String = Gson().toJson(myClass)
This way you're not working with JSON string directly but rather with Kotlin object which is type-safe and more convenient.
Look at the docs. It's pretty big and easy to understand
Here is some tutorials:
https://www.youtube.com/watch?v=f-kcvxYZrB4
http://www.studytrails.com/java/json/java-google-json-introduction/
https://www.tutorialspoint.com/gson/index.htm
UPDATE: If you really want to use JSONObject then use its constructor with a string parameter which parses your JSON string automatically.
val jsonObject = JSONObject(data)
Best way is using kotlinx.serialization. turn a Kotlin object into its JSON representation and back marking its class with the #Serializable annotation, and using the provided encodeToString and decodeFromString<T> extension functions on the Json object:
import kotlinx.serialization.*
import kotlinx.serialization.json.*
​
#Serializable
data class User(val name: String, val yearOfBirth: Int)
​
// Serialization (Kotlin object to JSON string)
​
val data = User("Louis", 1901)
val string = Json.encodeToString(data)
println(string) // {"name":"Louis","yearOfBirth":1901}
​
// Deserialization (JSON string to Kotlin object)
​
val obj = Json.decodeFromString<User>(string)
println(obj) // User(name=Louis, yearOfBirth=1901)
Further examples: https://blog.jetbrains.com/kotlin/2020/10/kotlinx-serialization-1-0-released/
I am adding 3 templates here for Kotlin Developers, It will solve json converting & parsing problems.
//Json Array template
{
"json_id": "12.4",
"json_name": "name of the array",
"json_image": "https://image_path",
"json_description": "Description of the Json Array"
}
Kotlin Model class
data class JsonDataParser(
#SerializedName("json_id") val id: Long,
#SerializedName("json_name") val name: String,
#SerializedName("json_image") val image: String,
#SerializedName("json_description") val description: String
)
Converting to Json String from the Model Class
val gson = Gson()
val json = gson.toJson(jsonDataParser)
Parsing from Json file/Strong
val json = getJson()
val topic = gson.fromJson(json, JsonDataParser::class.java)

Converting a HashMap using moshi

I'm trying to convert a HashMap of elements into a JSON string. I'm using the method used in this link.
val elementsNew: HashMap<String, Element> = HashMap(elements)
val type = Types.newParameterizedType(Map::class.java, String::class.java, Element::class.java)
var json: String = builder.adapter(type).toJson(elementsNew)
But this gives the following error
Error:(236, 40) Type inference failed: Not enough information to infer
parameter T in fun adapter(p0: Type!): JsonAdapter!
Please specify it explicitly.
Can any one tell me where's the fault? Is it because of Kotlin?
Looking at the signature of the adapter() method, it can't infer its type parameter from the argument:
public <T> JsonAdapter<T> adapter(Type type)
Hence you have to provide the type explicitly:
var json = builder.adapter<Map<String, Element>>(type).toJson(elementsNew)
or alternatively:
val adapter: JsonAdapter<Map<String, Element>> = builder.adapter(type)
var json = adapter.toJson(elementsNew)

How to parse JSON from an url using Kotlin on Android?

I've been trying to parse JSON from an url for hours now but I'm too stupid I guess
I have tried
val result = URL("http://date.jsontest.com/").readText()
but it crashes
java.net.MalformedURLException: no protocol: date.jsontest.com
I have tried Klaxon's library
fun parse(name: String) : Any? {
val cls = Parser::class.java
return cls.getResourceAsStream(name)?.let {
inputStream -> return Parser().parse(inputStream)
}
}
val obj = parse("http://date.jsontest.com/") as JsonObject
but it also crashes
kotlin.TypeCastException: null cannot be cast to non-null type com.beust.klaxon.JsonObject
Can someone please write in Kotlin the simpliest way to parse data from this link http://date.jsontest.com/
Hard to say why you are getting an error. Since this line is correct and working.
val result = URL("http://date.jsontest.com/").readText()
For the parse method. It does not work, becase it expects path to a JSON file but is getting a URL String.
Simplest example using Klaxon would be this.
val result = URL("http://date.jsontest.com/").readText()
val parser: Parser = Parser()
val stringBuilder: StringBuilder = StringBuilder(result)
val json: JsonObject = parser.parse(stringBuilder) as JsonObject
println("Time : ${json.string("time")}, Since epoch : ${json.long("milliseconds_since_epoch")}, Date : ${json.string("date")}, ")

Use custom JSON serializers with firebase

Is it possible to get JsonObjects or strings in Json format when using DataSnapshot.getValue()? Maybe I wasn't thorough enough with my search, but I couldn't find a way to use a custom serializer.
Update:
I haven't had the time for checking out the documentation for the latest SDK but it seems like there are some options for JSON fields.
The getValue() in DataSnapshot returns a HashMap.
So in any method of your Firebase listener, you could:
Get the value of the DataSnapshot, which will return a HashMap:
HashMap<String, JSONObject> dataSnapshotValue = (HashMap<String, JSONObject>) dataSnapshot.getValue();
Cast the Hashmapto a valid JSON string, using Gson:
String jsonString = new Gson().toJson(dataSnapshotValue);
With this valid jsonString, cast it as needed:
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(User.class, new UserSerializer());
final Gson gson = gsonBuilder.create();
User parsedUser = gson.fromJson(jsonString, User.class);
This gives you the possibility to use anything you want to cast an object from Firebase, you could either use custom serializers, an ExclusionStrategy, or retrieve some values from the HashMap directly.
Based on #RominaV answer and in case it may be helpful to someone that's what I have in Kotlin:
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
adapter.clear()
dataSnapshot.children.forEach {
val cardMap = it.value
val json = Gson().toJson(cardMap)
val card = Gson().fromJson<Card>(json, Card::class.java)
adapter.add(CardItem(card))
}
}
And that's my Card class
data class Card(var courseId: String, var cardQuestion: String, var cardAnswer: String) {
constructor() : this("", "", "")
}
I can also get the same outcome traversing through the dataSnapshot children this way:
dataSnapshot.children.forEach {
adapter.clear()
val courseId = it.child("courseId").value as String
val question = it.child("cardQuestion").value as String
val answer = it.child("cardAnswer").value as String
adapter.add(CardItem(Card(courseId, question, answer))
}
Thanks. :)

Categories

Resources