[Spring boot] DynamoDB not supported, requires @DynamoDBTyped or @DynamoDBTypeConverted 트러블 슈팅

Byuk_mm·2022년 8월 26일
0

Spring Boot Development

목록 보기
3/13
post-thumbnail
post-custom-banner

Spring Boot 개발 중 학습이 필요한 내용을 정리하고,
트러블 슈팅 과정을 기록하는 포스팅입니다.




✅ Background

Spring boot를 활용해서 RestAPI 개발 중 NosqlDynamoDBEntity를 저장해야할 일이 생겼습니다. AWS의 서비스들은 Spring boot에서 활용하기 쉽도록 라이브러리를 잘 만들어 놓았고, 정식 Docs와 관련 자료도 많아서 활용하기 간편했습니다.

수월하게 개발 중, DynamoDBDynamoDBMapper를 사용해서 간단하게 하나의 객체를 save하는데에서 발생했습니다.

📌 TextMemoState Entity Class

저장하려는 Entity 객체는 아래의 TextMemoState입니다. 해당 EntityRedis에도 저장이 되며, DynamoDB에도 저장이 되는 객체입니다.

@Getter
@RedisHash(value = "text_memo_state")
@DynamoDBTable(tableName = "text_memo_state")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TextMemoState {

    @Id
    @DynamoDBHashKey(attributeName = "id")
    private String id;

    @DynamoDBAttribute
    @Column(name = "individual_video_id")
    protected UUID individualVideoId;

    @DynamoDBAttribute
    @Column(name = "state_json")
    private String stateJson;

    @DynamoDBAttribute
    @Column(name = "video_time")
    private LocalTime videoTime;

    @DynamoDBAttribute
    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdDate;

    @Builder
    public TextMemoState(String id, UUID individualVideoId, String stateJson, LocalTime videoTime) {
        this.id = id;
        this.individualVideoId = individualVideoId;
        this.stateJson = stateJson;
        this.videoTime = videoTime;
        this.createdDate = LocalDateTime.now();
    }
}

📌 DynamoDB Save Method

간단하게 DynamoDBMapper를 활영해서 위의 TextMemoState 하나를 save하는 로직입니다.


@Service
@Transactional
public class TextMemoStateDao {

	private final DynamoDBMapper dynamoDBMapper;

  	// .. 중략

  	public TextMemoState saveToDynamo(TextMemoState textMemoState) {
      dynamoDBMapper.save(textMemoState);
      return textMemoState;
  	}
}



✅ Problem

DynamoDB 가이드 코드를 참고했으며, 크게 어렵지 않고 짧은 코드라 문제 없이 바로 될 것 같았지만 역시나 한번에 되지는 않습니다ㅎㅎ,,

not supported; requires @DynamoDBTyped or @DynamoDBTypeConverted

오류문만 봐도 Type이 호환되지 않아~ 라고 외치는 것 같습니다!


📌 Try 1. Id 문제인듯?

무엇이 문제일까~ 하고 구글링을 해보니 id와 관련된 내용이 나왔습니다.

@Id
@DynamoDBHashKey(attributeName = "id")
private String id;

현재 이 EntityRedis와도 연결이 돼있어서 @Id 어노테이션이 붙어있는데, DynamoDBKey값을 지정해주는 @DynamoDBHashKey 어노테이션이 같이 붙으면서 문제가 발생한 것일 수도 있다고 생각이 됐습니다.

@Id 어노테이션을 지우고 시도하면 Redis 관련 코드부터 오류가 나서 실행되지 않을 것 같았습니다. 때문에 클래스를 분리해서 DynamoDB만의 Entity 클래스를 하나 만들고 시도해봤으나, 같은 오류가 발생했습니다.

그러던 중, AWS 콘솔에서 DynamoDB의 키값의 데이터 타입이 자바 코드 상의 형식과 다르다는 부분을 발견했습니다.
DynamoDB의 키값을 Number 타입으로 지정돼 있었지만, 자바 코드 상의 id는 위 처럼 String 형식이었습니다.

이게 문제였네~ 하고 테이블을 삭제하고 다시 생성했습니다.(한번 테이블을 생성하면 key의 형식을 바꾸지 못한다고 하네요ㅠ)

되겠다 싶어서 돌려봤지만,, 오류는 계속해서 발생했습니다.

(해결하고 나서 생각해봤는데, 이 부분도 분명 문제였습니다!)


📌 Try 2. LocalTime, LocalDateTime 문제인가..?

@DynamoDBAttribute
@Column(name = "video_time")
private LocalTime videoTime;

@DynamoDBAttribute
@CreatedDate
@Column(name = "created_at", updatable = false)
private LocalDateTime createdDate;

구글링을 하면서 여러가지 방법을 보았지만, 저와 비슷한 경우는 아니었습니다. 그러던 중 Time과 관련된 데이터 타입들이 눈에 들어왔습니다. 이러한 데이터 타입들이 자동으로 String으로 변환이 안되는 것이 문제인가 싶었습니다.

아래는 AWS DynamoDb 라이브러리 안의 코드 중 일부입니다.

String/S types,
Character/char
String
java.net.URL
java.net.URI
java.util.Calendar
java.util.Currency
java.util.Date
java.util.Locale
java.util.TimeZone
java.util.UUID
S3Link

Number/N types,
java.math.BigDecimal
java.math.BigInteger
Boolean/boolean
Byte/byte
Double/double
Float/float
Integer/int
Long/long
Short/short

위에 부터 char 타입 ~ S3Link 타입까지는 String 타입으로 변환되며,
BigDecimal 타입 ~ short 타입까지는 Number 타입으로 변환된다고 합니다.

Date, TimeZone 타입은 자동으로 String 타입으로 바뀌지만,
제가 사용하는 LocalTime 타입과 LocalDateTime 타입은 자동으로 String 타입으로 변환되지 않는 것입니다.




✅ Solution

@DynamoDBAttribute
@DynamoDBTyped(DynamoDBMapperFieldModel.DynamoDBAttributeType.S)
@Column(name = "video_time")
private LocalTime videoTime;

@DynamoDBAttribute
@CreatedDate
@DynamoDBTyped(DynamoDBMapperFieldModel.DynamoDBAttributeType.S)
@Column(name = "created_at", updatable = false)
private LocalDateTime createdDate;

EntityLocalTimeLocalDateTime 선언부에 @DynamoDBTyped 어노테이션을 추가했습니다.
해당 어노테이션은 DynamoDB에 저장될 타입을 지정해주는 기능을 합니다.
DynamoDBAttributeType.S 로 타입을 지정함으로써 String형으로 저장되게끔 강제할 수 있습니다.

자바의 데이터 타입과 DB의 데이터 타입이 호환되지 않는 경우는 매우 흔한 경우라 쉽게 파악할 수 도 있었을 것 같은데, Redis와 엮인 문제 같은데? 라는 생각에 잡혀서 길을 돌아온 것 같습니다.

profile
어디야 벽벽 / 블로그 이전 -> byuk.dev
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 6월 8일

dynamodb 테이블을 만들 때 hashkey를 code 상의 hashkey 이름이 일치해야 하는 군요. LocalDataTime 문제도 있었네요. 참고가 많이 되었습니다. 잘 보고 갑니다.

답글 달기