JPA/JPA Basic

[JPA] 엔티티(Entity)가 기본생성자를 가져야 하는 이유 ( Reflection )

IT록흐 2023. 5. 25. 21:02
반응형

 

조회시 사용되는 엔티티(Entity)는 기본생성자를 가지고 있어야 한다.

 

@Entity
@Data
public class Member {
    @Id
    public String name;
    public int age;

    public Member() {} //반드시 필요!

    public Member(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

 

이유가 무엇일까?

 

◎ Reflection

 

 

EntityManger가 조회(find)를 요청하면 1차캐시에 원하는 엔티티가 없는 경우 DB에 SELECT문을 실행하여 조회한다. 그리고 결과를 1차캐시에 저장하고 엔티티 객체를 생성하여 반환(return)한다. 즉, 프로그램 실행 중에 동적으로 엔티티 객체를 생성해야 한다.

 

동적으로 객체를 생성하는 방법에는 두 가지가 있다.

 

① new 연산자

② Reflection

 

JPA는 new 연산자가 아닌 Reflection을 사용한다. Reflection을 사용하는 이유는 '문자열'로 클래스를 탐색하여 객체를 생성하기에 컴파일 단계에서 에러를 뱉지 않는다. new 연산자는 원하는 클래스를 import하지 않으면 컴파일과정에서 에러가 발생한다. 

 

TestMain 클래스 

public class TestMain {
    public static void main(String[] args) {
        Test test = new Test(); // new 연산자
    }
}

 

Test 객체를 new 연산자로 만들고 컴파일을 시도해보았다.

 

 

can not find symbol이 발생한다. 그럼 Reflection을 보자.

 

import java.lang.reflect.Constructor;

public class ReflectionMain {
    public static void main(String[] args) {

        try {
            Class<?> clazz = Class.forName("org.example.reflection.Test"); // 문자열로 클래스 탐색
            Constructor<?> constructor = clazz.getConstructor(); // 탐색된 클래스의 생성자 호출
            Object object = constructor.newInstance(); // 호출된 생성자로 동적으로 객체생성
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

 

원하는 클래스를 '문자열'로 탐색하기에 원하는 클래스파일을 import하지 않아도 컴파일 과정에서 에러가 발생하지 않는다. 

 

 

컴파일 단계에서 발생가능한 에러를 런타임 단계로 미루는 것이다. 이는 엄청난 유연성을 제공한다.

 

JPA는 엔티티를 자동으로 생성하여 클라이언트에 넘겨주어야 한다. 그런데 엔티티는 계속 새로 추가되고 컴파일 단계마다 엔티티를 관리해주어야 한다면 비효율일 수밖에 없다. Reflection은 엔티티가 계속 추가되어도 코드 수정없이 엔티티를 동적으로 생성할 수 있다. 클라이언트가 원하는 엔티티 클래스타입을 넘겨주면 JPA가 엔티티를 탐색한다. 

 

entityManager.find(Member.class,"member2")

 

클라이언트는 Reflection이 엔티티 클래스를 탐색할 수 있도록  find 메소드에 파라미터로 클래스타입을 넣어주어야 한다.

 

 

 엔티티(Entity)가 기본생성자를 가지고 있어야 하는 이유 

 

 

출처

 

JPA를 구현하는 Hibernate는 Reflection을 이용하여 객체를 동적으로 생성하는데, constructor.newInstance()로 객체를 생성한다. 그러므로 엔티티는 아규먼트 없는 기본생성자를 무조건 가지고 있어야 한다.  대신 Reflection은 클래스의 메타데이터에 접근하여 필드에 직접 데이터를 주입한다.

 

 

 

 

Reflection은 기본생성자로 객체를 생성하고 필드에는 메타데이터와 어노테이션을 분석하여 테이블의 컬럼과 매핑되는 데이터를 저장한다. 그리고 클라이언트에게 엔티티를 반환한다.

 

이처럼 JPA는 Reflection을 사용하여 객체를 동적으로 생성한다. 어노테이션부터 동적쿼리생성까지 JPA에는 Reflection 개념이 사용되는 부분이 많아 상당히 중요한 개념이다.

 

 


 

참고자료

 

자바 리플렉션(Reflection) 사용

자바의 리플렉션 http://ktko.tistory.com/152?category=629345 에서 리플렉션에 대한 개념? 에 대해 잠깐 포스팅하였습니다.자바 리플렉션 어디에 쓸까 ? 프로젝트 런타임에 클래스의 구조를 코딩으로 파악

ktko.tistory.com

 

[Java] 29. Reflection 기능을 사용하는 방법 - Class편

안녕하세요. 명월입니다. 이 글은 Java에서의 Reflection 기능을 사용하는 방법 - Class편에 대한 글입니다. Reflection이란 클래스의 구조를 분석하여 동적 로딩을 가능하게 하는 기능입니다. 라고 설명

nowonbun.tistory.com

 

Why does Hibernate require no argument constructor?

The no-argument constructor is a requirement (tools like Hibernate use reflection on this constructor to instantiate objects). I got this hand-wavy answer but could somebody explain further?

stackoverflow.com

 

4장. 영속 클래스들

Persistent classes are classes in an application that implement the entities of the business problem (e.g. Customer and Order in an E-commerce application). Not all instances of a persistent class are considered to be in the persistent state. For example,

docs.jboss.org

 

반응형