1. 概要

このチュートリアルでは、ジェネリックパラメーターによってSpringBeanを注入する方法を説明します。

2. Spring3.2のジェネリックスの自動配線。

Springは、バージョン3.2以降、ジェネリック型のインジェクションをサポートしています。

Vehicle という抽象クラスと、 Car:という具体的なサブクラスがあるとします。

public abstract class Vehicle {
    private String name;
    private String manufacturer;
 
    // ... getters, setters etc
}
public class Car extends Vehicle {
    private String engineType;
 
    // ... getters, setters etc
}

タイプVehicleのオブジェクトのリストをハンドラークラスに挿入するとします。

@Autowired
private List<Vehicle> vehicles;

Springは、すべてのVehicleインスタンスBeanをこのリストに自動配線します。JavaまたはXML構成を介してこれらのBeanをどのようにインスタンス化するかは関係ありません。

修飾子を使用して、Vehicleタイプの特定のBeanのみを取得することもできます。 次に、 @CarQualifier を作成し、@Qualifierで注釈を付けます。

@Target({
  ElementType.FIELD, 
  ElementType.METHOD,
  ElementType.TYPE, 
  ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface CarQualifier {
}

これで、リストでこの注釈を使用して、特定のVehiclesのみを取得できます。

@Autowired
@CarQualifier
private List<Vehicle> vehicles;

この場合、複数の Vehicle Beanを作成できますが、Springは@CarQualifierを持つBeanのみを上記のリストに挿入します。

public class CustomConfiguration {
    @Bean
    @CarQualifier
    public Car getMercedes() {
        return new Car("E280", "Mercedes", "Diesel");
    }
}

3. Spring4.0のジェネリックスの自動配線。

Motorcycleという別のVehicleサブクラスがあるとします。

public class Motorcycle extends Vehicle {
    private boolean twoWheeler;
    //... getters, setters etc
}

ここで、 Car Beanのみをリストに挿入し、 Motorcycle oneを挿入しない場合は、特定のサブクラスを型パラメーターとして使用することでこれを行うことができます。

@Autowired
private List<Car> vehicles;

Springでは、バージョン4.0以降、明示的なアノテーションを必要とせずに、修飾子として汎用タイプを使用できます

Spring 4.0より前では、上記のコードは Vehicle の複数のサブクラスのBeanでは機能しませんでした。明示的な修飾子がないと、NonUniqueBeanDefinitionExceptionを受け取ります。

4. ResolvableType

ジェネリックの自動配線機能は、舞台裏でResolvableTypeクラスの助けを借りて機能します。

これは、Javaタイプをカプセル化し、スーパータイプ、インターフェース、汎用パラメーターへのアクセスを処理し、最終的にクラスに解決するためにSpring4.0で導入されました。

ResolvableType vehiclesType = ResolvableType.forField(getClass().getDeclaredField("vehicles"));
System.out.println(vehiclesType);

ResolvableType type = vehiclesType.getGeneric();
System.out.println(type);

Class<?> aClass = type.resolve();
System.out.println(aClass);

上記のコードの出力には、対応する単純型と汎用型が表示されます。

java.util.List<com.example.model.Vehicle>
com.example.model.Vehicle
class com.example.model.Vehicle

5. 結論

ジェネリック型の注入は強力な機能であり、開発者が明示的な修飾子を割り当てる手間を省き、コードをよりクリーンで理解しやすくします。

いつものように、コードはGitHubにあります。