diff --git a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/MessageCodec.java b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/MessageCodec.java index f3b84de..e699fbe 100644 --- a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/MessageCodec.java +++ b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/MessageCodec.java @@ -1,24 +1,133 @@ package com.klaro.acquirecore.framework; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.stereotype.Component; -/** - * 레거시 {@code msg_layout.h} 고정길이 전문(電文) 코덱의 Spring 빈 자리표시자. - * - *

실 전환에서는 고정길이(positional) 바이트 레이아웃 ↔ DTO 바인딩을 담당한다 - * (BeanIO 또는 커스텀 코덱). 지금은 스켈레톤이 빈으로 뜨는지만 증명한다. - */ -@Component -public class MessageCodec { +import java.util.Map; - /** 고정길이 필드를 우측을 공백으로 채워 정규화한다 (자리표시자 구현). */ - public String padRight(String value, int width) { - if (value == null) { - value = ""; +/** + * Message codec interface and JSON implementation. + * Provides encoding/decoding of TxRequest and TxResponse. + */ +public interface MessageCodec { + + byte[] encodeRequest(TxRequest request); + TxRequest decodeRequest(byte[] data); + byte[] encodeResponse(TxResponse response); + TxResponse decodeResponse(byte[] data); + String getContentType(); + + @Component + class JsonMessageCodec implements MessageCodec { + + private final ObjectMapper objectMapper; + + public JsonMessageCodec() { + this.objectMapper = new ObjectMapper() + .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false) + .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); } - if (value.length() >= width) { - return value.substring(0, width); + + @Override + public byte[] encodeRequest(TxRequest request) { + try { + return objectMapper.writeValueAsBytes(new RequestDto( + request.getServiceName(), + request.getPayload(), + request.getContext() != null ? request.getContext().getTxnId() : null + )); + } catch (JsonProcessingException e) { + throw new CodecException("Failed to encode request", e); + } + } + + @Override + public TxRequest decodeRequest(byte[] data) { + try { + RequestDto dto = objectMapper.readValue(data, RequestDto.class); + return new TxRequest(dto.serviceName, dto.payload, null); + } catch (JsonProcessingException e) { + throw new CodecException("Failed to decode request", e); + } + } + + @Override + public byte[] encodeResponse(TxResponse response) { + try { + return objectMapper.writeValueAsBytes(new ResponseDto( + response.getResult().name(), + response.getResult().getCode(), + response.getData(), + response.getErrorMessage() + )); + } catch (JsonProcessingException e) { + throw new CodecException("Failed to encode response", e); + } + } + + @Override + public TxResponse decodeResponse(byte[] data) { + try { + ResponseDto dto = objectMapper.readValue(data, ResponseDto.class); + return new TxResponse( + TxCore.TxResult.fromCode(dto.resultCode), + dto.data, + dto.errorMessage + ); + } catch (JsonProcessingException e) { + throw new CodecException("Failed to decode response", e); + } + } + + @Override + public String getContentType() { + return "application/json"; + } + + public T decode(byte[] data, Class type) { + try { + return objectMapper.readValue(data, type); + } catch (JsonProcessingException e) { + throw new CodecException("Failed to decode data", e); + } + } + + private static class RequestDto { + public String serviceName; + public Map payload; + public Long txnId; + + public RequestDto() {} + + public RequestDto(String serviceName, Map payload, Long txnId) { + this.serviceName = serviceName; + this.payload = payload; + this.txnId = txnId; + } + } + + private static class ResponseDto { + public String result; + public int resultCode; + public Map data; + public String errorMessage; + + public ResponseDto() {} + + public ResponseDto(String result, int resultCode, Map data, String errorMessage) { + this.result = result; + this.resultCode = resultCode; + this.data = data; + this.errorMessage = errorMessage; + } + } + } + + class CodecException extends RuntimeException { + public CodecException(String message, Throwable cause) { + super(message, cause); } - return String.format("%-" + width + "s", value); } }