Json reader Expected data to be object but comes as array
I want to add offline caching to my images app
when I run the app I get this error and the app crashed
2023-01-12 11:51:31.119 5622-5622/com.example.images E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.images, PID: 5622
com.squareup.moshi.JsonDataException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at path $
at com.squareup.moshi.JsonUtf8Reader.beginObject(JsonUtf8Reader.java:172)
at com.example.images.network.NetworkImageContainerJsonAdapter.fromJson(NetworkImageContainerJsonAdapter.kt:36)
at com.example.images.network.NetworkImageContainerJsonAdapter.fromJson(NetworkImageContainerJsonAdapter.kt:22)
at com.squareup.moshi.internal.NullSafeJsonAdapter.fromJson(NullSafeJsonAdapter.java:41)
at retrofit2.converter.moshi.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:46)
at retrofit2.converter.moshi.MoshiResponseBodyConverter.convert(MoshiResponseBodyConverter.java:27)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:153)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}#db9bb9a, Dispatchers.Main.immediate]
trying to get json data to NetworkImageContainer class
json reader
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET
private const val BASE_URL = "https://picsum.photos/"
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.build()
interface ImageApiService {
#GET("v2/list")
suspend fun getImages(): NetworkImageContainer
}
object ImageApiNet {
val retrofitService= retrofit.create(ImageApiService::class.java)
}
json class and NetworkImageContainer class
import com.example.images.database.DatabaseImages
import com.example.images.domain.ImagesModels
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
#JsonClass(generateAdapter = true)
data class NetworkImageContainer(val images:List<NetworkImage>)
#JsonClass(generateAdapter = true)
data class NetworkImage(
val id: String,
val author:String,
#Json(name = "download_url")val download_url: String,
// val width: String,
// val height: String,
// val url: String
)
fun NetworkImageContainer.asDomainModel(): List<ImagesModels> {
return images.map {
ImagesModels(
id = it.id,
author = it.author,
download_url = it.download_url,
// width = it.width,
// height = it.height,
// url = it.url
)
}
}
fun NetworkImageContainer.asDatabaseModel(): List<DatabaseImages>{
return images.map {
DatabaseImages(
id = it.id,
author = it.author,
download_url = it.download_url,
// width = it.width,
// height = it.height,
// url = it.url
)
}
}
this is the API I use https://picsum.photos/
[
{
"id": "0",
"author": "Alejandro Escamilla",
"width": 5616,
"height": 3744,
"url": "https://unsplash.com/...",
"download_url": "https://picsum.photos/..."
}
]
You are basically telling it that your response looks like
{
"images": [{
"id": "0",
"author": "Alejandro Escamilla",
"width": 5616,
"height": 3744,
"url": "https://unsplash.com/...",
"download_url": "https://picsum.photos/..."
}]
}
You just need to get rid of NetworkImageContainer and change
suspend fun getImages(): NetworkImageContainer
to
suspend fun getImages(): List<NetworkImage>
Related
When calling the getUser function, I make an HTTP request that retrieves information about a user.
If the user does not exist I get the error:
io.ktor.client.features.ClientRequestException: Client request(https://api.intra.chocolat.fr/v2/users/fff) invalid: 404 Not Found. Text: "{}"
I am unable to catch the error, and to continue the execution of the program.
package com.ksainthi.swifty.api
import android.util.Log
import androidx.annotation.Keep
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.features.*
import io.ktor.client.features.json.*
import io.ktor.client.features.json.serializer.*
import io.ktor.client.features.observer.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.serialization.*
class Api42Service {
#Keep
#Serializable
data class Token(
#SerialName("access_token") val accessToken: String,
#SerialName("token_type") val tokenType: String,
#SerialName("expires_in") val expiresIn: Int,
#SerialName("scope") val scope: String,
#SerialName("created_at") val createdAt: Int
)
#Keep
#Serializable
data class User(
#SerialName("id") val id: Int,
#SerialName("email") val email: String,
#SerialName("login") val login: String? = null,
#SerialName("first_name") val firstName: String? = null,
#SerialName("last_name") val lastName: String? = null,
)
private var accessToken: String? = null
private var client: HttpClient = HttpClient() {
install(JsonFeature) {
serializer = KotlinxSerializer(kotlinx.serialization.json.Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
}
}
private val API_URL: String = "https://api.intra.chocolat.fr"
private val API_SECRET: String =
"<secret>"
private val API_UID: String =
"<api_uid>"
suspend fun requestAPI(
requestMethod: HttpMethod,
path: String,
params: MutableMap<String, String>?
): HttpResponse {
val urlString = API_URL
.plus(path)
return client.request(urlString) {
method = requestMethod
params?.forEach { (key, value) ->
parameter(key, value)
}
headers {
accessToken?.let {
println(it)
append(HttpHeaders.Authorization, "Bearer $it")
}
}
}
}
suspend fun getToken(): Token {
val params: MutableMap<String, String> = HashMap()
params["grant_type"] = "client_credentials";
params["client_secret"] = API_SECRET;
params["client_id"] = API_UID;
val response = requestAPI(HttpMethod.Post, "/oauth/token", params);
val token: Token = response.receive()
accessToken = token.accessToken
return token
}
suspend fun getUser(login: String): User? {
try {
val response = requestAPI(HttpMethod.Get, "/v2/users/$login", null);
val user: User = response.receive()
return user
} catch (cause: io.ktor.client.features.ClientRequestException) {
Log.d("wtf", "Catch your error here")
}
return null
}
}
I am using Json.decodeFromString<User>("json string") (https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)
model is like
data class User(val id: String, val name: String, val assets: List<Asset>)
data class Asset(val id: String, val sku: String, val name: String)
but input json is like
{
"data": {
"id": "userId",
"name": "userName",
"body": {
"assets": [
{
"data": {
"id": "assetId",
"sku": "assetSku",
"name": "assetName"
}
}
]
}
}
}
How can I parse json with serializer? Seems not able to parse with delegate and surrogate serializers easily.
Your POJO seems to be wrong , every field needs to have name corresponding to json value , or use GSON's SerializedName annotation and Parse sing Gson.
Your User POJO should look something like this,
data class User (
#SerializedName("data") var data : UserData
)
data class UserData(
#SerializedName("id") var id : String,
#SerializedName("name") var name : String,
#SerializedName("body") var body : Body
)
data class Body (
#SerializedName("assets") var assets : List<Assets>
)
data class Assets (
#SerializedName("data") var data : AssetsData
)
data class AssetsData(
#SerializedName("id") var id : String,
#SerializedName("sku") var sku : String,
#SerializedName("name") var name : String
)
for serializing and deserializing
dependencies {
implementation 'com.google.code.gson:gson:2.8.9'
}
val gson = Gson()
val jsonValue = gson.toJson(User)
val jsonToUser = gson.fromJson(jsonValue ,User::class.java)
Read about https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#under-the-hood-experimental
Tried something like this:
#Serializable(with = AssetSerializer::class)
data class Asset(val id: String, val sku: String, val name: String)
#Serializable(with = UserSerializer::class)
data class User(val id: String, val name: String, val assets: List<Asset>)
object AssetSerializer: KSerializer<Asset> {
override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("Asset") {
element("data", buildClassSerialDescriptor("data") {
element("id", String.serializer().descriptor)
element("sku", String.serializer().descriptor)
element("name", String.serializer().descriptor)
})
}
override fun serialize(encoder: Encoder, value: Asset) {
require(encoder is JsonEncoder)
encoder.encodeJsonElement(buildJsonObject {
put("data", buildJsonObject {
put("id", value.id)
put("sku", value.sku)
put("name", value.name)
})
})
}
override fun deserialize(decoder: Decoder): Asset {
require(decoder is JsonDecoder)
val root = decoder.decodeJsonElement()
val element = root.jsonObject["data"]!!
return Asset(
id = element.jsonObject["id"]!!.jsonPrimitive.content,
sku = element.jsonObject["sku"]!!.jsonPrimitive.content,
name = element.jsonObject["name"]!!.jsonPrimitive.content,
)
}
}
object UserSerializer: KSerializer<User> {
override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("User") {
element("data", buildClassSerialDescriptor("data") {
element("id", String.serializer().descriptor)
element("name", String.serializer().descriptor)
element("body", buildClassSerialDescriptor("body") {
element("assets", ListSerializer(Asset.serializer()).descriptor)
})
})
}
override fun serialize(encoder: Encoder, value: User) {
require(encoder is JsonEncoder)
encoder.encodeJsonElement(buildJsonObject {
put("data", buildJsonObject {
put("id", value.id)
put("name", value.name)
put("body", buildJsonObject {
put("assets", JsonArray(value.assets.map { asset ->
encoder.json.encodeToJsonElement(asset)
}))
})
})
})
}
override fun deserialize(decoder: Decoder): User {
require(decoder is JsonDecoder)
val root = decoder.decodeJsonElement()
val element = root.jsonObject["data"]!!
val assets = element
.jsonObject["body"]!!
.jsonObject["assets"]!!
.jsonArray
.map { asset ->
decoder.json.decodeFromJsonElement(asset)
}
return Asset(
id = element.jsonObject["id"]!!.jsonPrimitive.content,
name = element.jsonObject["name"]!!.jsonPrimitive.content,
assets = assets,
)
}
}
https://github.com/reticent-monolith/winds_server is the github repo if anyone finds it easier looking there.
I'm trying to use KMongo and Ktor with Kotlin's Serialization module but creating the MongoClient results in the following exception:
java.lang.ClassCastException: class org.litote.kmongo.serialization.SerializationCodecRegistry cannot be cast to class org.bson.codecs.configuration.CodecProvider (org.litote.kmongo.serialization.SerializationCodecRegistry and org.bson.codecs.configuration.CodecProvider are in unnamed module of loader 'app')
at org.litote.kmongo.service.ClassMappingTypeService$DefaultImpls.codecRegistry(ClassMappingTypeService.kt:83)
at org.litote.kmongo.serialization.SerializationClassMappingTypeService.codecRegistry(SerializationClassMappingTypeService.kt:40)
at org.litote.kmongo.serialization.SerializationClassMappingTypeService.coreCodecRegistry(SerializationClassMappingTypeService.kt:97)
at org.litote.kmongo.service.ClassMappingType.coreCodecRegistry(ClassMappingType.kt)
at org.litote.kmongo.service.ClassMappingTypeService$DefaultImpls.codecRegistry$default(ClassMappingTypeService.kt:79)
at org.litote.kmongo.KMongo.configureRegistry$kmongo_core(KMongo.kt:79)
at org.litote.kmongo.KMongo.createClient(KMongo.kt:70)
at org.litote.kmongo.KMongo.createClient(KMongo.kt:57)
at org.litote.kmongo.KMongo.createClient(KMongo.kt:47)
at org.litote.kmongo.KMongo.createClient(KMongo.kt:39)
at com.reticentmonolith.repo.MongoDispatchRepo.<init>(MongoDispatchRepo.kt:11)
at com.reticentmonolith.ApplicationKt.<clinit>(Application.kt:14)
... 23 more
Am I missing something in my build.gradle?
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.5.10'
id 'org.jetbrains.kotlin.plugin.serialization' version '1.5.10'
id 'application'
}
group 'com.reticentmonolith'
version '0.0.1-SNAPSHOT'
mainClassName = "io.ktor.server.netty.EngineMain"
sourceSets {
main.kotlin.srcDirs = main.java.srcDirs = ['src']
test.kotlin.srcDirs = test.java.srcDirs = ['test']
main.resources.srcDirs = ['resources']
test.resources.srcDirs = ['testresources']
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
// KOTLIN
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
// KTOR
implementation "io.ktor:ktor-server-netty:$ktor_version"
implementation "ch.qos.logback:logback-classic:$logback_version"
implementation "io.ktor:ktor-server-core:$ktor_version"
testImplementation "io.ktor:ktor-server-tests:$ktor_version"
implementation "io.ktor:ktor-serialization:$ktor_version"
// MONGO
implementation group: 'org.mongodb', name: 'mongo-java-driver', version: '3.12.8'
// KOTLINX SERIALIZATION
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1"
// KMONGO
implementation 'org.litote.kmongo:kmongo-serialization:4.2.7'
implementation group: 'org.litote.kmongo', name: 'kmongo-id-serialization', version: '4.2.7'
// KBSON (optional dependency for KMONGO and Serialization)
implementation "com.github.jershell:kbson:0.4.4"
}
Here's my MongoClient class:
import com.mongodb.client.MongoDatabase
import com.reticentmonolith.models.Dispatch
import java.time.LocalDate
import org.litote.kmongo.*
class MongoDispatchRepo: DispatchRepoInterface {
private val client = KMongo.createClient()
private val database: MongoDatabase = client.getDatabase("zw")
private val windsData = database.getCollection<Dispatch>("winds")
override fun createDispatch(dispatch: Dispatch) {
windsData.insertOne(dispatch)
}
override fun getAllDispatches(): Map<String, List<Dispatch>> {
val list = windsData.find().toList()
return mapOf("dispatches" to list)
}
override fun getDispatchesByDate(date: LocalDate): Map<String, List<Dispatch>> {
return mapOf("dispatches" to windsData.find(Dispatch::date eq date).toList())
}
override fun getDispatchesByDateRange(start: LocalDate, end: LocalDate): Map<String, List<Dispatch>> {
return mapOf("dispatches" to windsData.find(Dispatch::date gte(start), Dispatch::date lte(end)).toList())
}
override fun getDispatchById(id: Id<Dispatch>): Dispatch? {
return windsData.findOneById(id)
}
override fun updateDispatchById(id: Id<Dispatch>, update: Dispatch): Boolean {
val oldDispatch = getDispatchById(id)
if (oldDispatch != null) {
update.date = oldDispatch.date
update._id = oldDispatch._id
windsData.updateOneById(id, update)
return true
}
return false
}
override fun updateLastDispatch(update: Dispatch): Boolean {
val lastDispatch = getLastDispatch() ?: return false
update.date = lastDispatch.date
update._id = lastDispatch._id
windsData.updateOneById(lastDispatch._id, update)
return true
}
override fun deleteDispatchById(id: Id<Dispatch>) {
windsData.deleteOne(Dispatch::_id eq id)
}
override fun getLastDispatch(): Dispatch? {
val todaysDispatches = getDispatchesByDate(LocalDate.now())
if (todaysDispatches.isEmpty()) return null
return todaysDispatches["dispatches"]?.last()
}
override fun addSpeedsToLastDispatch(line4: Int?, line3: Int?, line2: Int?, line1: Int?) {
val lastDispatch = getLastDispatch() ?: return
lastDispatch.riders.get(4)?.speed = line4
lastDispatch.riders.get(3)?.speed = line3
lastDispatch.riders.get(2)?.speed = line2
lastDispatch.riders.get(1)?.speed = line1
updateLastDispatch(lastDispatch)
}
fun purgeDatabase() {
windsData.deleteMany(Dispatch::comment eq "")
}
}
And my Application.kt for Ktor:
package com.reticentmonolith
import com.reticentmonolith.models.createExampleDispatches
import io.ktor.application.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.http.*
import com.reticentmonolith.repo.MongoDispatchRepo
import io.ktor.features.*
import io.ktor.serialization.*
import kotlinx.serialization.json.Json
import org.litote.kmongo.id.serialization.IdKotlinXSerializationModule
val repo = MongoDispatchRepo()
fun main(args: Array<String>) = io.ktor.server.netty.EngineMain.main(args)
#Suppress("unused") // Referenced in application.conf
#kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
install(ContentNegotiation) {
json(
Json { serializersModule = IdKotlinXSerializationModule },
contentType = ContentType.Application.Json
)
}
repo.purgeDatabase()
val dispatchList = repo.getAllDispatches()["dispatches"]
if (dispatchList != null && dispatchList.isEmpty()) {
createExampleDispatches(0).forEach {
repo.createDispatch(it)
println("######## date: ${it.date} ################")
}
}
routing {
get("/dispatches/") {
call.response.status(HttpStatusCode.OK)
val dispatches = repo.getAllDispatches()
println("Dispatches from Mongo: $dispatches")
println("Dispatches encoded for response: $dispatches")
}
}
}
And finally the class being serialized:
package com.reticentmonolith.models
import com.reticentmonolith.serializers.DateSerializer
import com.reticentmonolith.serializers.TimeSerializer
import kotlinx.serialization.Contextual
import org.litote.kmongo.*
import kotlinx.serialization.Serializable
import java.time.LocalDate
import java.time.LocalTime
#Serializable
data class Dispatch(
var riders: MutableMap<Int, #Contextual Rider?> = mutableMapOf(
1 to null,
2 to null,
3 to null,
4 to null
),
var comment: String = "",
var wind_degrees: Int,
var wind_speed: Double,
var winds_instructor: String,
var bt_radio: String,
var _id: #Contextual Id<Dispatch> = newId(),
// #Serializable(with=DateSerializer::class)
#Contextual var date: LocalDate = LocalDate.now(),
// #Serializable(with=TimeSerializer::class)
#Contextual var time: LocalTime = LocalTime.now()
)
fun createExampleDispatches(amount: Int): Collection<Dispatch> {
val dispatches = mutableListOf<Dispatch>()
for (i in 0..amount) {
dispatches.add(Dispatch(
bt_radio = "BT Instructor",
winds_instructor = "Winds Instructor",
wind_speed = 20.5,
wind_degrees = 186
).apply {
this.riders[2] = Rider(67, front_slider = Slider.BLACK, trolley = 125)
this.riders[3] = Rider(112, front_slider = Slider.NEW_RED, rear_slider = Slider.YELLOW, trolley = 34)
})
}
return dispatches
}
Any help would be hugely appreciated :) Thanks!
I am trying to convert a string to JSONArray but I am having issues.
This is my test:
class MainActivityTest {
#Test
fun checkParse(){
val loader = ClassLoader.getSystemClassLoader()
val json: String = Files.lines(
get(
loader.getResource("data.json").toURI()
)
)
.parallel()
.collect(Collectors.joining())
val main = MainActivity()
val dataParse2 = Gson().fromJson(json, JSONArray::class.java)
val gson = GsonBuilder().create()
val parse2 = gson.fromJson(json, Array<QuoteModel>::class.java).toList()
val parse1 = main.parseResponse(dataParse2)
assertEquals(parse1,parse2)
}
}
This is the function I am testing in my MainActivity:
fun parseResponse(response: JSONArray): List<QuoteModel> {
val fileData = response.toString()
val gson = GsonBuilder().create()
return gson.fromJson(fileData, Array<QuoteModel>::class.java).toList()
}
And this is my data.json file:
[
{
"text": "Genius is one percent inspiration and ninety-nine percent perspiration.",
"author": "Thomas Edison"
},
{
"text": "You can observe a lot just by watching.",
"author": "Yogi Berra"
},
{
"text": "A house divided against itself cannot stand.",
"author": "Abraham Lincoln"
}
]
the issue comes in this line from my test:
val dataParse2 = Gson().fromJson(json, JSONArray::class.java)
Any ideas?
First Update
This is the function where I call the parseFunction in MainActivity:
private fun jsonArrayRequest(url: String): JsonArrayRequest {
return JsonArrayRequest(Request.Method.GET, url, null,
{ response ->
val quotesArray = parseResponse(response)
displayQuote(chooseQuote(quotesArray))
},
{ error ->
TODO("Handle error missing")
}
)
}
private fun jsonArrayRequest(url: String): JsonArrayRequest {
return JsonArrayRequest(Request.Method.GET, url, null,
{ response ->
val responseArray = JSONArray(response)
val quotesArray = parseResponse(responseArray)
displayQuote(chooseQuote(quotesArray))
},
{ error ->
TODO("Handle error missing")
}
)
fun parseResponse(response: JSONArray): List<QuoteModel> {
return Gson().fromJson(response.toString(), Array<QuoteModel>::class.java).toList()
In need your help in modifying my code, I am trying to build an application that contains a flight schedule by searching on a flight number via data json . l am using edit text and AsyncTask and custom list adapter list view .My application works fine, but the problem is when the user enters the flight number in wrong way l got FATAL EXCEPTION . because data json url he has data array when user enters correct flight number , other ways if user enters wrong flight number the data json url he will back data json in jsonobject and l get FATAL EXCEPTION is
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.iraqairoirt.iraqairports, PID: 5380
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Caused by: org.json.JSONException: Value null of type org.json.JSONObject$1 cannot be converted to JSONArray
at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONArray.<init>(JSONArray.java:96)
at org.json.JSONArray.<init>(JSONArray.java:108)
at com.iraqairoirt.iraqairports.BaghdadAirport.FlightSearch$Arr.handleJson(FlightSearch.kt:106)
at com.iraqairoirt.iraqairports.BaghdadAirport.FlightSearch$Arr.onPostExecute(FlightSearch.kt:90)
at com.iraqairoirt.iraqairports.BaghdadAirport.FlightSearch$Arr.onPostExecute(FlightSearch.kt:58)
at android.os.AsyncTask.finish(AsyncTask.java:660)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:677)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
data json if input is correct l get data array
{
"result": {
"request": {},
"response": {
"data": [
{
"identification": {
"id": null,
"row": 4849651452,
"callsign": null,
"codeshare": null
},
"status": {
"live": false,
"text": "Scheduled",
"icon": null,
"estimated": null,
"ambiguous": false
}
}
]
}
}
}
if input is wrong l get data json object and fatal EXCEPTION
{
"result": {
"request": {},
"response": {
"data": null
}
}
}
class activity including list adapter
class FlightSearch : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_flight_search)
flightlistlaout.bringToFront()
}
fun getflightsearchresult(view:View){
val FlightNumber=flightnumbertext.text.toString()
// val auto=autoCompleteTextView.text.toString()
if(FlightNumber.trim().length>0) {
val url = "flight/list.json?query="+FlightNumber+"&fetchBy=flight&page=1&limit=100&token="
Arr().execute(url)
Toast.makeText(applicationContext, "Message : ", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(applicationContext, "Please enter some message! ", Toast.LENGTH_SHORT).show()
}
}
inner class Arr : AsyncTask<String, String, String>() {
override fun onPreExecute() {
super.onPreExecute()
}
// for build connection
override fun doInBackground(vararg url: String?): String {
var text: String
val connection = URL(url[0]).openConnection() as HttpURLConnection
connection.connectTimeout = 700
try {
connection.connect()
text = connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
} finally {
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson(result)
}
override fun onProgressUpdate(vararg text: String?) {
}
#SuppressLint("WrongViewCast")
private fun handleJson(jsonString: String?) {
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("response")
val jsonArray = JSONArray(response.get("data").toString())
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
FlightShdu(
jsonObject.getJSONObject("identification").getJSONObject("number").getString("default"),
jsonObject.getJSONObject("airline").getString("name"),
jsonObject.getJSONObject("status").getJSONObject("generic").getJSONObject("status").getString(
"text"
),
jsonObject.getJSONObject("airline").getJSONObject("code").getString("icao"),
jsonObject.getJSONObject("time").getJSONObject("scheduled").getString("arrival"),
jsonObject.getJSONObject("airport").getJSONObject("origin").getJSONObject("code").getString(
"iata"
x++
}
list.forEach(::println)
var adapter = FlightSearchAdpater(this#FlightSearch, list)
flightsearchlists.adapter = adapter
}
}
}
class FlightSearchAdpater (val context: Context, val list: ArrayList<FlightShdu>): BaseAdapter() {
#SuppressLint("ViewHolder", "NewApi", "WrongViewCast")
override fun getView(p0: Int, convertView: View?, parent: ViewGroup?): View {
val view : View = LayoutInflater.from(context).inflate(R.layout.baghdad_arrivel_list,parent,false)
val list = list[p0]
val LogoAriline = view.findViewById(R.id.logo_image) as ImageView
val status = view.findViewById(R.id.ali_id) as AppCompatTextView
val Airport = view.findViewById(R.id.airportid) as AppCompatTextView
val code = view.findViewById(R.id.code_id) as AppCompatTextView
val TimeFlight = view.findViewById(R.id.time_id) as AppCompatTextView
val checkiflive = view.checkifliveTextId
view.callsign_id.text=list.Callsign
view.airline_id.text=list.Airline
code.text = list.code
view.ali_id.text=list.Stauts
status.text= list.Stauts
TimeFlight.text = getDateTime(list.TimeFlight)
Picasso.with(context).load(Uri.parse("/data/operators/"+status.text.toString()+"_logo0.png"))
.error(R.drawable.logo).into(LogoAriline)
Airport.text= list.Airport
view.model_id.text=list.Model
checkiflive.text=list.IfLive
private fun getDateTime(s: String): String? {
try {
val sdf = SimpleDateFormat("EE, MMM d KK:mm a")
val netDate = Date(s.toLong() * 1000)
return sdf.format(netDate)
} catch (e: Exception) {
return e.toString()
}
}
override fun getItem(p0: Int): Any {
return list [p0]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getCount(): Int {
return list.size
}
}
when l track FATAL EXCEPTION: main found the main problem in line 106 with this code val jsonArray = JSONArray(response.get("data").toString())
please l want answer with code guys , l want add text when the user enters wrong information he get respond example "no flights found please make sure about the flight number "
thank you
Caused by: org.json.JSONException: Value null of type
org.json.JSONObject$1 cannot be converted to JSONArray
You should check getJSONArray is null or not
Below code will work if Your Json "data":[]
val jsonData = response.getJSONArray("data")
if(jsonData.length()!=0)
{
// Do your work
}
FYI
You should check your Json data JSONArray or String.
Object dataVal= response.get("data");
if (dataValis is JSONArray)
{
// Your code
}
else
{
// null value
}
l found this way and its working fine
private fun handleJson(jsonString: String?) {
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("response")
if (jsonObj is JSONArray) {
val jsonArray= response.getJSONArray("data")
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
FlightShdu(
jsonObject.getJSONObject("identification").getJSONObject("number").getString("default"),
jsonObject.getJSONObject("airline").getString("name"),
jsonObject.getJSONObject("status").getJSONObject("generic").getJSONObject("status").getString(
"text"
),
)
)
x++
}
list.forEach(::println)
var adapter = FlightSearchAdpater(this#FlightSearch, list)
flightsearchlists.adapter = adapter
}else if(jsonObj is JSONObject){
val response = result.getJSONObject("response")
if(response.isNull("data")){
Toast.makeText(applicationContext, "Please enter currect flight number", Toast.LENGTH_SHORT).show()
}
}
}