#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 — это массив, а не объект с переменной массива 🙂