- 개요
// 현재 운영 서비스에 적용되어 있는 극단적인 예시 // if문 지옥 if (!lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) && !lSomeStringField.equalsIgnoreCase(SomeCase) ) { throw new IfException(ERR_CD_PARAM_INVALID, "SomeStringField"); } if ("".equalsIgnoreCase(someStringField2.trim())) { throw new IfException(ERR_CD_PARAM_INVALID, "someStringField2"); } if ("".equalsIgnoreCase(someStringField3.trim())) { throw new IfException(ERR_CD_PARAM_INVALID, "someStringField3"); } if ("".equalsIgnoreCase(someStringField4.trim())) { throw new IfException(ERR_CD_PARAM_INVALID, "someStringField4"); }
위 예시처럼 매우 비효율적인 작업이라 생각해 Annotation을 만들어 한꺼번에 체크할 수 있게 작업 한다면 어떨까 생각하였고, 효율적인 방안이라 생각해 공유한다. - TCP 전문 통신은 일반적으로 미리 정의된 길이에 따라 바이트를 잘라 통신에 사용한다. 서버는 클라이언트로부터 밭은 메시지를 각 필드에 길이 별로 잘라 매치시켜 JAVA Field 로 변환시킨다. 이때 필수값 체크가 필요하다면 파싱 이후에 별도의 메쏘드에서 각 상황에 맞는 필수값 체크 로직을 모두 구현해야 한다. 이때의 문제점은 각 필드 별로 필수값 체크를 따로 모두 진행해야 한다는 점이다. 즉, if 문이 각 필드별로 존재하게 되는 것.
- 개발우선 필드에 명시하기 위한 어노테이션을 생성한다.requiredIn 에 각 전문코드 (이 예제에선 documentCd 로 표현됨.)를 전달받아 전문 타입 별(상황 별)로 필수 값을 조절할 수 있게 세팅한다.POJO
Validation Utility 작성하기아래 소스 validateRequiredFields의 로직은 아래의 주석에 달아 둔 것과 같은 플로우를 가진다.@Required protected String code; @Required protected String version; @Required protected String documentCd; @Required(requiredIn = {"201", "301"}) protected String serialNo;
import java.lang.reflect.Field;
import java.util.Arrays;
public class ValidationUtils {
/**
* annotation (required) 를 이용하는 필드 값의 필수 값 체크
* required annotation 의 requiredIn 필드에 값이 세팅 되어 있는 경우 documentCd 가 requiredIn에 포함된다면 필수값 체크
* required annotation 만 존재한다면 전체 documentCd 에 대해 필수값 체크
* @param obj (Packet)
* @throws IfException
*/
public static void validateRequiredFields(Object obj) throws IfException {
Class<?> clazz = obj.getClass();
while (clazz != null && clazz != Object.class) {
for (Field field : clazz.getDeclaredFields()) { // 1. 해당 오브젝트의 모든 필드 들에 대해
if (field.isAnnotationPresent(Required.class)) { // 2. Required 어노테이션이 존재한다면
Required requiredAnnotation = field.getAnnotation(Required.class);
String[] requiredIn = requiredAnnotation.requiredIn();
try {
Field codeField = clazz.getDeclaredField("documentCd"); // 3. documentCd 값과 requiredIn의 값을 비교하기 위해 documentCd 값 가져오기.
codeField.setAccessible(true);
String code = (String) codeField.get(obj);
// 4-1. required annotation 존재하지만 필수 코드가 없는 경우 -> 전체 상황에 대해 필수.
// 4-2. required annotation 이 존재하며 requiredIn에 값이 있는 경우 documentCd 값이 requiredIn의 값들 중 하나라면
// 5. 필수값 검사
if (requiredIn.length == 0 || Arrays.asList(requiredIn).contains(code)) {
checkIfNull(field, obj);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IfException(NiceErrorCode.ERR_CD_UNKNOWN.getCode());
}
}
}
clazz = clazz.getSuperclass();
}
}
private static void checkIfNull(Field field, Object obj) throws IfException, IllegalAccessException {
field.setAccessible(true);
Object value = field.get(obj);
if (value == null || (value instanceof String && ((String) value).isEmpty())) {
// String 이란 가정하에 String 체크 진행 이하 String이 아닌 Integer 등이라면 아래에 해당 값 검사 추가 가능
throw new IfException(ERR_CD_PARAM_INVALID.getCode(), field.getName());
}
}
}
이제 특정 시점에서 사용자는 해당 Method를 언제든 호출 해 Required 체크를 진행할 수 있게 되었다. 각 상황 별로 validate 메소드를 만들어 if 문 지옥으로 작업하는 방향보다 사용자는 더욱 간단하게 필수값 체크를 진행할 수 있게 되었다.
'로직과의 사투 > Java' 카테고리의 다른 글
자바의 자료구조 Collection Framework (2) - List (0) | 2021.08.09 |
---|---|
자바의 자료구조 Collection Framework (1) - Map (0) | 2021.06.21 |
월요일 기준으로 주차 구하기 java.time (2) | 2021.01.20 |