public interface NewBusinessDtoMapper {
NewBusinessDto mapToDto(IbOffer quotation);
}
Quotation
IPM DTO Mapping
This document explains how IOS offers (IbOffer
and subclasses) are mapped to IPM DTOs for both new business and policy changes.
The key extension points are the following interfaces, which you can implement to provide your own mapping logic.
Interfaces for Mapping
New Business
The NewBusinessDtoMapper
maps an IbOffer
to a NewBusinessDto
(used when creating a new policy in IPM).
Change Policy
The ChangePolicyRequestDtoMapper
maps an IbOffer
to a ChangePolicyRequestDto
(used when endorsing or changing an existing policy in IPM).
public interface ChangePolicyRequestDtoMapper {
ChangePolicyRequestDto mapToDto(IbOffer quotation);
}
By implementing these interfaces, you can provide fully custom transformations from IOS domain objects to the IPM DTOs. The resulting mapper classes are then used by the relevant policy services to submit or change policies in IPM.
Composite Mappers for LOB-Specific Implementations
Different lines of business (LOB) often require distinct mapping logic.
Rather than implementing a single mapper for all scenarios across multiple LOBs, you can define individual LOB-specific mappers.
A composite mapper then automatically selects the appropriate mapper at runtime based on the LOB identifier (lobId
).
This pattern is equally applicable to issuing new policies and handling policy changes.
For implementation details, see CompositeNewBusinessDtoMapper
and CompositeChangePolicyRequestDtoMapper
.
Example: New Business Mapping
CompositeNewBusinessDtoMapper
holds a set of NewBusinessDtoMapper
implementations, each tied to a particular lobId
.
When mapToDto is called, it dispatches to the correct mapper based on the offer’s lobId.
To register your mapper for a specific LOB, create a Spring bean using an instance of a CompositeNewBusinessDtoMapper.Registration
:
import de.faktorzehn.ios.ipm.shared.MapperRegistrationFactory;
@Configuration
public class FnIosIpmConfiguration {
@Bean
CompositeNewBusinessDtoMapper.Registration fnCompositeNewBusinessDtoMapperRegistration(
NewBusinessMapperRegistrationFactory newBusinessMapperRegistrationFactory,
FnLobConfig lobConfig,
@Value("${ipm.tenant:1}") String ipmTenantId
) {
var contractBundleMapper = FnContractBundleToDtoMapper
.asFunctionWith(ToDtoMappingContext.with(LocaleContextHolder.getLocale()));
MappingRule<NewBusinessDto> contractBundleWithVariedBaseMappingRule = NewBusinessMappingRules
.contractBundleWithVariedBaseMappingRule(contractBundleMapper);
String lobId = lobConfig.getLobId();
return newBusinessMapperRegistrationFactory.create(lobId, $ -> ipmTenantId,
List.of(contractBundleWithVariedBaseMappingRule));
}
}
By defining this bean, the mapper is automatically registered and picked up by the composite mapper at runtime.
Fine-Grained Customization with MappingRules
In many cases, you don’t need to implement an entire mapper from scratch.
Instead, you can reuse or combine existing mapping logic through MappingRule
implementations.
A MappingRule
represents a single, reusable mapping step, making it easy to customize or extend mapping logic without duplicating code.
Using MappingRule
based Mappers
The following example demonstrates how to use the MappingRuleBasedNewBusinessDtoMapper
to assemble custom mappings from multiple mapping rules:
@Bean
CompositeNewBusinessDtoMapper.Registration hmCompositeNewBusinessDtoMapperRegistration(HmLobConfig lobConfig,
@Value("${ipm.tenant:1}") String ipmTenantId) {
MappingRule<NewBusinessDto> contractBundleMappingRule = (quotation, parentDto) -> {
parentDto.setLobId(lobConfig.getLobId());
parentDto.setTenantId(ipmTenantId);
var contractBundleCopy = (ExtContractBundle)quotation
.getChosenVariantExisting()
.getContractBundle().copyAndReplaceProductWithVariedBase();
var contractBundleDto = new HmContractBundleToDtoMapper()
.createDto(contractBundleCopy, ToDtoMappingContext.with(LocaleContextHolder.getLocale()));
parentDto.setContractBundle(contractBundleDto);
};
// replace default with lob-specific previous policy info mapper
MappingRule<NewBusinessDto> previousPolicyInfoMappingMethod = (quotation, dto) -> {
var previousPolicyInfo = new HmPreviousPolicyInfoToDtoMapper()
.createDto(quotation.getPreviousPolicyInfo(),
ToDtoMappingContext.with(LocaleContextHolder.getLocale()));
dto.setPreviousPolicyInfo(previousPolicyInfo);
};
var newBusinessMapper = new MappingRuleBasedNewBusinessDtoMapper(
List.of(previousPolicyInfoMappingMethod,
MappingRules.correspondenceRecipient(NewBusinessDto::setCorrespondenceRecipient),
MappingRules.premiumPayer(NewBusinessDto::setPremiumPayer),
MappingRules.intermediary(NewBusinessDto::setIntermediary),
MappingRules.applicationData(NewBusinessDto::setApplicationData),
MappingRules.issuanceType(NewBusinessDto::setIssuanceType),
contractBundleMappingRule));
return new CompositeNewBusinessDtoMapper.Registration(lobConfig.getLobId(), newBusinessMapper);
}
In this example:
-
Shared mapping logic such as
correspondenceRecipient
,premiumPayer
,intermediary
,applicationData
, andissuanceType
is provided via reusableMappingRules
factory methods. -
Business-specific rules like
contractBundleMappingRule
(mapping the contract bundle using a LOB-specific DTO mapper) andpreviousPolicyInfoMappingMethod
(using a custom previous policy info mapper) allow for targeted customization per LOB.
This approach offers a powerful yet flexible way to assemble a DTO mapper using a combination of common rules and line-of-business-specific logic.
You can combine this flexibility with structured configuration by registering the rule-based mapper through a CompositeNewBusinessDtoMapper.Registration
.
This enables automated selection of the appropriate mapper at runtime, based on the lobId
, while keeping the mapping logic modular and maintainable.