Mensajes en PascalCase
¿Cómo acepto mensajes entrantes en formato PascalCase?
Definir un ObjectMapper de Jackson personalizado
IPF actualmente tiene una clase utilitaria llamada SerializationHelper que es un wrapper alrededor de un Jackson ObjectMapper que registra serializadores/deserializadores personalizados. Esto nos permite tener un enfoque consistente al serializar/deserializar mensajes en todo el entorno de IPF.
De forma predeterminada, Jackson admite CamelCase y, por lo tanto, SerializationHelper también solo admite mensajes en CamelCase por defecto. Esto puede cambiarse fácilmente para soportar PascalCase.
Para soportar PascalCase necesita definir una nueva instancia de ObjectMapper con la siguiente propiedad:
private final ObjectMapper pascalCaseMapper = SerializationHelper.objectMapper()
.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE);
Esto luego puede usarse al mapear mensajes hacia/desde sistemas externos dentro del código del connector.
A continuación se muestra un ReceiveConnector y un SendConnector de ejemplo que recibirían o enviarían mensajes en PascalCase respectivamente:
package com.iconsolutions.connector.samples.pascal;
import akka.actor.ActorSystem;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.iconsolutions.common.exception.IconRuntimeException;
import com.iconsolutions.ipf.core.connector.ReceiveConnector;
import com.iconsolutions.ipf.core.connector.ReceiveConnectorBuilderHelper;
import com.iconsolutions.ipf.core.connector.SendConnector;
import com.iconsolutions.ipf.core.connector.SendConnectorBuilderHelper;
import com.iconsolutions.ipf.core.connector.message.MessageHeaders;
import com.iconsolutions.ipf.core.connector.message.TransportMessage;
import com.iconsolutions.ipf.core.connector.transport.ConnectorTransport;
import com.iconsolutions.ipf.core.connector.transport.ReceiveConnectorTransport;
import com.iconsolutions.ipf.core.shared.correlation.CorrelationId;
import com.iconsolutions.ipf.core.shared.domain.context.ProcessingContext;
import com.iconsolutions.ipf.core.shared.domain.context.UnitOfWorkId;
import com.iconsolutions.ipf.payments.domain.clearing_and_settlement.pacs002.FIToFIPaymentStatusReport;
import com.iconsolutions.ipf.payments.domain.clearing_and_settlement.pacs008.FIToFICustomerCreditTransfer;
import com.iconsolutions.ipf.payments.domain.payment_initiation.pain001.CustomerCreditTransferInitiation;
import com.iconsolutions.samplesystems.shared.model.header.CryptoHelper;
import com.iconsolutions.simulator.api.RequestHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
@Slf4j
public class PascalConnectors {
/**
* Here set the UPPER_CASE_CAMEL (PascalCase) naming strategy
* on your ObjectMapper instance
*/
private final ObjectMapper pascalCaseMapper = SerializationHelper.objectMapper()
.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE);
// tag::receiveConnector[]
@Bean
public ReceiveConnector<CustomerCreditTransferInitiation> executePaymentReceiveConnector(
ReceiveConnectorTransport initPaymentReceiveConnectorTransport,
RequestHandler someRequestHandler,
ActorSystem actorSystem) {
return ReceiveConnector.<CustomerCreditTransferInitiation>builder("InitPaymentReceive", "initpayment.receive-connector", actorSystem)
.withMessageLogger(m -> log.debug("Receive connector has identified message: {}", m.getMessage()))
.withProcessingContextExtractor(tm -> ProcessingContext.builder()
.unitOfWorkId(UnitOfWorkId.createRandom())
.build())
.withConnectorTransport(initPaymentReceiveConnectorTransport)
.withReceiveTransportMessageConverter(message -> this.convertResponse(message.getPayload().toString()))
.withReceiveHandler((context, payload) -> someRequestHandler.process(payload))
.build();
}
// end::receiveConnector[]
/**
* Here you would convert the incoming PAIN001 JSON message in Pascal format into your PAIN001 domain object
*/
public CustomerCreditTransferInitiation convertResponse(String messageText) {
try {
return pascalCaseMapper.readValue(messageText, CustomerCreditTransferInitiation.class);
} catch (JsonProcessingException e) {
throw new IconRuntimeException(e);
}
}
@Bean
public SendConnector<FIToFIPaymentStatusReport, FIToFIPaymentStatusReport> executePaymentSendConnector(
ConnectorTransport<FIToFIPaymentStatusReport> executePaymentReceiveConnectorTransport,
ActorSystem actorSystem) {
return SendConnector
.<FIToFIPaymentStatusReport, FIToFIPaymentStatusReport>builder("ExecutePaymentSend", "executepayment.send-connector", actorSystem)
.withMessageLogger(m -> log.debug("Send connector has identified message: {}", m.getMessage()))
.withCorrelationIdExtractor(it -> CorrelationId.of(it.getTxInfAndSts().get(0).getOrgnlTxId()))
.withConnectorTransport(executePaymentReceiveConnectorTransport)
.withSendTransportMessageConverter(this::convertToTransport)
.build();
}
/**
* Here you would convert the PACS002 domain object into Pascal formatted JSON before sending out
*/
public TransportMessage convertToTransport(FIToFIPaymentStatusReport response) {
try {
return new TransportMessage(new MessageHeaders(CryptoHelper.messageHeaders()), pascalCaseMapper.writeValueAsString(response));
} catch (JsonProcessingException e) {
throw new IllegalStateException(e);
}
}
}