enum으로 legacy code 와 신규 코드 매핑

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;
    }
}
  1. @JsonProperty : json 데이터 속 value
  2. codeName : 신규 코드. DB에 저장되는 값
  3. legacyCodeName : 기존 코드. mapping시 신규 코드 값으로 기존 코드값 조회용.

3. Converter

  • Java에서는 code값 'REQUEST'
  • 신규 scrapping Table에선 '준비'로 저장
  • 기존 최종 결과물 Table에선 '01'로 저장

이런 매핑을 도와주는 인터페이스 → AttributeConverter

  1. 엔티티 필드를 enum으로 정의 후 상단에 @Convert(convert = {컨버터클래스.class}) 붙여줌.
    @Convert(converter = TaxBillTypeConverter.class)
    @Column(name="tax_clsf")
    private TaxBillType taxClsf;
  1. 컨버터 클래스
@Convert
public class TaxBillTypeConverter extends AbstractCommonEnumAttributeConverter<TaxBillType> {
    public TaxBillTypeConverter() {
        super(TaxBillType.class);
    }
}

각 enum에 맞는 converter 생성해줘야함.

  1. 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로 따로 빼서 작업

  1. 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에 추가하면 됨.