본문 바로가기
(2024-10) 스파르타 내일배움캠프 - 백엔드/Java Reflect

ConfigLoader 예제

by 어뫄어뫄 2024. 11. 27.

ConfigLoaderDemo.java

package configloader;

import configs.AppConfig;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.util.Scanner;

public class ConfigLoaderDemo {
    private static final Path APP_CONFIG_PATH = Path.of("resources/application-config.cfg");

    public static void main(String[] args) throws IOException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        AppConfig appConfig = loadConfig(AppConfig.class, APP_CONFIG_PATH);

        System.out.println(appConfig);
    }

    public static <T> T loadConfig(Class<T> configClass, Path configFilePath) throws IOException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Scanner fileScanner = new Scanner(configFilePath);

        Constructor<?> constructor = configClass.getDeclaredConstructor();
        constructor.setAccessible(true);

        T configInstance = (T) constructor.newInstance();

        while (fileScanner.hasNextLine()) {
            String line = fileScanner.nextLine();
            String[] keyValue = line.split("=");

            if (keyValue.length != 2) {
                continue;
            }

            String fieldName = keyValue[0];
            String fieldValue = keyValue[1];

            Field field;
            try {
                field = configClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                System.out.printf("Field %s is not recognized and will be skipped.%n", fieldName);
                continue;
            }

            field.setAccessible(true);
            Object parsedValue = parseFieldValue(field.getType(), fieldValue);
            field.set(configInstance, parsedValue);
        }

        return configInstance;
    }

    private static Object parseFieldValue(Class<?> fieldType, String value) {
        if (fieldType.equals(int.class)) {
            return Integer.parseInt(value);
        } else if (fieldType.equals(short.class)) {
            return Short.parseShort(value);
        } else if (fieldType.equals(long.class)) {
            return Long.parseLong(value);
        } else if (fieldType.equals(float.class)) {
            return Float.parseFloat(value);
        } else if (fieldType.equals(double.class)) {
            return Double.parseDouble(value);
        } else if (fieldType.equals(String.class)) {
            return value;
        }
        throw new UnsupportedOperationException("Unsupported field type: " + fieldType.getName());
    }
}

 

configs/AppConfig.java

package configs;

public class AppConfig {
    private int launchYear;
    private String applicationName;
    private double subscriptionCost;

    public int getLaunchYear() {
        return launchYear;
    }

    public String getApplicationName() {
        return applicationName;
    }

    public double getSubscriptionCost() {
        return subscriptionCost;
    }

    @Override
    public String toString() {
        return "AppConfig{" +
                "launchYear=" + launchYear +
                ", applicationName='" + applicationName + '\'' +
                ", subscriptionCost=" + subscriptionCost +
                '}';
    }
}

 

1. Class.getDeclaredConstructor()

  • 설명: 클래스의 지정된 생성자를 가져옵니다.
  • 사용 예:
     
    Constructor<?> constructor = configClass.getDeclaredConstructor(); constructor.setAccessible(true); T configInstance = (T) constructor.newInstance();
    • 기본 생성자를 가져와 접근 제한을 해제하고, 새로운 인스턴스를 생성합니다.
    • setAccessible(true)를 통해 private 생성자도 사용할 수 있도록 설정합니다.

2. Class.getDeclaredField(String name)

  • 설명: 클래스의 지정된 필드를 가져옵니다.
  • 사용 예:
    Field field = configClass.getDeclaredField(fieldName);
    설정 파일의 키와 일치하는 이름의 필드를 동적으로 찾습니다. 존재하지 않으면 예외가 발생하며, 이를 처리해 무시하도록 구현되었습니다.

3. Field.setAccessible(true)

  • 설명: private 필드에도 접근할 수 있도록 제한을 해제합니다.
  • 사용 예:
     
    field.setAccessible(true);
    필드 값을 설정하기 위해 접근 제한을 제거합니다.

4. Field.set(Object obj, Object value)

  • 설명: 특정 객체에서 해당 필드에 값을 설정합니다.
  • 사용 예:
    field.set(configInstance, parsedValue);
     
    설정 파일에서 읽은 값을 파싱한 후 해당 필드에 할당합니다.

5. Class.getType()

  • 설명: 필드의 데이터 타입(Class 객체)을 반환합니다.
  • 사용 예:
     
    Object parsedValue = parseFieldValue(field.getType(), fieldValue);
    필드 타입에 따라 적절히 변환된 값을 반환합니다.