Spring Cassandra UDT converting 삽질 과정
안녕하세요.
Spring Data Cassandra 를 사용하면서 삽질한 과정을 정리해보고자 합니다.
우선 배경설명을 드리겠습니다.
Spring cassandra 2.6.11
CREATE TABLE table (
partition_key text,
clusering_key_1 text,
detail frozen<Detail>,
primary key (partition_key, clusering_key_1)
) with clustering order by (clustering_key_1 desc);
CREATE TYPE Detail (
name text,
male boolean
)
테이블은 위와 같이 구성되어 있으며,
UDT (user defined type) 은 Detail 이라는 이름으로 생성했습니다.
제가 접한 문제점은
CassandraRepository 의 save() (혹은 CassnadraTemplate 의 insert() ) 과정에 있어,
UDT인 Detail 이 converting 을 수행할 수 없다는 오류였습니다.
GenericConverionService 에서
sourceType 으로는 제가 정의한 클래스가,
targetType 으로는 UdtValue 인터페이스가 정의가되어
둘이 매칭이 되지 않은 NO_MATCH 상태가 되고, converting 을 할 수 없다고 에러를 발생시킨것입니다.
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type
위와 같은 문제를 해결한 과정과 원인에 대해서 설명을 드리겠습니다.
문제가 된 부분은 바로
@CassandraType(type = CassandraType.Name.UDT)
해당 어노테이션 이었습니다.
Spring Cassandra 에서 UDT type 을 사용할 때는 Embedded 방식을 사용하게 되는데,
이때 Class 상위에
@UserDefinedType
어노테이션을 붙혀 해당 클래스가 UDT 로 활용됨을 명시합니다.
그러나 저는 여기서 Embedded 되는 클래스 가 선언된 클래스내에서도
위에서 문제가 된 어노테이션을 선언해주었습니다.
Cassandra Config 과정에서 선언된 MappingCassandraConverter 가
@CassandraColumnType 으로 명시된 field 들을 불러와
해당 필드의 타입을 source 로, 선언한 어노테이션 안의 타입을 target 으로 선언하게 되는데요,
이때 Name.UDT 의 대상은 UdtValue 인터페이스가 되고, 어노테이션의 대상이 되는 필드는 Detail 이라는 클래스 이므로,
이 둘을 converting 할 수 있는 방법이 없어 예외가 발생하는 것 입니다.
우리가 UDT 타입을 쓰면서도 원하는 것은
클래스 자체보다는 embedded 된 클래스 내부의 필드이므로,
내부 필드들이 convert 될 수 있게
@CassandraType 어노테이션만 지운다면 해당 문제는 해결됩니다.