AttributeConverter <X, Y>

조갱·2022년 2월 26일
0

kotlin

목록 보기
2/10

Spring Security와 Attribute Converter (이곳을 클릭 하지 마세요! 아직 글 못썼습니다 ㅠㅠ) 이슈에 대한 글을 적다가, 글의 내용이 너무 방대해져 포스팅을 나누어서 하려고 한다.

1. AttriuteConverter 란?

Attribute Converter는 javax.persistence 패키지에 정의된 interface로 EntityDB 사이에서 데이터를 변환하는 역할을 한다.

2. 제네릭 타입

Attribute Converter는 <X,Y>로 2개의 제네릭 타입을 받고있다.
X: entity의 타입
Y: DB의 타입
이다.

3. 메소드

Attribute Converter 정의된 메소드는 딱 2가지인데

public Y convertToDatabaseColumn(X attribute);
public X convertToEntityAttribute(Y dbData);

가 있다. 메소드 명이 직관적이기 때문에 의미를 바로 파악할 수 있겠지만, 굳이 설명하자면 Entity <-> DB 사이를 변환하는 메소드이다.

4. 사용법

4-1. gradle 설정

AttributeConverter<>javax.persistence패키지에 포함된 인터페이스이다.
따라서 아래와 같이 gradle에 depencency를 추가해준다.

4-1-1. Gradle (kotlin)

Spring : implementation("javax.persistence:javax.persistence-api:2.2")
SpringBoot : implementation("org.springframework.boot:spring-boot-starter-data-jpa:2.6.4")

4-1-2. Gradle

Spring : implementation 'javax.persistence:javax.persistence-api:2.2'
SpringBoot : implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.6.4'

4-1-3. Maven

Spring :

<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence-api</artifactId>
    <version>2.2</version>
</dependency>

SpringBoot :

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.6.4</version>
</dependency>

4-2. Class 정의

우선, AttributeConverter<X, Y>를 상속받는 클래스를 정의한다.
나는 MutableList <> String 간에 JSON Serialize / Deserialize 를 하기 때문에 jackson 라이브러리를 추가로 사용했다.

package 패키지명

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import import javax.persistence.*

class MutableListConverter() : AttributeConverter<MutableList<Long>, String> {
    private val mapper: ObjectMapper = ObjectMapper()

    override fun convertToDatabaseColumn(attribute: MutableList<Long>?): String {
        return mapper.writeValueAsString(attribute)
    }

    override fun convertToEntityAttribute(dbData: String?): MutableList<Long> {
        return mapper.readValue(dbData ?: "", object : TypeReference<MutableList<Long>>() {})
    }
}

4-3. Annotation 적용

package 패키지명

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import import javax.persistence.*

@Entity
@Table(name = "FAVORITE")
data class FavoriteEntity(
	// 생성자
    
    @Column(name = "product_id_list")
    @Convert(converter = MutableListConverter::class)
    var productIdList: MutableList<Long> = mutableListOf()
) {
    // 클래스 내부
    // 메소드 정의 등
}

class MutableListConverter() : AttributeConverter<MutableList<Long>, String> {
    private val mapper: ObjectMapper = ObjectMapper()

    override fun convertToDatabaseColumn(attribute: MutableList<Long>?): String {
        return mapper.writeValueAsString(attribute)
    }

    override fun convertToEntityAttribute(dbData: String?): MutableList<Long> {
        return mapper.readValue(dbData ?: "", object : TypeReference<MutableList<Long>>() {})
    }
}

실제로 사용중인 코드의 일부이다.
AttributeConverter<X, Y>를 상속하여 Converter를구현한 뒤,
Entity에 @Convert(converter = 클래스) 어노테이션을 붙여주기면 하면 된다.

Entity에 List형태로 값을 쓰면(add(), remove()...) DB에는 MutableListConverter 에 정의된 convertToDatabaseColumn 를 거쳐 String 형태로 저장된다.

반대로 DB에서 값을 읽어오면(repository.findById 등) convertToEntityAttribute를 통해 MutableList<> 형태로 Entity에 할당된다.

profile
A fast learner.

0개의 댓글