I have problem with injecting bean with generic types. Look at the example. I will inject to the service a repository which types takes from App class. Now i have exception:
No qualifying bean of type 'asd.IRepository' available: expected single matching bean but found 2: a,b
asd here is package, just for tests.
What can I do in this situation? Is any way to makes it?
public interface IRepository<T, V> {
void print();
}
@Component
public class A implements IRepository<String,String> {
@Override
public void print() {
System.out.println("A");
}
}
@Component
public class B implements IRepository<Double,String> {
@Override
public void print() {
System.out.println("A");
}
}
@Service
public class ServiceABC<V, T> {
@Autowired
private IRepository<V,T> repo;
public void print(){
repo.print();
}
}
@Controller
public class App {
@Autowired
private ServiceABC<String, String> serviceABC;
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext("asd");
App app = ctx.getBean(App.class);
app.serviceABC.print();
}
You have to name your components and autowire by name:
@Component("A")
public class A implements IRepository<String,String> {...}
@Component("B")
public class B implements IRepository<Double,String> {...}
[...]
@Autowired
@Qualifier("B")
private IRepository repo;
It looks like you don't know in advance which implementation of your IRepository
interface you will need. And you will know that at runtime. In this case it is a typical case for Factory pattern where you will have a IRepositoryFactory
that will have a method thhat retrieves specific implementation by type (for example IRepositoryFactory.getInstance(String type);
So in your ServiceABC
you may use the IRepository
to get specific bean at runtime. So Factory pattern may be an answer to your question. I also wrote an article that deals with this type of problem and proposes the idea of self-populating Factory (using Open source library that provides such utility). Here is the link to the article: Non-intrusive access to "Orphaned" Beans in Spring framework
Something like that?
@Controller
public class RepositoryFactory {
@Autowired
private IRepository<String, String> a;
@Autowired
private IRepository<Double, String> b;
public IRepository getRepository(String className) {
if(className.equalsIgnoreCase("a")) {
return a;
} else if(className.equalsIgnoreCase("b")) {
return b;
}
return null;
}
}
@Service
public class ServiceABC {
@Autowired
private RepositoryFactory repositoryFactory;
public void print(String className){
repositoryFactory.getRepository(className).print();
}
}
@Controller
public class App {
@Autowired
private ServiceABC serviceABC;
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext("asd");
App app = ctx.getBean(App.class);
app.serviceABC.print(A.class.getSimpleName());
}
}s
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.