ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Reflection API ?
    ☕️ java 2023. 2. 9. 19:43

    📌 Reflection API


    💡 구체적인 클래스 타입을 알지 못해도 그 클래스의 정보(메서드, 타입, 변수 등등)에 접근할 수 있게 해주는 자바 API

     

    📌 Reflection API 기능


    Person.java

    public class Person {
      private String name;
      protected String address;
      public int age;
    }

     

    필드 접근

    • Class<T> 클래스의 getFields() 메서드
      • public으로 선언된 필드만 조회가 가능
    • Class<T> 클래스의 getDeclaredFields() 메서드

     

    Test

      @Test
      void get_field() {
        Object person = new Person();
    
        Field[] getFields = person.getClass().getFields();
    
        Field[] getDeclaredFields = person.getClass().getDeclaredFields();
    
        System.out.println("-- getFields() --");
        for (Field field : getFields) {
          System.out.println(field.getName());
        }
    
        System.out.println("-- getDeclaredFields() --");
        for (Field field : getDeclaredFields) {
          System.out.println(field.getName());
        }
    
        List<String> fieldNames = getFieldNames(getFields);
        List<String> declaredFieldNames = getFieldNames(getDeclaredFields);
        
        assertTrue(declaredFieldNames
            .containsAll(Arrays.asList("name", "address", "age")));
        assertFalse(fieldNames
            .containsAll(Arrays.asList("name", "address", "age")));
        assertTrue(fieldNames
            .containsAll(Arrays.asList("age")));
      }

     

    결과

    -- getFields() --
    age
    -- getDeclaredFields() --
    name
    address
    age

     

    인스턴스 생성

    • getConstructor()
      • 타입을 명시해 원하는 생성자 조회
      • 해당하는 생성자가 없을 수도 있기 때문에 try-catch 문을 사용해야 한다.
    • newInstance()
      • 가져온 생성자의 newInstance() 메서드를 사용해 인스턴스를 생성할 수 있다.

     

    Person.java

    public class Person {
    
      private String name;
      protected String address;
      public int age;
      
      public Person() {
      }
    
      public Person(String name, int age) {
        this.name = name;
        this.age = age;
      }
    
      public Person(String name, String address, int age) {
        this.name = name;
        this.address = address;
        this.age = age;
      }

     

    Test

      @Test
      void new_instance() {
        
        Class<Person> clazz = Person.class;
    
        try {
          Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
          Person beomsic = constructor.newInstance("beomsic", 20);
    
          assertNotNull(beomsic);
          assertEquals("beomsic", beomsic.getName());
        } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
          e.printStackTrace();
        }
      }

     

    메소드 접근

    • getMethod()
      • public 메서드에만 접근 가능
    • getDeclaredMethod()

     

    Person.java

    public class Person {
    
      private String name;
      protected String address;
      public int age;
    
      public Person(String name, String address, int age) {
        this.name = name;
        this.address = address;
        this.age = age;
      }
    
      public String getName() {
        return name;
      }
    
    }

     

    Test

      @Test
      void get_method() {
        Class<Person> clazz = Person.class;
    
        try {
          Constructor<Person> constructor = clazz.getConstructor(String.class, String.class, int.class);
          Person person = constructor.newInstance("beomsic", "서울", 10);
          Method getName = person.getClass().getMethod("getName");
          Method getNameByDeclaredMethod = person.getClass().getDeclaredMethod("getName");
     
          assertNotNull(getName);
          assertNotNull(getNameByDeclaredMethod);
    
          // invoke() : 메소드 실행
          assertEquals("beomsic", (String) getName.invoke(person));
          
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
          e.printStackTrace();
        }
    
      }

     

    사용

     

    Spring Container의 BeanFactory

    • Bean은 애플리케이션이 실행한 후 런타임에 객체가 호출될 때 동적으로 객체의 인스턴스를 생성한다.
    • 이때, Spring Container의 BeanFactory에서 리플렉션을 사용

     

    Spring Data JPA

    • Entity에 기본 생성자가 필요한 이유
      • 동적으로 객체 생성 시 Reflection API를 활용하기 때문

     

    • Reflection API로는 생성자의 인자 정보를 가져올 수 없다.
    • 따라서, 기본 생성자가 반드시 있어야 객체를 생성할 수 있다.
    • 기본 생성자로 객체를 생성만 하면 필드 값등은 Reflection API로 넣어줄 수 있다.

     

    참고자료

    https://www.baeldung.com/java-reflection

    https://blog.gangnamunni.com/post/Annotation-Reflection-Entity-update/

    https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/

    https://giron.tistory.com/112

    https://ebabby.tistory.com/4

    '☕️ java' 카테고리의 다른 글

    [Java] String / StringBuffer / StringBuilde  (0) 2023.03.03
    [Java] Static 과 Final  (0) 2023.03.03
    커스텀 validation 만들기  (0) 2023.01.28
    equals / hashCode  (0) 2022.12.07
    CheckedException 과 UncheckedException  (0) 2022.10.10

    댓글

Designed by Tistory.