CAP Java에서 @On 어노테이션 이름이 틀리면 생기는 일
CAP for Java에서 커스텀 Action 핸들러를 구현할 때 @On 어노테이션의 이름이 CDS 서비스 정의와 정확히 일치하지 않으면 핸들러가 전혀 실행되지 않습니다. 오류 메시지도 없고 예외도 발생하지 않습니다. Action을 호출하면 빈 응답만 반환됩니다. 이 침묵의 실패를 디버깅하는 데 많은 시간을 낭비할 수 있습니다.
문제 시나리오: 핸들러 이름 불일치
// CDS 서비스 정의
service OrdersService {
entity Orders as projection on db.Orders;
// Action 이름: confirmOrder (camelCase)
action confirmOrder(orderId: String) returns Orders;
}
// 잘못된 핸들러: 이름 대소문자 불일치
@Component
@ServiceName("OrdersService")
public class OrdersHandler implements EventHandler {
// "ConfirmOrder" — 대문자 C, 등록 안 됨
@On(event = "ConfirmOrder", service = "OrdersService")
public void handleConfirmOrder(ActionEventContext ctx) {
// 이 코드는 절대 실행되지 않음
// 오류도 없음, 그냥 무시됨
ctx.setResult(Map.of("status", "confirmed"));
}
}
// 올바른 핸들러: CDS와 정확히 동일한 이름
@Component
@ServiceName("OrdersService")
public class OrdersHandler implements EventHandler {
// "confirmOrder" — CDS와 동일
@On(event = "confirmOrder", service = "OrdersService")
public void handleConfirmOrder(ActionEventContext ctx) {
// 정상 실행됨
String orderId = (String) ctx.getParameterInfo().getParam("orderId");
// 비즈니스 로직
ctx.setResult(processOrder(orderId));
}
}
올바른 Action 핸들러 구조
// CDS 정의
service ShipmentService {
entity Shipments as projection on db.Shipments;
action dispatchShipment(
shipmentId : String,
carrierId : String,
trackingNo : String
) returns Shipments;
action cancelShipment(
shipmentId : String,
reason : String
) returns Shipments;
}
@Component
@ServiceName("ShipmentService")
public class ShipmentHandler implements EventHandler {
@Autowired
PersistenceService persistenceService;
// Action 이름이 CDS와 완전 일치해야 함
@On(event = "dispatchShipment", service = "ShipmentService")
public void onDispatchShipment(ActionEventContext ctx) {
// 파라미터 읽기
var params = ctx.getParameterInfo();
String shipmentId = (String) params.getParam("shipmentId");
String carrierId = (String) params.getParam("carrierId");
String trackingNo = (String) params.getParam("trackingNo");
// 유효성 검사
if (shipmentId == null || carrierId == null) {
throw new ServiceException(ErrorStatuses.BAD_REQUEST,
"shipmentId와 carrierId는 필수입니다.");
}
// 비즈니스 로직
var update = Update.entity(Shipments_.class)
.data(Map.of(
"status", "DISPATCHED",
"carrierId", carrierId,
"trackingNo", trackingNo,
"dispatchedAt", LocalDate.now().toString()
))
.byId(shipmentId);
persistenceService.run(update);
// 업데이트된 엔티티 반환
var result = persistenceService.run(
Select.from(Shipments_.class).byId(shipmentId)
);
ctx.setResult(result.single(Shipments.class));
}
@On(event = "cancelShipment", service = "ShipmentService")
public void onCancelShipment(ActionEventContext ctx) {
String shipmentId = (String) ctx.getParameterInfo().getParam("shipmentId");
String reason = (String) ctx.getParameterInfo().getParam("reason");
var update = Update.entity(Shipments_.class)
.data(Map.of(
"status", "CANCELLED",
"cancelReason", reason,
"cancelledAt", LocalDate.now().toString()
))
.byId(shipmentId);
persistenceService.run(update);
var result = persistenceService.run(
Select.from(Shipments_.class).byId(shipmentId)
);
ctx.setResult(result.single(Shipments.class));
}
}
핸들러 등록 확인 방법
// 서버 시작 로그에서 핸들러 등록 확인
// 로그 레벨을 DEBUG로 설정 (application.properties)
// logging.level.com.sap.cds=DEBUG
// 정상 등록 시 로그:
// [INFO] Registered handler 'dispatchShipment' for service 'ShipmentService'
// [INFO] Registered handler 'cancelShipment' for service 'ShipmentService'
// 누락 시: 해당 로그가 없음
// 테스트로 확인 (가장 확실한 방법)
@SpringBootTest
class ShipmentHandlerTest {
@Autowired
private ShipmentService shipmentService;
@Test
void testDispatchShipmentHandlerRegistered() {
// Action이 올바르게 처리되면 오류 없이 결과 반환
assertDoesNotThrow(() -> {
shipmentService.run(
ActionInput.create("dispatchShipment")
.param("shipmentId", "SHP-001")
.param("carrierId", "DHL")
.param("trackingNo", "DHL123456")
);
});
}
}
핵심 체크리스트
- @On의 event 이름이 CDS 서비스의 Action 이름과 대소문자까지 동일한가
- @ServiceName이 CDS 서비스 이름과 일치하는가
- 서버 시작 로그에서 핸들러 등록 확인
- 단위 테스트로 Action 핸들러 동작 검증
공식 문서
CAP Java Action 핸들러 구현 가이드는 cap.cloud.sap/docs/java/event-handlers에서 확인하세요.
댓글 0
아직 댓글이 없습니다.