❗️문제 코드
public enum ContentType {
APPLICATION_JSON("application/json"),
APPLICATION_X_WWW_FORM_URLENCODED("application/x-www-form-urlencoded");
private final String value;
ContentType(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
❗️오류 상황
AI를 이용한 사내 캘린더 만들기 프로젝트에서 팀 캘린더에 웹훅을 등록하는 기능을 postman으로 테스트하던 중 오류가 발생했다.
POST /api/notification/webhook
{
"calendarId": 1,
"payloadUrl": "https://example.com/webhook",
"contentType": "application/json"
}
❗️오류 문구 : org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type 'com.elice.iliceworksbe.common.constant.ContentType' from String "application/x-www-form-urlencoded": not one of the values accepted for Enum class: [APPLICATION_X_WWW_FORM_URLENCODED, APPLICATION_JSON]
💡오류 원인:
ContentType이 Enum타입인데, JSON에서 "application/json" 값을 받았지만, ContentType Enum에서는 APPLICATION_X_WWW_FORM_URLENCODED, APPLICATION_JSON 값만 유효함.
-> Enum이 허용하는 값과 실제 JSON에서 온 값이 다르기 때문에 Spring이 변환할 수 없어서 예외(HttpMessageNotReadableException)가 발생함.
@JsonValue@JsonCreator사용
public enum ContentType {
APPLICATION_JSON("application/json"),
APPLICATION_X_WWW_FORM_URLENCODED("application/x-www-form-urlencoded");
private final String value;
ContentType(String value) {
this.value = value;
}
@JsonValue //JSON 직렬화 시 사용
public String getValue() {
return value;
}
@JsonCreator //JSON 역직렬화시 사용
public static ContentType fromValue(String value) {
for (ContentType type : ContentType.values()) {
if (type.value.equalsIgnoreCase(value)) {
return type;
}
}
throw new BaseException(ErrorCode.INVALID_CONTENT_TYPE);
}
}
❓선택 이유
Json 요청과 응답에서 application/json 유지됨
Enum 내부적으로는 APPLICATION_JSON을 유지하여 코드의 가독성을 높임
| 구분 | 설명 | 예시 |
|---|---|---|
| 직렬화 (Serialization) | Java 객체 → JSON 변환 | API 응답 시 (@ResponseBody) |
| 역직렬화 (Deserialization) | JSON → Java 객체 변환 | API 요청 처리 (@RequestBody) |
@PostMapping
public ResponseEntity<String> receiveWebhook(@RequestBody Map<String, Object> requestBody) {
try {
// 요청 본문에서 contentType 추출
String contentTypeValue = (String) requestBody.get("contentType");
// ContentType Enum으로 변환
ContentType contentType = ContentType.fromValue(contentTypeValue);
// Dto 변환 처리
return ResponseEntity.ok("Received: " + contentType);
} catch (Exception e) {
return ResponseEntity.badRequest().body("Invalid content type");
}
}
❗️ 유지보수가 어렵고 비효율적
public enum ContentType {
@JsonProperty("application/x-www-form-urlencoded")
APPLICATION_X_WWW_FORM_URLENCODED,
@JsonProperty("application/json")
APPLICATION_JSON
}
❗️ 직렬화는 가능하지만 역직렬화는 제대로 작동하지 않을 가능성이 크다.
직렬화할 때는 "application/json"으로 변환되어 정상작동하지만
역직렬화할 때는 application/json -> APPLICATION_JSON으로 변환되지 않아 오류 발생(HttpMessageNotReadableException)
public enum ContentType {
APPLICATION_JSON("application/json"),
APPLICATION_X_WWW_FORM_URLENCODED("application/x-www-form-urlencoded");
private final String value;
ContentType(String value) {
this.value = value;
}
@JsonEnumDefaultValue
public static final ContentType DEFAULT = APPLICATION_JSON;
}
❗️잘못된 값을 보내도 예외가 발생하지 않아 디버깅 어려움
💡
@JsonValue와@JsonCreator를 사용한다.
- JSON에서 "application/json"을 그대로 받아서 APPLICATION_JSON으로 변환 가능
- JSON 응답에서도 "application/json"이 유지됨
- Enum을 그대로 사용할 수 있어 코드 가독성이 높음