简体   繁体   中英

Spring 4 - Autowire generic interface

Starting with Spring (v4.3.8), I encounter a problem when Spring try to load dependency injections.

I want to call the "manage" method of the ManagerImpl1.java or ManagerImpl2.java implementation based on the type of T (Debit1 or Debit2). Here are the details:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.datacollection.infoprod.Manager' available: expected single matching bean but found 2: ManagerImpl1,ManagerImpl2

Business.java :

@Component
public class Business<T extends Debit> {

    @Autowired
    private Manager<T> manager;

    public void treatment(Context<T> context, FindServiceReturnMessage response) {

        manager.manage(response, context);
    }

Manager.java :

public interface Manager<T extends Debit> {

    void manage(final FindServiceReturnMessage response, Context<T> context);
}

ManagerImpl1.java :

@Component
public class ManagerImpl1 implements Manager<Debit1> {

    @Override
    public void manage(final FindServiceReturnMessage response, Context<Debit1> context) {

    }
}

ManagerImpl2.java :

@Component
public class ManagerImpl2 implements Manager<Debit2> {

    @Override
    public void manage(final FindServiceReturnMessage response, Context<Debit2> context) {

    }
}

Also, "Debit1" and "Debit2" implement the interface "Debit".

I tried several things but without success...

You need to add a qualifier on your Bean like the following:

@Component
@Qualifier("managerImpl2")
public class ManagerImpl2 implements Manager<Debit2> {

    @Override
    public void manage(final FindServiceReturnMessage response, Context<Debit2> context) 
    {

    }
}

Then, when you wanna use it, use once more your @Qualifier annotation:

@Component
public class Business<T extends Debit> {

    @Autowired
    @Qualifier("managerImpl2")
    private Manager<T> manager;

    public void treatment(Context<T> context, FindServiceReturnMessage response) {

        manager.manage(response, context);
    }
}

Yet, as @dvorog said in the comments, as Generics are not present at compile, you will probably have to make a Business interface like this:

public interface Business<T extends Debit> {

    public void treatment(Context<T> context, FindServiceReturnMessage response);
}

and implements BusinessImpl to specify it each time you have a new kind of Debit :

@Component
public class ManagerImpl2Business<Debit2> {

    @Autowired
    @Qualifier("managerImpl2")
    private Manager<Debit2> manager;

    public void treatment(Context<Debit2> context, FindServiceReturnMessage response) {

        manager.manage(response, context);
    }
}

This will repeat a step over and will probably end with some unmaintainable code, or some if (T instanceof Debit1) somewhere to make your genericity work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM