Анализатор проблем Android Kotlin с Retrofit2 ожидал BEGIN_OBJECT, но был BEGIN_ARRAY в строке 1 столбец 2 путь $

#android #kotlin #retrofit2

#Android #kotlin #retrofit2

Вопрос:

У меня возникла проблема при получении json из демонстрационного API Mercadopago, и я не могу понять, что происходит, не могли бы вы сказать мне, что я делаю не так?

и хорошо ли моделируются поля «financial_institutions» и «exclusion_pattern»?

Спасибо

JSON

 [
    {
        "id": "mercadopago_cc",
        "name": "Mercado Pago   Banco Patagonia",
        "payment_type_id": "credit_card",
        "status": "active",
        "secure_thumbnail": "https://http2.mlstatic.com/storage/logos-api-admin/dbf74650-b234-11e9-b872-f9cdde9240f0-m@2x.png",
        "thumbnail": "https://http2.mlstatic.com/storage/logos-api-admin/dbf74650-b234-11e9-b872-f9cdde9240f0-m@2x.png",
        "deferred_capture": "supported",
        "settings": [
            {
                "card_number": {
                    "validation": "standard",
                    "length": 16
                },
                "bin": {
                    "pattern": "^((515073)|(515070)|(532384))",
                    "installments_pattern": "^((515073)|(515070)|(532384))",
                    "exclusion_pattern": null
                },
                "security_code": {
                    "length": 3,
                    "card_location": "back",
                    "mode": "mandatory"
                }
            },
            {
                "card_number": {
                    "validation": "standard",
                    "length": 16
                },
                "bin": {
                    "pattern": "^(532383)",
                    "installments_pattern": "^(532383)",
                    "exclusion_pattern": null
                },
                "security_code": {
                    "length": 3,
                    "card_location": "back",
                    "mode": "optional"
                }
            }
        ],
        "additional_info_needed": [
            "cardholder_name",
            "cardholder_identification_type",
            "cardholder_identification_number"
        ],
        "min_allowed_amount": 0,
        "max_allowed_amount": 250000,
        "accreditation_time": 2880,
        "financial_institutions": [],
        "processing_modes": [
            "aggregator"
        ]
    },
    {
        "id": "cabal",
        "name": "Cabal",
        "payment_type_id": "credit_card",
        "status": "active",
        "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/cabal.gif",
        "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/cabal.gif",
        "deferred_capture": "supported",
        "settings": [
            {
                "card_number": {
                    "validation": "standard",
                    "length": 16
                },
                "bin": {
                    "pattern": "^((627170)|(589657)|(603522)|(604((20[1-9])|(2[1-9][0-9])|(3[0-9]{2})|(400))))",
                    "installments_pattern": "^((627170)|(589657)|(603522)|(604((20[1-9])|(2[1-9][0-9])|(3[0-9]{2})|(400))))",
                    "exclusion_pattern": "^(604201)"
                },
                "security_code": {
                    "length": 3,
                    "card_location": "back",
                    "mode": "mandatory"
                }
            }
        ],
        "additional_info_needed": [
            "cardholder_name",
            "cardholder_identification_type",
            "cardholder_identification_number"
        ],
        "min_allowed_amount": 0,
        "max_allowed_amount": 700000,
        "accreditation_time": 2880,
        "financial_institutions": [],
        "processing_modes": [
            "aggregator"
        ]
    },
    {
        "id": "maestro",
        "name": "Maestro",
        "payment_type_id": "debit_card",
        "status": "active",
        "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/maestro.gif",
        "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/maestro.gif",
        "deferred_capture": "unsupported",
        "settings": [
            {
                "card_number": {
                    "validation": "none",
                    "length": 18
                },
                "bin": {
                    "pattern": "^(501026|501068|501051|501059|557909|501066|588729|501075|501062|501060|501057|501056|501055|501053|501043|501041|501038|501028|501023|501021|501020|501018|501016)",
                    "installments_pattern": "",
                    "exclusion_pattern": null
                },
                "security_code": {
                    "length": 3,
                    "card_location": "back",
                    "mode": "mandatory"
                }
            },
            {
                "card_number": {
                    "validation": "none",
                    "length": 19
                },
                "bin": {
                    "pattern": "^(501068|601782|508143|501081|501080)",
                    "installments_pattern": "",
                    "exclusion_pattern": null
                },
                "security_code": {
                    "length": 3,
                    "card_location": "back",
                    "mode": "mandatory"
                }
            }
        ],
        "additional_info_needed": [
            "cardholder_identification_number",
            "cardholder_identification_type",
            "cardholder_name"
        ],
        "min_allowed_amount": 1,
        "max_allowed_amount": 700000,
        "accreditation_time": 1440,
        "financial_institutions": [],
        "processing_modes": [
            "aggregator"
        ]
    },
    {
        "id": "cmr",
        "name": "CMR",
        "payment_type_id": "credit_card",
        "status": "active",
        "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/cmr.gif",
        "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/cmr.gif",
        "deferred_capture": "supported",
        "settings": [
            {
                "card_number": {
                    "validation": "standard",
                    "length": 16
                },
                "bin": {
                    "pattern": "^(557039)",
                    "installments_pattern": "^(557039)",
                    "exclusion_pattern": null
                },
                "security_code": {
                    "length": 3,
                    "card_location": "back",
                    "mode": "mandatory"
                }
            }
        ],
        "additional_info_needed": [
            "cardholder_name",
            "cardholder_identification_type",
            "cardholder_identification_number"
        ],
        "min_allowed_amount": 1,
        "max_allowed_amount": 700000,
        "accreditation_time": 2880,
        "financial_institutions": [],
        "processing_modes": [
            "aggregator"
        ]
    }
]
  

ОШИБКА

 2020-11-12 12:50:46.417 17673-17673/com.example.leandropayments V/Error: Error retrofit
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224)
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
    at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:119)
    at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:218)
    at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:112)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:141)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:919)
 Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:213)
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37) 
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25) 
    at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:119) 
    at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:218) 
    at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:112) 
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:141) 
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
    at java.lang.Thread.run(Thread.java:919)
  

мой класс взаимодействует

  class InteractorMethodsPayments(private val listener: ResponseListener<MethodPayment>): BaseInteractorApiMP<MethodsPaymentsResponse>() {
    fun execute(){
        mpApiClient.searchMethodsPaymentsByKey(key).enqueue(this)
    }

    override fun onResponse(call: Call<MethodsPaymentsResponse>, response: Response<MethodsPaymentsResponse>) {
        try {
            // Example using Non-Null Asserted Call to catch the exception in case of being a null reference
            if (response!!.isSuccessful amp;amp; response.body() != null) {
                val methodsPaymentsDataModel = response.body()?.values ?: emptyList()
                listener.onResponse(methodsPaymentsDataModel)
            }
        } catch (e: Exception) {
            listener.onError(e)
        }
    }

    override fun onFailure(call: Call<MethodsPaymentsResponse>, t: Throwable) {
        listener.onError(t)
    }
}
  

class ApiServicesMP

 open class BaseInteractorApiMP<T : Any?>(): Callback<T> {
    companion object {
        const val baseBitBucketApiUrl = "https://api.mercadopago.com/v1/"
        const val key = "*******************************"
    }

    val mpApiClient: ApiServicesMP

    init {
        mpApiClient = Retrofit.Builder()
            .baseUrl(baseBitBucketApiUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiServicesMP::class.java)
    }

    override fun onResponse(call: Call<T>, response: Response<T>) {
        TODO("Not yet implemented")
    }

    override fun onFailure(call: Call<T>, t: Throwable) {
        TODO("Not yet implemented")
    }
}
  

Интерфейс ResponseListener

 interface ResponseListener<T> {
    fun onResponse(repos: List<T>)
    fun onError(t: Throwable?)
}
  

Интерфейс ApiserviceMP

 interface ApiServicesMP {

    @GET("payment_methods")
    fun searchMethodsPaymentsByKey(
        @Query("public_key") key: String
    ): Call<MethodsPaymentsResponse>

    @GET("payment_methods/card_issuers{public_key,payment_method_id}")
    fun searchCardsByKey(
        @Path("public_key") key: String,
        @Path("payment_method_id") method_id: String
    ): Call<CardsResponse>

    @GET("payment_methods/installments{public_key,amount,payment_method_id,issuer.id}")
    fun searchInstallmenstsByKey(
        @Path("public_key") username: String,
        @Path("payment_method_id") method_id: String,
        @Path("issuer.id") issuer_id: String
    ): Call<InstallmentsResponse>
}
  

Класс данных

 data class MethodsPaymentsResponse(val values: List<MethodPayment>)
  

Модель

 data class MethodPayment(
    val id: String,
    val name: String,
    val payment_type_id: String,
    val status: String,
    val secure_thumbnail: String,
    val thumbnail: String,
    val deferred_capture: String,
    val settings: List<Setting>,
    val additional_info_needed: List<String>,
    val min_allowed_amount: Double,
    val max_allowed_amount: Double,
    val accreditation_time: Double,
    val financial_institutions: List<String>,
    val processing_modes: List<String>
)
  

 

Ответ №1:

Ваш ответ должен быть List<MethodPayment> , а не MethodsPaymentsResponse содержать список платежей.
Корень JSON — это массив, а не объект с переменной массива 🙂