리플렉션을 활용한 클래스 메타데이터 조작

클래스 구조 정보 획득

리플렉션 API를 사용하면 런타임에 클래스의 구조적 정보를 얻을 수 있습니다. 다음 코드는 주요 메타데이터 조회 방법을 보여줍니다:

public class ReflectionInspector {
    public static void main(String[] args) throws Exception {
        Class<?> targetClass = Class.forName("com.example.model.Student");

        // 클래스 식별자 획득
        System.out.println("전체 경로: " + targetClass.getName());
        System.out.println("단순 이름: " + targetClass.getSimpleName());

        // public 필드만 조회
        for (var field : targetClass.getFields()) {
            System.out.println("Public 필드: " + field);
        }

        // 모든 접근 제어자의 필드 조회
        for (var field : targetClass.getDeclaredFields()) {
            System.out.println("선언된 필드: " + field);
        }

        // 특정 필드 조회 (private 포함)
        Field ageField = targetClass.getDeclaredField("age");
        System.out.println("특정 필드: " + ageField);

        // public 메서드 목록
        System.out.println("--- Public 메서드 ---");
        for (var method : targetClass.getMethods()) {
            System.out.println(method);
        }

        // 클래스 내 선언된 모든 메서드
        System.out.println("--- 선언된 메서드 ---");
        for (var method : targetClass.getDeclaredMethods()) {
            System.out.println(method);
        }

        // 생성자 정보 조회
        System.out.println("--- Public 생성자 ---");
        for (var constructor : targetClass.getConstructors()) {
            System.out.println(constructor);
        }

        System.out.println("--- 선언된 생성자 ---");
        for (var constructor : targetClass.getDeclaredConstructors()) {
            System.out.println(constructor);
        }
    }
}

객체 생성 및 메서드 호출

리플렉션을 통해 클래스의 인스턴스를 동적으로 생성하고 메서드를 호출할 수 있습니다:

public class DynamicInvoker {
    public static void main(String[] args) throws Exception {
        Class<?> targetClass = Class.forName("com.example.model.Student");

        // 기본 생성자로 객체 생성
        Object student1 = targetClass.getDeclaredConstructor().newInstance();
        System.out.println("기본 생성자 객체: " + student1);

        // 매개변수가 있는 생성자 활용
        Constructor<?> paramConstructor = targetClass
            .getDeclaredConstructor(String.class, int.class, int.class);
        Object student2 = paramConstructor.newInstance("alice", 22, 100);
        System.out.println("매개변수 생성자 객체: " + student2);

        // 필드 값 설정 및 조회
        Object student3 = targetClass.getDeclaredConstructor().newInstance();
        student3.getClass().getMethod("setAge", int.class).invoke(student3, 25);
        int retrievedAge = (int) student3.getClass()
            .getMethod("getAge").invoke(student3);
        System.out.println("설정된 나이: " + retrievedAge);

        // private 메서드 호출을 위한 접근 허용
        Method privateMethod = targetClass
            .getDeclaredMethod("internalProcess", String.class);
        privateMethod.setAccessible(true);
        privateMethod.invoke(student3, "테스트 데이터");
    }
}

어노테이션 정보 추출

리플렉션을 사용하면 클래스와 필드에 적용된 어노테이션의 메타데이터를 읽을 수 있습니다:

public class AnnotationReader {
    public static void main(String[] args) throws Exception {
        Class<?> entityClass = Student.class;

        // 클래스 레벨 어노테이션 조회
        System.out.println("--- 클래스 어노테이션 ---");
        for (var annotation : entityClass.getAnnotations()) {
            System.out.println(annotation);
        }

        // 특정 어노테이션의 값 읽기
        TableInfo tableInfo = entityClass.getAnnotation(TableInfo.class);
        System.out.println("테이블 이름: " + tableInfo.tableName());

        // 필드 레벨 어노테이션 분석
        Field nameField = entityClass.getDeclaredField("name");
        ColumnInfo colAnnotation = nameField.getAnnotation(ColumnInfo.class);
        System.out.println("컬럼명: " + colAnnotation.columnName());
        System.out.println("데이터 타입: " + colAnnotation.dataType());
        System.out.println("길이: " + colAnnotation.maxLength());
    }
}

// 어노테이션 정의 예시
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableInfo {
    String tableName();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface ColumnInfo {
    String columnName();
    String dataType();
    int maxLength();
}

// 어노테이션이 적용된 엔티티 클래스
@TableInfo(tableName = "students")
class Student {
    @ColumnInfo(columnName = "full_name", dataType = "varchar", maxLength = 8)
    private String name;

    @ColumnInfo(columnName = "student_age", dataType = "int", maxLength = 3)
    private int age;

    @ColumnInfo(columnName = "student_id", dataType = "int", maxLength = 10)
    private int id;

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

    // getter/setter 메서드 생략
}

태그: java reflection Annotation Class Metadata Dynamic proxy

7월 7일 02:45에 게시됨