From 016442973e050bff743cfcfab3e4c5be5517f414 Mon Sep 17 00:00:00 2001 From: johngreen Date: Thu, 30 Apr 2026 06:41:15 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20ObjectMapper=20=EC=97=90=20JavaTimeModul?= =?UTF-8?q?e=20=EB=93=B1=EB=A1=9D=20(OffsetDateTime=20=EC=A7=81=EB=A0=AC?= =?UTF-8?q?=ED=99=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 증상: POST /api/ai-agents 가 500 으로 응답. 원인: 커스텀 @Bean ObjectMapper 가 Spring Boot 자동 모듈 등록을 가로 막아 java.time.OffsetDateTime (AiAgent.created_at/updated_at 등) 직렬화 실패. INSERT 자체는 성공했으나 응답 변환에서 깨짐. - JacksonConfig: registerModule(new JavaTimeModule()) + WRITE_DATES_AS_TIMESTAMPS=false (ISO-8601 문자열 출력) - GlobalExceptionHandler: 직전 디버그 메시지 노출 원복 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../main/java/com/erp/config/GlobalExceptionHandler.java | 8 +------- .../src/main/java/com/erp/config/JacksonConfig.java | 8 +++++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend-spring/src/main/java/com/erp/config/GlobalExceptionHandler.java b/backend-spring/src/main/java/com/erp/config/GlobalExceptionHandler.java index 0650f57a..1085973e 100644 --- a/backend-spring/src/main/java/com/erp/config/GlobalExceptionHandler.java +++ b/backend-spring/src/main/java/com/erp/config/GlobalExceptionHandler.java @@ -33,13 +33,7 @@ public class GlobalExceptionHandler { public ResponseEntity> handleException(Exception e, HttpServletRequest request) { log.error("Unhandled exception", e); - // QA 진단 임시 — root cause class + message 노출 (안정화 후 원복 예정) - String detail = e.getClass().getSimpleName() + ": " + (e.getMessage() != null ? e.getMessage() : "no message"); - Throwable cause = e.getCause(); - if (cause != null) { - detail += " | caused by " + cause.getClass().getSimpleName() + ": " + cause.getMessage(); - } return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(ApiResponse.error("[DEBUG] " + detail, request.getRequestURI())); + .body(ApiResponse.error("서버 내부 오류가 발생했습니다.", request.getRequestURI())); } } diff --git a/backend-spring/src/main/java/com/erp/config/JacksonConfig.java b/backend-spring/src/main/java/com/erp/config/JacksonConfig.java index ff6f11b4..c58c33a7 100644 --- a/backend-spring/src/main/java/com/erp/config/JacksonConfig.java +++ b/backend-spring/src/main/java/com/erp/config/JacksonConfig.java @@ -1,8 +1,9 @@ package com.erp.config; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -13,6 +14,11 @@ public class JacksonConfig { public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); + // Java 8 date/time (OffsetDateTime, LocalDateTime 등) 직렬화 지원. + // 커스텀 ObjectMapper 빈이 있으면 Spring Boot 자동 구성 모듈 등록이 적용되지 + // 않으므로 명시적으로 등록한다. + mapper.registerModule(new JavaTimeModule()); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return mapper; } }