Using now MapStruct for mapping JSON entities
This commit is contained in:
parent
82485a29b1
commit
474d4d1f91
|
@ -24,6 +24,9 @@ ext {
|
|||
textInfoExtractorVersion = "1.0.1"
|
||||
|
||||
|
||||
mapStructVersion = "1.4.0.Beta3"
|
||||
|
||||
|
||||
hbci4jVersion = '3.1.37'
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
|
||||
sourceCompatibility = "1.7"
|
||||
|
@ -16,6 +17,10 @@ compileTestKotlin {
|
|||
dependencies {
|
||||
implementation project(':BankingUiCommon')
|
||||
|
||||
implementation("org.mapstruct:mapstruct:$mapStructVersion")
|
||||
|
||||
kapt("org.mapstruct:mapstruct-processor:$mapStructVersion")
|
||||
|
||||
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package net.dankito.banking.persistence
|
||||
|
||||
import net.dankito.banking.persistence.mapper.EntitiesMapper
|
||||
import net.dankito.banking.persistence.mapper.CustomerConverter
|
||||
import net.dankito.banking.persistence.model.CustomerEntity
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.ui.model.Customer
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
import net.dankito.banking.util.ISerializer
|
||||
import net.dankito.utils.multiplatform.Month
|
||||
import org.mapstruct.factory.Mappers
|
||||
import java.io.FileOutputStream
|
||||
import java.net.URL
|
||||
|
||||
|
@ -17,7 +17,7 @@ open class BankingPersistenceJson(
|
|||
protected val serializer: ISerializer
|
||||
) : IBankingPersistence {
|
||||
|
||||
protected val mapper = EntitiesMapper()
|
||||
protected val mapper = Mappers.getMapper(CustomerConverter::class.java)
|
||||
|
||||
|
||||
init {
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package net.dankito.banking.persistence.mapper
|
||||
|
||||
import net.dankito.banking.persistence.model.AccountTransactionEntity
|
||||
import net.dankito.banking.persistence.model.BankAccountEntity
|
||||
import net.dankito.banking.persistence.model.CustomerEntity
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
import net.dankito.banking.ui.model.Customer
|
||||
import org.mapstruct.*
|
||||
|
||||
|
||||
@Mapper
|
||||
abstract class CustomerConverter {
|
||||
|
||||
// Context is needed to fix cycle dependencies issue
|
||||
|
||||
protected val bankAccountCustomerField = BankAccount::class.java.getDeclaredField(BankAccount::customer.name)
|
||||
|
||||
|
||||
init {
|
||||
bankAccountCustomerField.isAccessible = true
|
||||
}
|
||||
|
||||
|
||||
@Mapping(source = "technicalId", target = "id")
|
||||
abstract fun mapToEntity(customer: Customer, @Context context: CycleAvoidingMappingContext): CustomerEntity
|
||||
|
||||
@InheritInverseConfiguration
|
||||
abstract fun mapCustomer(customer: CustomerEntity, @Context context: CycleAvoidingMappingContext): Customer
|
||||
|
||||
abstract fun mapCustomers(customers: List<Customer>, @Context context: CycleAvoidingMappingContext): List<CustomerEntity>
|
||||
|
||||
open fun mapCustomers(customers: List<Customer>): List<CustomerEntity> {
|
||||
// create a new context instance each time as otherwise just cached instance would be taken und BankAccounts and AccountTransactions would never get updated
|
||||
return mapCustomers(customers, CycleAvoidingMappingContext())
|
||||
}
|
||||
|
||||
abstract fun mapCustomerEntities(customers: List<CustomerEntity>, @Context context: CycleAvoidingMappingContext): List<Customer>
|
||||
|
||||
open fun mapCustomerEntities(customers: List<CustomerEntity>): List<Customer> {
|
||||
// create a new context instance each time as otherwise just cached instance would be taken und BankAccounts and AccountTransactions would never get updated
|
||||
return mapCustomerEntities(customers, CycleAvoidingMappingContext())
|
||||
}
|
||||
|
||||
|
||||
@Mapping(source = "technicalId", target = "id")
|
||||
abstract fun mapBankAccount(account: BankAccount, @Context context: CycleAvoidingMappingContext): BankAccountEntity
|
||||
|
||||
@InheritInverseConfiguration
|
||||
abstract fun mapBankAccount(account: BankAccountEntity, @Context context: CycleAvoidingMappingContext): BankAccount
|
||||
|
||||
abstract fun mapBankAccounts(accounts: List<BankAccount>, @Context context: CycleAvoidingMappingContext): List<BankAccountEntity>
|
||||
|
||||
abstract fun mapBankAccountEntities(accounts: List<BankAccountEntity>, @Context context: CycleAvoidingMappingContext): List<BankAccount>
|
||||
|
||||
@AfterMapping
|
||||
open fun mapBankAccountCustomer(serializedAccount: BankAccountEntity, @MappingTarget account: BankAccount, @Context context: CycleAvoidingMappingContext) {
|
||||
val mappedCustomer = mapCustomer(serializedAccount.customer, context)
|
||||
|
||||
bankAccountCustomerField.set(account, mappedCustomer)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Mapping(source = "technicalId", target = "id")
|
||||
abstract fun mapTransaction(transaction: AccountTransaction, @Context context: CycleAvoidingMappingContext): AccountTransactionEntity
|
||||
|
||||
@InheritInverseConfiguration
|
||||
fun mapTransaction(transaction: AccountTransactionEntity, @Context context: CycleAvoidingMappingContext): AccountTransaction {
|
||||
val account = mapBankAccount(transaction.bankAccount, context)
|
||||
|
||||
val mappedTransaction = AccountTransaction(account, transaction.amount, transaction.currency, transaction.unparsedUsage, transaction.bookingDate,
|
||||
transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, transaction.bookingText,
|
||||
transaction.valueDate, transaction.statementNumber, transaction.sequenceNumber, transaction.openingBalance, transaction.closingBalance,
|
||||
transaction.endToEndReference, transaction.customerReference, transaction.mandateReference, transaction.creditorIdentifier, transaction.originatorsIdentificationCode,
|
||||
transaction.compensationAmount, transaction.originalAmount, transaction.sepaUsage, transaction.deviantOriginator, transaction.deviantRecipient,
|
||||
transaction.usageWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement, transaction.currencyType, transaction.bookingKey,
|
||||
transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution, transaction.supplementaryDetails,
|
||||
transaction.transactionReferenceNumber, transaction.relatedReferenceNumber)
|
||||
|
||||
mappedTransaction.technicalId = transaction.id
|
||||
|
||||
return mappedTransaction
|
||||
}
|
||||
|
||||
abstract fun mapTransactions(transactions: List<AccountTransaction>, @Context context: CycleAvoidingMappingContext): List<AccountTransactionEntity>
|
||||
|
||||
abstract fun mapTransactionEntities(transactions: List<AccountTransactionEntity>, @Context context: CycleAvoidingMappingContext): List<AccountTransaction>
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package net.dankito.banking.persistence.mapper
|
||||
|
||||
import org.mapstruct.BeforeMapping
|
||||
import org.mapstruct.MappingTarget
|
||||
import org.mapstruct.TargetType
|
||||
import java.util.*
|
||||
|
||||
|
||||
open class CycleAvoidingMappingContext {
|
||||
|
||||
private val knownInstances: MutableMap<Any, Any> = IdentityHashMap()
|
||||
|
||||
|
||||
/**
|
||||
* Gets an instance out of this context if it is already mapped.
|
||||
*/
|
||||
@BeforeMapping
|
||||
open fun <T> getMappedInstance(source: Any, @TargetType targetType: Class<T>): T {
|
||||
return targetType.cast(knownInstances[source])
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts an instance into the cache, so that it can be remembered to avoid endless mapping.
|
||||
*/
|
||||
@BeforeMapping
|
||||
open fun storeMappedInstance(source: Any, @MappingTarget target: Any) {
|
||||
knownInstances[source] = target
|
||||
}
|
||||
|
||||
}
|
|
@ -107,7 +107,7 @@ class BankingPersistenceJsonTest {
|
|||
createCustomer(2),
|
||||
createCustomer(3)
|
||||
)
|
||||
val serializableCustomers = Mappers.getMapper(CustomerConverter::class.java).mapToEntities(customers, CycleAvoidingMappingContext())
|
||||
val serializableCustomers = Mappers.getMapper(CustomerConverter::class.java).mapCustomers(customers, CycleAvoidingMappingContext())
|
||||
|
||||
serializer.serializeObject(serializableCustomers, file)
|
||||
|
||||
|
|
Loading…
Reference in New Issue