스프링 - PostgreSQL text[] 타입을 엔티티의 List<String> 필드에 매핑하기

2025. 2. 2. 21:33· Spring
목차
  1. 개요
  2. 사용자 정의 Hibernate UserType: StringArrayType 구현
  3. 엔티티 클래스에 List<String> 필드 추가
  4. Reference

스프링 - PostgreSQL text[] 타입을 엔티티의 List 필드에 매핑하기

 

작성 일자 : 2025년 02월 02일


 

Image illustrated by Dalle3

 

 

개요

 

PostgreSQL에서는 text[] 타입과 같은 배열 타입을 기본으로 지원합니다.

 

이를 활용하면 @ElementCollection을 사용하는 방법과는 다르게 별도의 조인 테이블을 생성하지 않고도 여러 값을 하나의 컬럼에 저장할 수 있습니다.

 

하지만, Hibernate는 기본적으로 List<String>과 PostgreSQL의 text[] 타입을 매핑할 수 없기 때문에 직접 변환 로직을 구현해주어야 합니다.

 


 

 

사용자 정의 Hibernate UserType: StringArrayType 구현

 

먼저, Java의 List과 PostgreSQL의 text[] 사이의 변환을 담당하는 사용자 정의 UserType을 만들어 보겠습니다.

import java.io.Serializable;
import java.sql.Array;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserType;

public class StringArrayType implements UserType<List<String>> {

    @Override
    public int getSqlType() {
        return Types.ARRAY;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Class<List<String>> returnedClass() {
        return (Class<List<String>>) (Class<?>) List.class;
    }

    @Override
    public boolean equals(List<String> x, List<String> y) {
        return Objects.equals(x, y);
    }

    @Override
    public int hashCode(List<String> x) {
        return x == null ? 0 : x.hashCode();
    }

    @Override
    public List<String> nullSafeGet(ResultSet rs, int position,
            SharedSessionContractImplementor session, Object owner) throws SQLException {
        Array array = rs.getArray(position);
        if (array == null) {
            return null;
        }
        return Arrays.asList((String[]) array.getArray());
    }

    @Override
    public void nullSafeSet(PreparedStatement st, List<String> value, int index,
            SharedSessionContractImplementor session) throws SQLException {
        if (st != null) {
            if (value != null) {
                try (var connection = session.getJdbcConnectionAccess().obtainConnection()) {
                    Array array = connection.createArrayOf("text", value.toArray());
                    st.setArray(index, array);
                }
            } else {
                st.setNull(index, Types.ARRAY);
            }
        }
    }

    @Override
    public List<String> deepCopy(List<String> value) {
        return value == null ? null : List.copyOf(value);
    }

    @Override
    public boolean isMutable() {
        return true;
    }

    @Override
    public Serializable disassemble(List<String> value) {
        return (Serializable) value;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<String> assemble(Serializable cached, Object owner) {
        return (List<String>) cached;
    }

    @Override
    public List<String> replace(List<String> detached, List<String> managed, Object owner) {
        return deepCopy(detached);
    }

    @Override
    public JdbcType getJdbcType(TypeConfiguration typeConfiguration) {
        return typeConfiguration.getJdbcTypeRegistry().getDescriptor(getSqlType());
    }

    @Override
    public long getDefaultSqlLength(Dialect dialect, JdbcType jdbcType) {
        return 255L;
    }

    @Override
    public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) {
        return 0;
    }

    @Override
    public int getDefaultSqlScale(Dialect dialect, JdbcType jdbcType) {
        return 0;
    }
}

 


 

 

엔티티 클래스에 List<String> 필드 추가

 

다음으로, 엔티티 클래스에 List<String> 타입의 필드를 추가하고, @Type 어노테이션을 사용하여 사용자 정의 UserType을 지정해줍니다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "sample_entities")
public class SampleEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /*
     * PostgreSQL의 text[] 컬럼과 매핑됩니다.
     */
    @Type(StringArrayType.class)
    @Column(name = "string_array", columnDefinition = "text[]", nullable = false)
    private List<String> stringArray;

}

 

  • @Type 어노테이션을 사용하여 Hibernate에게 해당 필드가 사용자 정의 StringArrayType을 이용해 매핑되어야 함을 알려줍니다.
  • columnDefinition 속성을 사용하여 실제 데이터베이스 컬럼이 PostgreSQL의 text[] 타입임을 명시합니다.

 


Reference

  • Github - Deltafi
 

deltafi/deltafi-core/src/main/java/org/deltafi/core/types/hibernate/StringArrayType.java at 18b4ef67e7eb2da185b6ba52fedb0036bfb6

DeltaFi is a flexible, code-light data transformation and normalization platform. - deltafi/deltafi

github.com

 

저작자표시 (새창열림)
  1. 개요
  2. 사용자 정의 Hibernate UserType: StringArrayType 구현
  3. 엔티티 클래스에 List<String> 필드 추가
  4. Reference
'Spring' 카테고리의 다른 글
  • 스프링 - Flyway BeanCreationException 해결 방법
  • ShadcnUI - Drawer 또는 Dialog 위의 sonner 클릭 안되는 문제 해결하기
  • 스프링 - RabbutMQ Retry 정책 설정하기(ft. 10만원의 교훈)
  • 스프링 - Redission 분산락으로 동시성 문제 해결하기 예시
gerrymandering
gerrymandering
gerrymandering
gerrymandering
gerrymandering
전체
오늘
어제
  • 분류 전체보기 (84)
    • SOLID 원칙 (6)
    • 번역 (4)
    • Nginx (1)
    • Tailwind CSS (1)
    • AWS (7)
      • DMS를 사용한 RDS to OpenSearch .. (3)
      • ECS를 이용한 Blue-Green 무중단 배포 .. (7)
    • NextJS (7)
    • 기타 (12)
    • Prompt Engineering (6)
    • 읽어볼만한 글 (3)
      • 기술 (0)
      • 쓸만한 툴 (0)
      • 아이템 (0)
      • 웹 디자인 (0)
      • 기타 (3)
    • Cloud Architecture (5)
    • Trouble Shooting (9)
    • Spring (11)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

최근 댓글

최근 글

글쓰기 / 관리자
hELLO · Designed By 정상우.v4.2.1
gerrymandering
스프링 - PostgreSQL text[] 타입을 엔티티의 List<String> 필드에 매핑하기
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.