Javaにおけるリフレクションとアノテーションの活用

リフレクションの基礎

クラス情報の取得には主に以下の3つの手法がある。

public class ReflectionTest {
    public void setup() {
        // テスト前処理
    }

    public void demonstrateClassRetrieval() throws ClassNotFoundException {
        // 文字列からクラス情報を取得 - 設定ファイル読み込みに適す
        Class<?> clazz1 = Class.forName("com.example.model.User");
        
        // クラスリテラルから取得 - メソッド引数等に利用
        Class<User> clazz2 = User.class;
        
        // インスタンスから取得
        Class<? extends User> clazz3 = new User().getClass();
        
        // 同一性検証
        assert clazz1 == clazz2;
        assert clazz2 == clazz3;
    }

    public void teardown() {
        // テスト後処理
    }
}

メンバー要素へのアクセス

public class MemberAccessDemo {
    public static void main(String[] args) throws Exception {
        Class<User> userClass = User.class;
        
        // フィールド操作
        // Field publicField = userClass.getField("username"); // publicフィールドのみ
        // Field[] publicFields = userClass.getFields(); // 全publicフィールド
        
        // Field privateField = userClass.getDeclaredField("password"); // アクセス修飾子に関わらず取得
        // Field[] allFields = userClass.getDeclaredFields(); // 全フィールド取得
        // privateField.setAccessible(true); // privateフィールドへのアクセス許可
        
        // コンストラクタ操作
        // Constructor<User> constructor = userClass.getConstructor(String.class, String.class);
        // User userInstance = constructor.newInstance("admin", "secret");
        
        // User defaultUser = userClass.newInstance(); // 非推奨だが可能
        
        // メソッド操作
        // User target = new User();
        // Method setUsername = userClass.getMethod("setUsername", String.class);
        // Method setPassword = userClass.getMethod("setPassword", String.class);
        // setUsername.invoke(target, "newuser");
        // setPassword.invoke(target, "newpass");
        
        // クラス情報の取得
        // String fullName = userClass.getName(); // 完全修飾クラス名
        // Method[] allMethods = userClass.getMethods(); // 全publicメソッド
    }
}

実践的なリフレクションの応用

設定ファイルに基づく動的オブジェクト生成の例を示す。

サービスクラス

// Instructor.java
public class Instructor {
    public void conductLesson() {
        System.out.println("講師が授業を行っています");
    }
}

// Learner.java
public class Learner {
    public void attendClass() {
        System.out.println("学習者が勉強しています");
    }
}

設定ファイル

# config/application.conf
targetClass=Learner
actionMethod=attendClass

実行クラス

public class DynamicExecutor {
    public static void main(String[] args) throws Exception {
        // クラスローダーを用いた設定ファイル読み込み
        ClassLoader loader = DynamicExecutor.class.getClassLoader();
        InputStream configStream = loader.getResourceAsStream("config/application.conf");
        
        // プロパティ解析
        Properties config = new Properties();
        config.load(configStream);
        String className = config.getProperty("targetClass");
        String methodName = config.getProperty("actionMethod");
        
        // 動的インスタンス生成
        Class<?> targetClass = Class.forName(className);
        Object instance = targetClass.newInstance();
        
        // メソッド実行
        Method action = targetClass.getMethod(methodName);
        action.invoke(instance);
    }
}

アノテーションの理解と活用

アノテーションの種類

/*
 * アノテーションの分類:
 * 1. ドキュメンテーション用: @param, @return, @author 等のJavadoc関連
 * 2. 標準提供アノテーション: @Override, @Deprecated, @SuppressWarnings
 * 3. メタアノテーション: @Target, @Retention, @Documented, @Inherited
 * 4. カスタムアノテーション: ユーザー定義
 */

カスタムアノテーションの作成

列挙型定義

public enum ThemeColor {
    RED, GREEN, YELLOW, BLUE
}

関連アノテーション

public @interface RelatedInfo {
    String description() default "";
}

主アノテーション定義

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Configuration {
    String identifier() default "default";
    int version() default 1;
    ThemeColor theme() default ThemeColor.BLUE;
    RelatedInfo related() default @RelatedInfo;
    String[] tags() default {};
}

アノテーションの使用と解析

@Configuration(identifier = "main-module", version = 2)
public class AnnotationProcessor {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<AnnotationProcessor> targetClass = AnnotationProcessor.class;
        
        // クラスレベルのアノテーション解析
        Configuration classConfig = targetClass.getAnnotation(Configuration.class);
        
        // メソッドレベルのアノテーション解析
        Method targetMethod = targetClass.getMethod("execute");
        Configuration methodConfig = targetMethod.getAnnotation(Configuration.class);
        
        // アノテーション属性値の取得
        String id = classConfig.identifier();
        int ver = methodConfig.version();
        System.out.println("ID: " + id + ", Version: " + ver);
    }
    
    @Configuration(tags = {"execution", "process"})
    public void execute() {
        // 処理内容
    }
}

タグ: Java Reflection Annotation JUnit properties

7月1日 16:15 投稿