Saving some CPU cycles, only serializing finTsModel if required

This commit is contained in:
dankito 2024-10-15 13:21:19 +02:00
parent ecf930fcad
commit 4802493886
7 changed files with 24 additions and 39 deletions

View File

@ -73,7 +73,7 @@ open class FinTsClient(
if (accountsSupportingRetrievingTransactions.isEmpty()) { if (accountsSupportingRetrievingTransactions.isEmpty()) {
val errorMessage = "None of the accounts ${accounts.map { it.productName }} supports retrieving balance or transactions" // TODO: translate val errorMessage = "None of the accounts ${accounts.map { it.productName }} supports retrieving balance or transactions" // TODO: translate
return GetAccountDataResponse(ErrorCode.NoneOfTheAccountsSupportsRetrievingData, errorMessage, mapper.map(bank), previousJobMessageLog ?: listOf(), bank, serialize(bank)) return GetAccountDataResponse(ErrorCode.NoneOfTheAccountsSupportsRetrievingData, errorMessage, mapper.map(bank), previousJobMessageLog ?: listOf(), bank)
} }
for (account in accountsSupportingRetrievingTransactions) { for (account in accountsSupportingRetrievingTransactions) {
@ -89,7 +89,7 @@ open class FinTsClient(
val errorCode = unsuccessfulJob?.let { mapper.mapErrorCode(it) } val errorCode = unsuccessfulJob?.let { mapper.mapErrorCode(it) }
?: if (retrievedTransactionsResponses.size < accountsSupportingRetrievingTransactions.size) ErrorCode.DidNotRetrieveAllAccountData else null ?: if (retrievedTransactionsResponses.size < accountsSupportingRetrievingTransactions.size) ErrorCode.DidNotRetrieveAllAccountData else null
return GetAccountDataResponse(errorCode, mapper.mapErrorMessages(unsuccessfulJob), mapper.map(bank, retrievedTransactionsResponses, param.retrieveTransactionsTo), return GetAccountDataResponse(errorCode, mapper.mapErrorMessages(unsuccessfulJob), mapper.map(bank, retrievedTransactionsResponses, param.retrieveTransactionsTo),
mapper.mergeMessageLog(previousJobMessageLog, *retrievedTransactionsResponses.map { it.messageLog }.toTypedArray()), bank, serialize(bank)) mapper.mergeMessageLog(previousJobMessageLog, *retrievedTransactionsResponses.map { it.messageLog }.toTypedArray()), bank)
} }
protected open suspend fun getAccountTransactions(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse { protected open suspend fun getAccountTransactions(param: GetAccountDataParameter, bank: BankData, account: AccountData): GetAccountTransactionsResponse {
@ -124,7 +124,7 @@ open class FinTsClient(
if (getAccountInfoResponse.successful == false) { if (getAccountInfoResponse.successful == false) {
return TransferMoneyResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse), return TransferMoneyResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse),
getAccountInfoResponse.messageLog, bank, serialize(bank)) getAccountInfoResponse.messageLog, bank)
} else { } else {
return transferMoneyAsync(param, recipientBankIdentifier, getAccountInfoResponse.bank, getAccountInfoResponse.bank.accounts, getAccountInfoResponse) return transferMoneyAsync(param, recipientBankIdentifier, getAccountInfoResponse.bank, getAccountInfoResponse.bank.accounts, getAccountInfoResponse)
} }
@ -138,14 +138,14 @@ open class FinTsClient(
val accountToUse: AccountData val accountToUse: AccountData
if (accountsSupportingTransfer.isEmpty()) { if (accountsSupportingTransfer.isEmpty()) {
return TransferMoneyResponse(ErrorCode.NoAccountSupportsMoneyTransfer, "None of the accounts $accounts supports money transfer", previousJobResponse?.messageLog ?: listOf(), bank, serialize(bank)) return TransferMoneyResponse(ErrorCode.NoAccountSupportsMoneyTransfer, "None of the accounts $accounts supports money transfer", previousJobResponse?.messageLog ?: listOf(), bank)
} else if (accountsSupportingTransfer.size == 1) { } else if (accountsSupportingTransfer.size == 1) {
accountToUse = accountsSupportingTransfer.first() accountToUse = accountsSupportingTransfer.first()
} else { } else {
val selectedAccount = param.selectAccountToUseForTransfer?.invoke(accountsSupportingTransfer) val selectedAccount = param.selectAccountToUseForTransfer?.invoke(accountsSupportingTransfer)
if (selectedAccount == null) { if (selectedAccount == null) {
return TransferMoneyResponse(ErrorCode.MoreThanOneAccountSupportsMoneyTransfer, "More than one of the accounts $accountsSupportingTransfer supports money transfer, so we cannot clearly determine which one to use for this transfer", previousJobResponse?.messageLog ?: listOf(), bank, serialize(bank)) return TransferMoneyResponse(ErrorCode.MoreThanOneAccountSupportsMoneyTransfer, "More than one of the accounts $accountsSupportingTransfer supports money transfer, so we cannot clearly determine which one to use for this transfer", previousJobResponse?.messageLog ?: listOf(), bank)
} }
accountToUse = selectedAccount accountToUse = selectedAccount
@ -156,7 +156,7 @@ open class FinTsClient(
val response = config.jobExecutor.transferMoneyAsync(context, BankTransferData(param.recipientName, param.recipientAccountIdentifier, recipientBankIdentifier, val response = config.jobExecutor.transferMoneyAsync(context, BankTransferData(param.recipientName, param.recipientAccountIdentifier, recipientBankIdentifier,
param.amount, param.reference, param.instantPayment)) param.amount, param.reference, param.instantPayment))
return TransferMoneyResponse(mapper.mapErrorCode(response), mapper.mapErrorMessages(response), mapper.mergeMessageLog(previousJobResponse, response), bank, serialize(bank)) return TransferMoneyResponse(mapper.mapErrorCode(response), mapper.mapErrorMessages(response), mapper.mergeMessageLog(previousJobResponse, response), bank)
} }
private fun getRecipientBankCode(param: TransferMoneyParameter): String? { private fun getRecipientBankCode(param: TransferMoneyParameter): String? {
@ -194,7 +194,7 @@ open class FinTsClient(
*/ */
open suspend fun getRequiredDataToSendUserJobs(param: FinTsClientParameter): net.dankito.banking.client.model.response.FinTsClientResponse { open suspend fun getRequiredDataToSendUserJobs(param: FinTsClientParameter): net.dankito.banking.client.model.response.FinTsClientResponse {
if (param.finTsModel != null) { if (param.finTsModel != null) {
return net.dankito.banking.client.model.response.FinTsClientResponse(null, null, emptyList(), param.finTsModel, serialize(param.finTsModel)) return net.dankito.banking.client.model.response.FinTsClientResponse(null, null, emptyList(), param.finTsModel)
} }
val defaultValues = (param as? GetAccountDataParameter)?.defaultBankValues val defaultValues = (param as? GetAccountDataParameter)?.defaultBankValues
@ -209,7 +209,7 @@ open class FinTsClient(
val getAccountInfoResponse = getAccountInfo(param, bank) val getAccountInfoResponse = getAccountInfo(param, bank)
return net.dankito.banking.client.model.response.FinTsClientResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse), return net.dankito.banking.client.model.response.FinTsClientResponse(mapper.mapErrorCode(getAccountInfoResponse), mapper.mapErrorMessages(getAccountInfoResponse),
getAccountInfoResponse.messageLog, bank, serialize(bank)) getAccountInfoResponse.messageLog, bank)
} }
protected open suspend fun getAccountInfo(param: FinTsClientParameter, bank: BankData): GetAccountInfoResponse { protected open suspend fun getAccountInfo(param: FinTsClientParameter, bank: BankData): GetAccountInfoResponse {
@ -236,12 +236,4 @@ open class FinTsClient(
return GetAccountInfoResponse(context, getAccountsResponse) return GetAccountInfoResponse(context, getAccountsResponse)
} }
@JvmName("serializeNullable")
@JsName("serializeNullable")
private fun serialize(bank: BankData?) =
bank?.let { serialize(bank) }
private fun serialize(bank: BankData): String? = mapper.serialize(bank)
} }

View File

@ -15,12 +15,9 @@ import net.codinux.banking.fints.response.segments.AccountType
import net.codinux.banking.fints.util.BicFinder import net.codinux.banking.fints.util.BicFinder
import net.codinux.banking.fints.extensions.minusDays import net.codinux.banking.fints.extensions.minusDays
import net.codinux.banking.fints.extensions.todayAtEuropeBerlin import net.codinux.banking.fints.extensions.todayAtEuropeBerlin
import net.codinux.banking.fints.serialization.FinTsModelSerializer
open class FinTsModelMapper( open class FinTsModelMapper {
private val serializer: FinTsModelSerializer = FinTsModelSerializer()
) {
protected open val bicFinder = BicFinder() protected open val bicFinder = BicFinder()
@ -203,7 +200,4 @@ open class FinTsModelMapper(
return responses.filterNotNull().flatMap { it.messageLog } return responses.filterNotNull().flatMap { it.messageLog }
} }
open fun serialize(finTsModel: BankData?): String? =
finTsModel?.let { serializer.serializeToJson(finTsModel) }
} }

View File

@ -5,7 +5,7 @@ import kotlinx.serialization.json.Json
import net.codinux.banking.fints.model.BankData import net.codinux.banking.fints.model.BankData
import net.codinux.log.logger import net.codinux.log.logger
open class FinTsModelSerializer { object FinTsModelSerializer {
private val json: Json by lazy { private val json: Json by lazy {
Json { this.ignoreUnknownKeys = true } Json { this.ignoreUnknownKeys = true }
@ -23,7 +23,7 @@ open class FinTsModelSerializer {
private val log by logger() private val log by logger()
open fun serializeToJson(bank: BankData, prettyPrint: Boolean = false): String? { fun serializeToJson(bank: BankData, prettyPrint: Boolean = false): String? {
return try { return try {
val serializableData = mapper.map(bank) val serializableData = mapper.map(bank)
@ -36,7 +36,7 @@ open class FinTsModelSerializer {
} }
} }
open fun deserializeFromJson(serializedFinTsData: String): BankData? = try { fun deserializeFromJson(serializedFinTsData: String): BankData? = try {
val serializedData = json.decodeFromString<SerializedFinTsData>(serializedFinTsData) val serializedData = json.decodeFromString<SerializedFinTsData>(serializedFinTsData)
mapper.map(serializedData) mapper.map(serializedData)

View File

@ -2,6 +2,7 @@ package net.dankito.banking.client.model.response
import net.codinux.banking.fints.model.BankData import net.codinux.banking.fints.model.BankData
import net.codinux.banking.fints.model.MessageLogEntry import net.codinux.banking.fints.model.MessageLogEntry
import net.codinux.banking.fints.serialization.FinTsModelSerializer
// TODO: rename to BankingClientResponse? // TODO: rename to BankingClientResponse?
@ -9,8 +10,7 @@ open class FinTsClientResponse(
open val error: ErrorCode?, open val error: ErrorCode?,
open val errorMessage: String?, open val errorMessage: String?,
open val messageLog: List<MessageLogEntry>, open val messageLog: List<MessageLogEntry>,
open val finTsModel: BankData? = null, open val finTsModel: BankData? = null
open val serializedFinTsModel: String? = null
) { ) {
internal constructor() : this(null, null, listOf()) // for object deserializers internal constructor() : this(null, null, listOf()) // for object deserializers
@ -22,4 +22,7 @@ open class FinTsClientResponse(
open val errorCodeAndMessage: String open val errorCodeAndMessage: String
get() = "$error${errorMessage?.let { " $it" }}" get() = "$error${errorMessage?.let { " $it" }}"
// save some CPU cycles, only serialize finTsModel if required
open val serializedFinTsModel: String? by lazy { finTsModel?.let { FinTsModelSerializer.serializeToJson(it) } }
} }

View File

@ -10,9 +10,8 @@ open class GetAccountDataResponse(
errorMessage: String?, errorMessage: String?,
open val customerAccount: CustomerAccount?, open val customerAccount: CustomerAccount?,
messageLog: List<MessageLogEntry>, messageLog: List<MessageLogEntry>,
finTsModel: BankData? = null, finTsModel: BankData? = null
serializedFinTsModel: String? = null ) : FinTsClientResponse(error, errorMessage, messageLog, finTsModel) {
) : FinTsClientResponse(error, errorMessage, messageLog, finTsModel, serializedFinTsModel) {
internal constructor() : this(null, null, null, listOf()) // for object deserializers internal constructor() : this(null, null, null, listOf()) // for object deserializers

View File

@ -8,6 +8,5 @@ open class TransferMoneyResponse(
error: ErrorCode?, error: ErrorCode?,
errorMessage: String?, errorMessage: String?,
messageLog: List<MessageLogEntry>, messageLog: List<MessageLogEntry>,
finTsModel: BankData? = null, finTsModel: BankData? = null
serializedFinTsModel: String? = null ) : FinTsClientResponse(error, errorMessage, messageLog, finTsModel)
) : FinTsClientResponse(error, errorMessage, messageLog, finTsModel, serializedFinTsModel)

View File

@ -12,21 +12,19 @@ class FinTsModelSerializerTest {
private val serializedBankData = TestDataGenerator.serializedBankData private val serializedBankData = TestDataGenerator.serializedBankData
private val underTest = FinTsModelSerializer()
@Test @Test
fun serializeToJson() { fun serializeToJson() {
val bank = TestDataGenerator.generateBankDataForSerialization() val bank = TestDataGenerator.generateBankDataForSerialization()
val result = underTest.serializeToJson(bank, true) val result = FinTsModelSerializer.serializeToJson(bank, true)
assertEquals(serializedBankData, result) assertEquals(serializedBankData, result)
} }
@Test @Test
fun deserializeFromJson() { fun deserializeFromJson() {
val result = underTest.deserializeFromJson(serializedBankData) val result = FinTsModelSerializer.deserializeFromJson(serializedBankData)
assertNotNull(result) assertNotNull(result)
@ -48,7 +46,7 @@ class FinTsModelSerializerTest {
assertContains(result.supportedJobs, account.allowedJobs) // check that it contains exactly the same object instances assertContains(result.supportedJobs, account.allowedJobs) // check that it contains exactly the same object instances
} }
assertEquals(serializedBankData, underTest.serializeToJson(result, true)) assertEquals(serializedBankData, FinTsModelSerializer.serializeToJson(result, true))
} }
} }