코틀린 @get
을 사용하여 entity를 구현하였는데, @GeneratedValue
앞에 붙이지 않아서 save() 시 id를 assign 해주지 않았다는 에러가 발생하였다.
// 문제상황 코드
@Entity
@Entity
open class Example {
@get:Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@get:Column(name = "example_id", nullable = false)
open var id: Long? = null
...
그래서 @GeneratedValue
앞에 @get
을 선언해줌으로써 문제를 해결했는데,
정확한 이슈 발생이유와 해결방안이 이해가 가지 않았다.
@get
이 정확히 어떤 이유로 사용되는지 이해하지 못했다.@get
어노테이션이 왜 필요한가? 라는 의문이 있었다.@get
을 사용하면서 @Id
가 getter 메서드 위에 선언되어 사용되는 것이였다.@Id
가 적용되었는데 어떻게 동작하고 있지? 란 의문이에 관해 jpa 접근 전략과 코틀린의 프로터피 개념에 대해 먼저 정리해보았다.
그 후 이슈 발생이유와 해결방안을 다시 정리해보겠다.
JPA가 Entity에 접근하는 방법은 2가지다.
@Access(AccessType.FEILD)
@Access(AccessType.PROPERTY)
@Access
어노테이션이 선언되어 있지 않으면,@Id
어노테이션이 선언된 위치(필드, getter)에 따라 access 방식이 설정된다.
/** 필드 접근 방식 */
@Entity
public class Member {
@Id
private Long id;
private String name;
}
/** 프로퍼티 접근 방식 */
@Entity {
private Long id;
private String namel
@Id
public String getId() {
return this.id;
}
}
class Jordan {
var name: String = "Jordan"
var age: Int = 20
}
//@file:JvmName("AppKta" ) // 생성되는 클래스 파일 이름 지정
annotation class TA ()
// 예시 어노테이션
annotation class TA1()
class ClassA (
@field:TA val first: String,
@get:TA val second: String, // property getter
@set:TA var second1: String, // property setter
@property:TA val fourth: Long, // are not visible to Java
@param:TA val fifth: String, // constructor의 parameter
@setparam:TA var sixth: String, // setter의 parameter...set ( value )
@property:[TA TA1] val seventh: String, // 다수의 Use-site Target annotation 적용 방법1
@property:TA @property:TA1 val eighth: String // 다수의 Use-site Target annotation 적용 방법2
) {}
어노테이션에 대한 자세한 설명은 https://logictocore.tistory.com/50 참고
// 문제 상황
@Entity
open class Example {
@get:Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@get:Column(name = "example_id", nullable = false)
open var id: Long? = null
...
@get
이 @GeneratedValue
앞에 선언되지 않았다.@get
어노테이션으로 인해 JPA에서 프로퍼티 전략을 사용하여 entity에 접근하게 되고,@GeneratedValue
만 선언되고, @Id
와 @Colum
은 getter에 선언된다. ⇒ 그래서 프로퍼티 전략으로 인해 필드에 선언된 @GeneratedValue
가 적용되지 않았던 것이다.// 문제상황 자바코드
public class Example {
@GeneratedValue(
strategy = GenerationType.IDENTITY
)
@Nullable
private Long id;
...
@Id
@Column(
name = "example_id",
nullable = false
)
@Nullable
public Long getId() {
return this.
}
...
@GeneratedValue
에 get 어노테이션을 적용시킨다.
// 해결 코드
@Entity
open class Example {
@get:Id
@get:GeneratedValue(strategy = GenerationType.IDENTITY)
@get:Column(name = "example_id", nullable = false)
open var id: Long? = null
...
// 자바 코드
public class Example {
@Nullable
private Long id;
...
@Id
@GeneratedValue(
strategy = GenerationType.IDENTITY
)
@Column(
name = "example_id",
nullable = false
)
@Nullable
public Long getId() {
return this.id;
}
...
Intellij generated 기능을 사용해서 entity를 생성했을 때 @get
이 붙여서 생성된다.
@get
의 사용법을 알지 못한 상태에서 이슈가 발생하여 @get
에 대해 정확히 알게 되었고, 그래서 현재 상황에서 @get
을 사용하는 이유가 궁금했다.
일단 entity에 get을 사용한 예시를 찾아보려 했는데, 아무리 구글링을 해보아도 찾지 못했다.
현재 getter를 통해서 하이버네이트 관련 어노테이션만 적용하고 있고, getter 로직 내에 별도의 비즈니스 코드를 사용하고 있는것도 아니다. 즉, @get
이 없이도 사용가능한데 왜 사용하고 있는지 궁금했다.
그리고 프로퍼티 접근보다 필드 접근 방식을 더 선호한다는 아래와 같은 글을 찾았다.
참고 https://thorben-janssen.com/access-strategies-in-jpa-and-hibernate/
5번째 이유인,, 프로퍼티 접근 방식을 사용했을때 예상치 못한 위험이 발생할 수 있다고 하니깐… 안전하게 필드 접근 방식을 사용하는게 어떤가 생각하였다.