diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc index 331d26d4e..fadd5f797 100644 --- a/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc +++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanProductDataV1.avsc @@ -657,6 +657,17 @@ "null", "boolean" ] + }, + { + "default": null, + "name": "customData", + "type": [ + "null", + { + "values": "bytes", + "type": "map" + } + ] } ] } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java index 531f1b355..73990337d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java @@ -38,6 +38,7 @@ public interface LoanAccountDataMapper { @Mapping(target = "purchasePriceRatio", ignore = true) @Mapping(target = "delinquent.installmentDelinquencyBuckets", ignore = true) @Mapping(target = "customData", ignore = true) + @Mapping(target = "product.customData", ignore = true) LoanAccountDataV1 map(LoanAccountData source); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanProductDataMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanProductDataMapper.java index 4daae8e58..72e0f3c25 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanProductDataMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanProductDataMapper.java @@ -22,9 +22,11 @@ import org.apache.fineract.avro.loan.v1.LoanProductDataV1; import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroMapperConfig; import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; @Mapper(config = AvroMapperConfig.class) public interface LoanProductDataMapper { + @Mapping(target = "customData", ignore = true) LoanProductDataV1 map(LoanProductData source); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/AbstractLoanBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/AbstractBusinessEventWithCustomDataSerializer.java similarity index 79% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/AbstractLoanBusinessEventSerializer.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/AbstractBusinessEventWithCustomDataSerializer.java index f9e32aa17..c3c3d6934 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/AbstractLoanBusinessEventSerializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/AbstractBusinessEventWithCustomDataSerializer.java @@ -16,17 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan; +package org.apache.fineract.infrastructure.event.external.service.serialization.serializer; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; -import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer; -import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; -public abstract class AbstractLoanBusinessEventSerializer> implements BusinessEventSerializer { +public abstract class AbstractBusinessEventWithCustomDataSerializer> implements BusinessEventSerializer { protected Map collectCustomData(final T event) { return getExternalEventCustomDataSerializers().stream().collect(HashMap::new, (map, serializer) -> { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java index 117b3f4b2..792d60809 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java @@ -29,6 +29,7 @@ import org.apache.fineract.avro.loan.v1.LoanInstallmentDelinquencyBucketDataV1; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBusinessEvent; import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanAccountDataMapper; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.AbstractBusinessEventWithCustomDataSerializer; import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer; import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService; @@ -47,7 +48,8 @@ import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class LoanBusinessEventSerializer extends AbstractLoanBusinessEventSerializer implements BusinessEventSerializer { +public class LoanBusinessEventSerializer extends AbstractBusinessEventWithCustomDataSerializer + implements BusinessEventSerializer { private final LoanReadPlatformService service; private final LoanAccountDataMapper mapper; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java index 433f0df78..72345015b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java @@ -26,6 +26,7 @@ import org.apache.fineract.avro.loan.v1.LoanChargeDataV1; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanChargeBusinessEvent; import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanChargeDataMapper; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.AbstractBusinessEventWithCustomDataSerializer; import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService; @@ -33,7 +34,7 @@ import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class LoanChargeBusinessEventSerializer extends AbstractLoanBusinessEventSerializer { +public class LoanChargeBusinessEventSerializer extends AbstractBusinessEventWithCustomDataSerializer { private final LoanChargeReadPlatformService service; private final LoanChargeDataMapper mapper; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanProductBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanProductBusinessEventSerializer.java index 5a1345c8e..fc70978f9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanProductBusinessEventSerializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanProductBusinessEventSerializer.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan; +import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.avro.generic.GenericContainer; import org.apache.fineract.avro.generator.ByteBufferSerializable; @@ -25,17 +26,19 @@ import org.apache.fineract.avro.loan.v1.LoanProductDataV1; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.product.LoanProductBusinessEvent; import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanProductDataMapper; -import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.AbstractBusinessEventWithCustomDataSerializer; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class LoanProductBusinessEventSerializer implements BusinessEventSerializer { +public class LoanProductBusinessEventSerializer extends AbstractBusinessEventWithCustomDataSerializer { private final LoanProductReadPlatformService service; private final LoanProductDataMapper mapper; + private final List> externalEventCustomDataSerializers; @Override public boolean canSerialize(BusinessEvent event) { @@ -46,11 +49,18 @@ public class LoanProductBusinessEventSerializer implements BusinessEventSerializ public ByteBufferSerializable toAvroDTO(BusinessEvent rawEvent) { LoanProductBusinessEvent event = (LoanProductBusinessEvent) rawEvent; LoanProductData data = service.retrieveLoanProduct(event.get().getId()); - return mapper.map(data); + final LoanProductDataV1 loanProductDataV1 = mapper.map(data); + loanProductDataV1.setCustomData(collectCustomData(event)); + return loanProductDataV1; } @Override public Class getSupportedSchema() { return LoanProductDataV1.class; } + + @Override + protected List> getExternalEventCustomDataSerializers() { + return externalEventCustomDataSerializers; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanTransactionBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanTransactionBusinessEventSerializer.java index 808aafca7..6d2b303e2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanTransactionBusinessEventSerializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanTransactionBusinessEventSerializer.java @@ -26,6 +26,7 @@ import org.apache.fineract.avro.loan.v1.LoanTransactionDataV1; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionBusinessEvent; import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanTransactionDataMapper; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.AbstractBusinessEventWithCustomDataSerializer; import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer; import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData; @@ -35,7 +36,7 @@ import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class LoanTransactionBusinessEventSerializer extends AbstractLoanBusinessEventSerializer +public class LoanTransactionBusinessEventSerializer extends AbstractBusinessEventWithCustomDataSerializer implements BusinessEventSerializer { private final LoanReadPlatformService service; diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanProductBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanProductBusinessEventSerializerTest.java new file mode 100644 index 000000000..c3937d1ef --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanProductBusinessEventSerializerTest.java @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.fineract.avro.loan.v1.LoanProductDataV1; +import org.apache.fineract.infrastructure.event.business.domain.loan.product.LoanProductBusinessEvent; +import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanProductDataMapper; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; +import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; +import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@MockitoSettings(strictness = Strictness.LENIENT) +@ExtendWith(MockitoExtension.class) +class LoanProductBusinessEventSerializerTest { + + @Mock + private LoanProductReadPlatformService loanProductReadPlatformService; + @Mock + private LoanProductDataMapper loanProductDataMapper; + + private LoanProductBusinessEventSerializer serializer; + + @BeforeEach + void setUp() { + final List> externalEventCustomDataSerializers = List + .of(new ExternalEventCustomDataSerializer<>() { + + @Override + public ByteBuffer serialize(final LoanProductBusinessEvent event) { + return ByteBuffer.wrap("test_data_for_loan_product".getBytes(UTF_8)); + } + + @Override + public String key() { + return "test_key_1"; + } + }, new ExternalEventCustomDataSerializer<>() { + + @Override + public ByteBuffer serialize(final LoanProductBusinessEvent event) { + return ByteBuffer.wrap("test_data_for_loan_product_1".getBytes(UTF_8)); + } + + @Override + public String key() { + return "test_key_1"; + } + }, new ExternalEventCustomDataSerializer<>() { + + @Override + public ByteBuffer serialize(final LoanProductBusinessEvent event) { + return ByteBuffer.wrap("test_data_for_loan_product_2".getBytes(UTF_8)); + } + + @Override + public String key() { + return "test_key_2"; + } + }); + serializer = new LoanProductBusinessEventSerializer(loanProductReadPlatformService, loanProductDataMapper, + externalEventCustomDataSerializers); + } + + @Test + void testLoanProductCustomDataSerialization() { + final long productId = 1; + + final LoanProduct loanProduct = mock(LoanProduct.class); + final LoanProductData loanProductData = mock(LoanProductData.class); + final LoanProductBusinessEvent event = mock(LoanProductBusinessEvent.class); + + when(loanProductReadPlatformService.retrieveLoanProduct(productId)).thenReturn(loanProductData); + when(loanProduct.getId()).thenReturn(productId); + when(event.get()).thenReturn(loanProduct); + + final LoanProductDataV1 expectedAvroData = LoanProductDataV1.newBuilder().setId(productId).setCustomData(new HashMap<>()).build(); + when(loanProductDataMapper.map(any(LoanProductData.class))).thenReturn(expectedAvroData); + + final LoanProductDataV1 result = (LoanProductDataV1) serializer.toAvroDTO(event); + + assertNotNull(result); + assertNotNull(result.getCustomData()); + final Map customData = result.getCustomData(); + assertEquals("test_data_for_loan_product_1", new String(customData.get("test_key_1").array(), UTF_8)); + assertEquals("test_data_for_loan_product_2", new String(customData.get("test_key_2").array(), UTF_8)); + } + +}