Mario Burga
Mario Burga

Reputation: 1157

JSON parsing using Gson returns an error for a boolean value

I have the following json generated from a WordPress Post:

    {  
   "events":[  
      {  
         "id":4651,
         "title":"Test title",
         "description":"testttt",
         "image": {
            url: "https://myhost.tv/wp-content/uploads/2019/07/event2.jpg",
            id: "4652"}
       }
       ]
 }

My model for json is as follows:

    data class EventsFeed(val events: Array<Events>)

    data class Events (

        val id : Int,
        val title : String,
        val description : String,
        val image : Image
    )


    data class Image (
        val url : String,
        val id : Int,
    )

I do the parsing with Json and everything works fine, but when I do a POST in wordpress and I don't put an image, the value of the Image key puts me as afalse, like this:

{  
   "events":[  
      {  
         "id":4651,
         "title":"Stand Up Comedy",
         "description":"testttt",
         "image":false
       }
       ]
 }

And just because image has the valuefalse, the parsing returns an error: Expected BEGIN_OBJECT but was BOOLEAN at line 1 column 5781 path $ .events [1] .image

What can I do so that when the post has no image to parse correctly ignoring the value false or in any case if it isfalse please keep it a default image (https://myhost.com/image_defaul.jpg)

The json is generated by the plugin for Wordpress: The Events Calendar: Demo json here

My function (usen Volley and Gson) for parsing is as follows (the data array is sent to an adapter for display in a recyclerview)

fun jsonObjectRequest() {
    Log.i(LOG_TAG, "jsonObjectRequest")

    // Instantiate the RequestQueue.
    val queue = Volley.newRequestQueue(activity)

    val url = "https://myhost.tv/wp-json/tribe/events/v1/events"

    // Request a JSONObject response from the provided URL.
    val jsonObjectRequest = JsonObjectRequest( url, null,
        Response.Listener { response ->
            Log.i(LOG_TAG, "Response is: $response")

            val gson = Gson()
            val homeEvents  = gson.fromJson(response.toString(), EventsFeed::class.java)

            activity?.runOnUiThread {
                recyclerEvents.adapter = AdaptadorEventos(homeEvents)

            }   
        },
        Response.ErrorListener { error ->
            error.printStackTrace()
            Log.e(LOG_TAG, "That didn't work!")
        }
    )

    // Add the request to the RequestQueue.
    queue.add(jsonObjectRequest)
}

Upvotes: 0

Views: 1200

Answers (4)

Akshay Kumar Both
Akshay Kumar Both

Reputation: 382

The reason why your post method is not getting the Image Class object is because of the json is not a valid json, You may validate it on https://jsonlint.com/. The reason is: "url" and "id" keys are not surrounded by "". Take a look at the below solution, it works perfectly:

package com.example.myapplication

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import com.google.gson.Gson

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        getEvemtsObject()

    }

    private val jsonString = " {\n" +
            " \t\"events\": [{\n" +
            " \t\t\"id\": 4651,\n" +
            " \t\t\"title\": \"Test title\",\n" +
            " \t\t\"description\": \"testttt\",\n" +
            " \t\t\"image\": {\n" +
            " \t\t\t\"url\": \"https://myhost.tv/wp-content/uploads/2019/07/event2.jpg\",\n" +
            " \t\t\t\"id\": \"4652\"\n" +
            " \t\t}\n" +
            " \t}]\n" +
            " }"

    private fun getEvemtsObject() {
        val gson = Gson()
        System.out.println("from_gson  ---> " + gson.fromJson<EventsFeed>(jsonString,EventsFeed::class.java))
    }

}

Upvotes: 2

Mojtaba Haddadi
Mojtaba Haddadi

Reputation: 1376

the image parameter in constructor should be nullable. rewrite your class like this

data class Events (

    val id : Int,
    val title : String,
    val description : String,
    var image : Image? = null)

and change your API to send null instead of false.

Upvotes: 1

Andrei Tanana
Andrei Tanana

Reputation: 8442

You can use custom Gson deserializer like this:

class EventsDeserializer : JsonDeserializer<Events> {
    override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Events {
        val jsonObject = json.asJsonObject
        return Events(
            id = jsonObject.get("id").asInt,
            title = jsonObject.get("title").asString,
            description = jsonObject.get("description").asString,
            image = parseImage(context, jsonObject.get("image"))
        )
    }

    private fun parseImage(context: JsonDeserializationContext, json: JsonElement): Image =
        try {
            context.deserialize(json, Image::class.java)
        } catch (_: Throwable) {
            Image("https://myhost.com/image_defaul.jpg", 0)
        }
}

and here is the test of your json:

fun main() {
    val gson = GsonBuilder()
        .registerTypeAdapter(Events::class.java, EventsDeserializer())
        .create()
    val json = """
{
  "events": [
    {
      "id": 4651,
      "title": "Stand Up Comedy",
      "description": "testttt",
      "image": false
    }
  ]
}
    """.trimIndent()
    val events = gson.fromJson(json, EventsFeed::class.java)
}

Upvotes: 1

Martin Zeitler
Martin Zeitler

Reputation: 76769

This might also be an option (but fixing the API is the better option):

val image: Any

Upvotes: 0

Related Questions