본문 바로가기

back-end/spring

spring/ JPA를 이용해 json 형태의 컬럼을 RDB에서 편리하게 다루기 | hypersistence-utils - java1.8 환경구성

 

 

 

 

spring/ JPA를 이용해 json 형태의 컬럼을 RDB에서 편리하게 다루기 (hypersistence-utils) - java17

프로젝트 스펙 상 메인 데이터베이스로 MySQL을 사용하고 있다. 하지만 도중에 문항에 대한 답을 매칭시켜 저장해야 하는 상황이 생겼고, 요구사항을 RDB 구조 그대로 가져가면서 충족시키기엔 문

romcanrom.tistory.com

 

이전 글에 이어 기존의 프로젝트에서도 hypersistence-utils를 사용해 json 형태의 컬럼 값을 코드상으로 파싱해오는 과정을 기록한다.

 

 

Project Spec

  • Java 1.8
  • Spring 2.5.8
  • MySQL 8.0.31
  • JPA
  • hibernate 5.4.33

 


개요

 

[{"key_a":5},{"key_b":7},{"key_c":7},{"key_d":7}]

 

기존 진행되던 프로젝트에서는 로그성으로 응답 결과를 위의 형식으로 컬럼에 저장하고 있었다. 해당 컬럼에 대해 insert나 select 작업 시 컬럼 값을 String으로 받고 코드 로직 내부에서 직접 Json 형식을 파싱해오고 있었는데, 코드의 인지 복잡도가 높아지게 되면서 신규 프로젝트에서 사용했던 hypersistence-utils를 기존의 프로젝트에도 적용하기로 했다.

 

상세 내용은 위의 포스팅으로 대체하고, java 1.8 기준에서의 환경 설정 위주로 작성한다.

 


 

java 1.8 기준 hypersistence-utils 환경설정 하기

 

hypersistence-utils 공식 github

 

GitHub - vladmihalcea/hypersistence-utils: The Hypersistence Utils library (previously known as Hibernate Types) gives you Sprin

The Hypersistence Utils library (previously known as Hibernate Types) gives you Spring and Hibernate utilities that can help you get the most out of your data access layer. - GitHub - vladmihalcea/...

github.com

 

  • 이어지는 환경설정 내용은 모두 해당 링크의 가이드에 따라 적용한 것으로, 추후 작동에 문제가 있는 경우 해당 링크의 최신 알림을 확인한다

 


 

build.gradle 의존성 추가

    // hypersistence utils - hibernate 5.4.33 기준
    implementation 'io.hypersistence:hypersistence-utils-hibernate-52:3.5.0'
    implementation 'com.fasterxml.jackson.core:jackson-core:2.15.0'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.0'

 

hypersistence-utils 라이브러리와 함께 json 직렬화에 필요한 jackson을 주입한다.

 


 

package-info.java 파일 생성

 

@TypeDef(
        name = "json", typeClass = JsonType.class
)
package io.hypersistence.optimizer;

import io.hypersistence.utils.hibernate.type.json.JsonType;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;

 

프로젝트의 루트 경로에 위와 같은 내용을 담은 package-info.java 파일을 생성한다. 생성하지 않아도 무방하나, 생성하지 않을 경우 이후 entity 컬럼 설정 시 약간 번거로워진다. 

 


 

@Entity Class 구성 변경

 

@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Entity(name = "TB_JULY_EG")
@TypeDef(name = "json", typeClass = JsonType.class) //기존의 구성에 추가
public class JulyEg {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "IDX")
    private Long idx;
    
    ...
    
    @Type(type = "json") // 기존의 구성에 추가
    @Column(name = "JULY_RESULTS")
    private List<Map<String, Integer>> julyResults; // 컬럼 지정 형식에 맞춰 반환 타입 지정
}



1. hypersistence utils를 적용할 Entity 클래스의 클래스 레벨@TypeDef(name = "json", typeClass = JsonType.class) 어노테이션 추가

 

2. hypersistence utils를 적용할 컬럼 (json 형식의 문자열이 저장된 컬럼)의 필드 레벨@Type(type = "json") 어노테이션 추가

 

위의 두 가지 설정을 해당하는 Entity 클래스에 설정해주면 준비가 완료된다.

 

이후 해당 컬럼을 사용하는 로직에서는 손수 json 파싱 처리를 해줄 필요가 없으며, hypersistence가 그 역할을 위임받아 파싱한 결과를 정한 컬럼 타입으로 반환해준다.

 


* HibernateException 에러가 뜨는 경우

 

Caused by: org.hibernate.HibernateException: The propertyClass in JsonTypeDescriptor is null, hence it doesn't know to what Java Object type to map the JSON column value that was read from the database!

 

환경구성을 마치고, insert 작업까지는 성공했는데 저장된 데이터를 select 하는 과정에서 위의 에러를 마주쳤다. 관련된 정보가 적어 혹시 지정된 컬럼이 DB 상에 null로 저장되어 있는 값이 있어 그런가 해서 초기값도 지정해보고, package-info.java 파일도 일부 수정해보고 했는데 해당 문제는 아니었다.

 

혹시 위와 같은 에러를 마주친다면 @Entity 클래스 레벨에 @TypeDef(name = "json", typeClass = JsonType.class) 어노테이션이 알맞게 지정되어 있고, package-info.java 파일이 알맞은 경로(프로젝트 루트 경로)에 알맞은 내용을 담고 있는지 확인해보자.