-
Notifications
You must be signed in to change notification settings - Fork 145
Description
Description
We are using this library for our Ticket Vending Machine where we make use of Adyen UX300 terminals with ANDROID app.
From past few weeks we are getting a crash within the library when making a call to POST /sync API call public TerminalAPIResponse sync(TerminalAPIRequest terminalAPIRequest).
We have been using this library for more than 2 years and atleast 1.5 years in production. Over the months we are making updates/upgrade to library versions.
Current version is 40.1.0 We are recently getting the crash out of the blue, we tried restoring the app to the previous version incase the something might have gone side ways. But, that did not help. We tried downgrading the library to 38.x still no success.
Kindly help.
Steps to reproduce
- Have UX300 LIVE terminal
- setup a payment and store related info on the cloud and dashboard.
- make the
terminalCloudApi.sync(request)using the ip address of the terminal.
Actual behavior
When calling sync it crashes the library internally(and leads to Android app crash)
I have attached the crash logs, request logs at the bottom.
Here is the top stack trace:
java.lang.NoSuchMethodError java.lang.NoSuchMethodError: No static method supportedOptions(Ljava/lang/Class;)Ljava/util/Set; in class Ljdk/net/Sockets; or its super classes (declaration of 'jdk.net.Sockets' appears in /apex/com.android.art/javalib/core-oj.jar)
0 org.apache.hc.client5.http.impl.io.DefaultHttpClientConnectionOperator.<clinit>(DefaultHttpClientConnectionOperator.java:87)
1 org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder.createConnectionOperator(PoolingHttpClientConnectionManagerBuilder.java:325)
2 org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder.build(PoolingHttpClientConnectionManagerBuilder.java:344)
3 com.adyen.httpclient.AdyenHttpClient.createHttpClientWithSocketFactory(AdyenHttpClient.java:268)
4 com.adyen.httpclient.AdyenHttpClient.createCloseableHttpClient(AdyenHttpClient.java:258)
5 com.adyen.httpclient.AdyenHttpClient.request(AdyenHttpClient.java:127)
6 com.adyen.service.resource.Resource.request(Resource.java:120)
7 com.adyen.service.resource.Resource.request(Resource.java:94)
8 com.adyen.service.resource.Resource.request(Resource.java:70)
9 com.adyen.service.TerminalCloudAPI.sync(TerminalCloudAPI.java:75)
10 se.flygbussarna.adyen.AdyenImpl.executeTransactionSync(AdyenImpl.kt:206)
11 se.flygbussarna.blue.usecase.payment.AdyenPaymentUseCase$initiatePayment$1.invokeSuspend(AdyenPaymentUseCase.kt:122)Expected behavior
It should open/activate the transaction on the UX300 terminal for user to make the payment.
Code snippet or screenshots (if applicable)
Crash happens when we call the terminalCloudApi.sync(request)
override fun executeTransactionSync(request: TerminalAPIRequest): TerminalAPIResponse? =
terminalCloudApi.sync(request)Full class implementation
class AdyenImpl : AdyenAPI {
private val clientProvider: ClientProvider = ClientProviderImpl()
private val terminalCloudApi = TerminalCloudAPI(clientProvider.getClient())
private fun getMessageHeader(
serviceId: String,
saleId: String,
poiId: String,
) = MessageHeader().apply {
messageClass = MessageClassType.SERVICE
messageType = MessageType.REQUEST
protocolVersion = "3.0"
serviceID = serviceId
saleID = saleId
poiid = poiId
}
private fun getPaymentMessageHeader(
serviceId: String,
saleId: String,
poiId: String,
) = getMessageHeader(
serviceId = serviceId,
saleId = saleId,
poiId = poiId
).apply {
messageCategory = MessageCategoryType.PAYMENT
}
private fun getAbortPaymentMessageHeader(
serviceId: String,
saleId: String,
poiId: String,
) = getMessageHeader(
serviceId = serviceId,
saleId = saleId,
poiId = poiId
).apply {
messageCategory = MessageCategoryType.ABORT
}
private fun getDiagnosisMessageHeader(
serviceId: String,
saleId: String,
poiId: String,
) = getMessageHeader(
serviceId = serviceId,
saleId = saleId,
poiId = poiId
).apply {
messageCategory = MessageCategoryType.DIAGNOSIS
}
private fun getVySaleData(bookingId: String) = SaleData().apply {
val merchantApplication = CommonField().apply {
version = "1.0"
name = "Vy FlygBusSarna"
}
val applicationInfo = ApplicationInfo().apply {
this.merchantApplication = merchantApplication
}
val saleToAcquirerData = SaleToAcquirerData().apply {
// internal code hidden
}
val timestamp = DatatypeFactory.newInstance().newXMLGregorianCalendar(GregorianCalendar())
val transactionIdentification = TransactionIdentification().apply {
// internal code hidden
this.timeStamp = timestamp
}
this.saleTransactionID = transactionIdentification
this.saleToAcquirerData = saleToAcquirerData
// internal code hidden
}
private fun getSaleToPOIRequest(
serviceId: String,
saleId: String,
poiId: String,
) = SaleToPOIRequest().apply {
messageHeader = getPaymentMessageHeader(
serviceId = serviceId,
saleId = saleId,
poiId = poiId,
)
}
private fun getSaleToPOIForAbortRequest(
serviceId: String,
saleId: String,
poiId: String,
) = SaleToPOIRequest().apply {
messageHeader = getAbortPaymentMessageHeader(
serviceId = serviceId,
saleId = saleId,
poiId = poiId,
)
}
private fun getPaymentTransaction(amount: Double, currency: String) =
PaymentTransaction().apply {
val amountsReq = AmountsReq().apply {
this.currency = currency // "SEK"
this.requestedAmount = BigDecimal.valueOf(amount)
}
this.amountsReq = amountsReq
}
private fun getAbortMessageReference(
serviceIdForAbort: String,
saleId: String,
poiId: String,
) = MessageReference().apply {
messageCategory = MessageCategoryType.PAYMENT
serviceID = serviceIdForAbort
saleID = saleId
poiid = poiId
}
override fun generateTerminalRequestForPayment(
amount: Double,
currency: String,
serviceId: String,
saleId: String,
poiId: String,
bookingId: String,
): TerminalAPIRequest {
val paymentRequest = PaymentRequest().apply {
paymentTransaction = getPaymentTransaction(amount, currency)
saleData = getVySaleData(bookingId)
}
val saleToPOIRequest = getSaleToPOIRequest(
serviceId = serviceId,
saleId = saleId,
poiId = poiId,
).apply {
this.paymentRequest = paymentRequest
}
return TerminalAPIRequest().apply {
this.saleToPOIRequest = saleToPOIRequest
}
}
override fun generateTerminalRequestForAbortingPayment(
serviceIdForAbort: String,
serviceId: String,
saleId: String,
poiId: String,
): TerminalAPIRequest {
val abortMessageReference = getAbortMessageReference(
serviceIdForAbort = serviceIdForAbort,
saleId = saleId,
poiId = poiId,
)
val abortRequest = AbortRequest().apply {
messageReference = abortMessageReference
abortReason = "user abort"
}
val saleToPOIRequest = getSaleToPOIForAbortRequest(
serviceId = serviceId,
saleId = saleId,
poiId = poiId,
).apply {
this.abortRequest = abortRequest
}
return TerminalAPIRequest().apply {
this.saleToPOIRequest = saleToPOIRequest
}
}
override fun transactionStatusRequest(requestServiceID: String) {}
override fun executeTransactionSync(request: TerminalAPIRequest): TerminalAPIResponse? =
terminalCloudApi.sync(request)
override fun executeTransactionAsync(request: TerminalAPIRequest): String =
terminalCloudApi.async(request)
override fun diagnosisRequest(
serviceId: String,
saleId: String,
poiId: String,
): TerminalAPIRequest {
val saleToPOIRequest = SaleToPOIRequest()
saleToPOIRequest.setMessageHeader(
getDiagnosisMessageHeader(
serviceId = serviceId,
saleId = saleId,
poiId = poiId,
)
)
saleToPOIRequest.setDiagnosisRequest(
DiagnosisRequest().apply {
this.isHostDiagnosisFlag = true
}
)
return TerminalAPIRequest().apply {
this.saleToPOIRequest = saleToPOIRequest
}
}
}Adyen Java API Library version
38.x, 39.x, 40.x
Java version
19 and 21
Operating System
Android
Additional context
TVM-755584-HiAz4qex0r6GP_dfNtZ-console.txt
TVM-755584-HiAz4qex0r6GP_dfNtZ-callstack.txt
request-log.txt