JPA를 사용하면서 서버정보를 담고있는 Server Entity의 필드중 하나인 type을 enum타입으로 사용하려고 했다.
위는 ServerType이라는 enum클래스이다. code와 desc 두 개의 필드를 가지고있고, 현재 DB의 컬럼에는 code가 저장되어 있다. 따라서 DB에 INSERT 할 때는 code를 사용하고, SELECT 할 때는 해당 code를 가지고있는 enum객체를 담아주길 원했다.
이대로 Server Entity에 enum ServerType을 컬럼으로 정의하고 실행해 보았다.
특정 조건 없이 findOne을 했을 때 DB에서 가져오는 ServerType의 값이 Entity와 매핑이 되지 않았다.
org.springframework.dao.InvalidDataAccessApiUsageException: No enum constant com.spectra.store.jpo.enums.ServerType.P; nested exception is java.lang.IllegalArgumentException: No enum constant com.spectra.store.jpo.enums.ServerType.P
- DB에서 값을 가져와 Entity로 변환 할 때 기본적으로 enum클래스의 필드 이름인 ServerType.P로 매핑하려 하는데 해당 enum은 ServerType.PRODUCT 이기 때문에 발생하는 에러인 것 같다.
원하는 값을 매핑하기 위해서는 ServerType.PRODUCT의 code에 매핑을 시켜줘야 한다.
이를 간단하게 해결해 주는 AttributeConverter가 존재한다!!
AttributeConverter는 인터페이스로 2개의 메서드가 선언되어있다. 이를 구현하는 자식 클래스를 만들어 재정의 하면 된다.
AttributeConverter를 상속하는 ServerTypeConverter를 만들었고 메서드들을 재정의했다. DB로 저장하기 위해 해당 ServerType.getCode()를 하여 code를 DB에 저장하고, Entity로 변환하기 위해 ServerType(enum)에 ofCode(String code) static 메서드를 만들었다.
그리고 Entity의 ServerType필드에는 @Convert,
ServerTypeConverter에는 @Converter Annotaion을 붙여주면 끝이다!!
이대로 간단하게 끝나면 정말 좋겠지만... 생각을 조금 더 해보면 Enum클래스 마다 ofCode() 메서드와 Converter를 만들어 줘야한다. 필요한 enum클래스가 100개라면 Converter도 100개가 만들어져야한다!!
"불필요하고 반복되는 작업은 개발자를 힘들게해요!!"
현재 반복되는 작업인 AttributeConverter 클래스의 메소드 재정의 부분과 enum의 ofCode() 메서드를 추상화 하여 자식클래스에서 간편하게 사용하도록 만들 것이다.
우선 EnumField 인터페이스를 만들어 getter를 강제하고 enum클래스들이 이를 상속하도록 한다. 이는 밑의 추상화 Converter 클래스에서 다형성을 활용하기 위함이다.
AbstractEnumCodeAttributeConverter 클래스는 이전에 각각의 enum에서 재정의하던 기능들을 추상화 시킨 클래스이다.
반환타입을 보면 <T extends Enum & EnumField>인데 이 의미는 Enum과 EnumField를 동시에 상속받고 구현하는 타입이라는 뜻이다. 결국 ServerType이 반환타입이 되겠다.
이렇게 불특정한 타입이지만 어느정도의 경계는 정해주고 추론 할 수 있도록 해주는 것이 "경계가 있는 타입 파라미터(Bounded Type Parameter)"라고 한다.
ServerTypeConverter클래스는 부모클래스인 AbstractEnumCodeAttributeConverter클래스에 자기 자신을 넘겨 타입을 정의한다.
마지막으로 AbstractEnumCodeAttributeConverter클래스에서 호출하는 EnumBalueUtils 클래스이다. 이는 Util클래스로 final클래스로 정의하고 메서드를 static으로 선언한다.
메서들의 기능을 하나씩 보겠다.
처음에 무지성으로 찾아보며 개발하다가 이렇게 글로 정리하려니 꽤나 힘든 일이다. 하지만 이렇게 정리하니 Converter가 어떤 동작을 하는지 조금은 이해가 가고, 사실 Converter도 중요하지만 Bounded Type Parameter라는 엄청난 수확이 있었던 것 같다.
여기까지 이 글을 읽어주신 분들께 정말 감사하고 피드백 환영입니다!! 글 쓰는 연습좀 더 해야겠습니다...
https://techblog.woowahan.com/2600/ -> AttributeConverter
https://thecodinglog.github.io/java/2020/12/09/java-generic-class.html -> Bounded Type Parameter