enum으로 legacy code 와 신규 코드 매핑
📌갓블로그 참고
Legacy DB의 JPA Entity Mapping (Enum Converter 편) - 우아한형제들 기술 블로그
1. 기존 코드와 Scrapping 시 보내주는 코드
기존 코드 01, 02, 03... 같은 숫자 코드. 스크래핑시 보내주는 코드는 한글 이름으로 보내줌. ex) 계산서, 수정계산서
2. 신규 코드 enum으로 정의
public enum TaxBillType implements CommonType {
@JsonProperty("세금계산서")
TAX_A("세금계산서", "01"),
@JsonProperty("수정세금계산서")
TAX_B("수정세금계산서", "02"),
@JsonProperty("계산서")
TAX_C("계산서", "01"),
@JsonProperty("수정계산서")
TAX_D("수정계산서", "02");
private String codeName;
private String legacyCodeName;
TaxBillType(String codeName, String legacyCodeName) {
this.codeName = codeName;
this.legacyCodeName = legacyCodeName;
}
@Override
public String getCodeName() {
return this.codeName;
}
@Override
public String getLegacyTxCodeName() {
return this.legacyCodeName;
}
}
@JsonProperty
: json 데이터 속 valuecodeName
: 신규 코드. DB에 저장되는 값legacyCodeName
: 기존 코드. mapping시 신규 코드 값으로 기존 코드값 조회용.
3. Converter
- Java에서는 code값 'REQUEST'
- 신규 scrapping Table에선 '준비'로 저장
- 기존 최종 결과물 Table에선 '01'로 저장
이런 매핑을 도와주는 인터페이스 → AttributeConverter
- 엔티티 필드를 enum으로 정의 후 상단에
@Convert(convert = {컨버터클래스.class})
붙여줌.
@Convert(converter = TaxBillTypeConverter.class)
@Column(name="tax_clsf")
private TaxBillType taxClsf;
- 컨버터 클래스
@Convert
public class TaxBillTypeConverter extends AbstractCommonEnumAttributeConverter<TaxBillType> {
public TaxBillTypeConverter() {
super(TaxBillType.class);
}
}
각 enum에 맞는 converter 생성해줘야함.
- AttributeConverter
각 컨버터는 AbstractCommonEnumAttributeConverter
를 상속받는다. (custom) 이 클래스는 AttributeConverter
를 implements 해준다.
- AttributeConverter
@Getter
public class AbstractCommonEnumAttributeConverter<E extends Enum<E> & CommonType> implements AttributeConverter<E, String> {
/**
* 대상 Enum 클래스의 {@link Class} 객체
*/
private Class<E> targetEnumClass;
public AbstractCommonEnumAttributeConverter(Class<E> targetEnumClass) {
this.targetEnumClass = targetEnumClass;
}
@Override
public String convertToDatabaseColumn(E attribute) {
return CommonEnumValueConvertUtils.toCode(attribute);
}
@Override
public E convertToEntityAttribute(String dbData) {
return CommonEnumValueConvertUtils.ofCode(targetEnumClass, dbData);
}
}
- enum → DB column 값으로 변환
@Override
public String convertToDatabaseColumn(E attribute) {
return CommonEnumValueConvertUtils.toCode(attribute);
}
- DB column 값 → enum으로 변환
@Override
public E convertToEntityAttribute(String dbData) {
return CommonEnumValueConvertUtils.ofCode(targetEnumClass, dbData);
}
→ 변환 하는 과정은 utill로 따로 빼서 작업
- ConverterUtill 클래스
- ofCode
- 해당 코드가 enum에 있는지 확인 후 있으면 enum값으로 return
- 없으면 Exception 처리
public static <T extends Enum<T> & CommonType> T ofCode(Class<T> enumClass, String code){
if(StringUtils.isBlank(code)){
return null;
}
return EnumSet.allOf(enumClass).stream()
.filter(v->v.getCodeName().equals(code))
.findAny()
.orElseThrow(()-> new Exception(String.format("조회된 [%s]에 해당하는 code 값이 %s 에 존재하지 않습니다.", code, enumClass.getSimpleName())));
}
- toCode
- enum 값의 getCode() return
-
public static <T extends Enum<T> & CommonType> String toCode(T enumValue){ if(enumValue == null){ return ""; } return enumValue.getCodeName(); } public static <T extends Enum<T> & CommonType> String toLegacyCode(T enumValue){ if(enumValue == null){ return ""; } return enumValue.getLegacyCodeName(); }
- 신규 테이블 저장용 toCode와 기존 테이블 저장용 toCode 두개 만듦.
- 그럼 자동으로 저장 잘됨 -끗-
문제 발생
Enum에 정의되어있지 않은 값들이 자꾸 들어와서 error를 뱉음..
→ error를 뱉는 건 맞지만.. 일단 정의되지 않은 값도 1차 수신땐 받게 변경
@Getter
public enum TaxKndType implements CommonType {
ENUM_CODE값들..,
DEFAULT_VALUE("", "");
DEFAULT_VALUE
추가- 기존
@JsonProtery
제거하고@JsonCreator
로 변경@JsonCreator public static TaxKndType forValue(String value) { TaxKndType enumValue = Arrays.stream(TaxKndType.values()) .filter(o -> o.getScpCodeName().equals(value)) .findFirst().orElse(DEFAULT_VALUE); if(enumValue.equals(TaxKndType.DEFAULT_VALUE)){ enumValue.scpCodeName = value; } return enumValue; }
- 들어온 값
value
가 enum 안에 codeName과 일치하면 해당 enum return - 없으면
DEFAULT_VALUE
의 codeName에 value값 담고 return - 이렇게 하면 신규 매핑 테이블엔 정의되지 않은 코드값을 보내도 테이블에 담김
- 수신테이블엔 담기지만 후처리시 기존 코드와 대응하는 코드는 정해놓지 않았기 때문에 에러남.
- log 보고 새로운 코드 enum에 추가하면 됨.