Não consigo fazer IoC quando dois componentes são da mesma herança?
Exemplo:
abstract class Facade<T> {
// métodos abstratos e não-abstratos
}
@Component
class ClienteFacade extends Facade<ClienteModel> {
// implementações
}
Até aqui tudo bem. Consigo receber meu ClienteFacade no construtor do Controller numa boa.
Ocorreu uma Exception quando adicionei mais uma classe na herança:
@Component
class ImovelFacade extends Facade<ImovelModel> {
// implementações
}
StackTrace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [br.com.imobiliaria.facade.Facade] is defined: more than one 'primary' bean found among candidates: [clienteFacade, imovelFacade]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.determinePrimaryCandidate(DefaultListableBeanFactory.java:844)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:770)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:680)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:771)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:691)
... 77 more
O Server nem sobe nesse caso. Já tentei colocar a anotação na classe Pai mas tbm não funciona.
Será que não consigo fazer IoC quando dois componentes são do mesmo tipo?
Só pra esclarecer. Aquele rollback no facade parece um pouco estranho, mas montei essa estrutura onde o Facade é que tem o DaoFactory. O Controller tem apenas o Facade e o Model, deixando para o Facade fazer a chamada à persistência.
Não consegui pensar noutra forma de encapsular isso.
Então me parece que o erro não tá no fato da classe Pai ser abstrata, pois mesmo deixando-a abstrata novamente, eu removi a anotação @Component da classe ImovelFacade, deixando apenas UMA filha com a anoteção. Assim funcionou de boa.
O problema é que preciso do ImovelFacade, pois a ideia é recebe-lo no contrutor do Controller ImovelController.
vc quer que no interceptor o VRaptor injete o mesmo Facade que o seu controller está usando?
isso não vai funcionar assim…
qdo vc pede um Facade, o VRaptor vai procurar todas as classes compatíveis com esse tipo. Se tiver mais de uma, ele dá erro. Não tem como o VRaptor descobrir qual é a mesma classe que foi instanciada no controller e usá-la…
o melhor jeito de fazer isso é ao invés de usar herança, usar composição:
@Component
class ClienteFacade {
public ClienteFacade(Facade facade) {
this.facade = facade;
}
}
@Component
class ImovelFacade {
public ImovelFacade(Facade facade) {
this.facade = facade;
}
}
ou pelo menos separar essa parte que vc usa no interceptor, se vc quiser mesmo usar herança, em outra classe que tem só uma implementação, e fazer sua abstract Facade usar essa classe
Isso mesmo, oq eu quero é injetar o mesmo Facade do Controller no Interceptor, pois fiz uma estrutura que parece estranha mas o DaoFactory está dentro do Facade e tal, e previso fechar o DaoFactory.
Enfim, usando a composição não consegui ainda entender qual Facade eu iria injetar no Interceptor, pois ainda preciso fechar o recurso do DaoFactory. Pelo que entendi teria que criar um interceptor pra cada Controller,onde cada controller teria sua anotação, com o interceptor injetando o Facade específico. Seria isso mesmo?
Pra reverter o problema, ainda com o uso da herança, tirei a anotação @Component dos Facade´s. Nos Controllers eu injeto o DaoFactory, e no construtor crio o Facade passando aquele factory no construtor.
class ClienteFacade extends Facade<ClienteModel> {
public ClienteFacade(DaoFactory factory) {
super(factory);
}
}
abstract class Facade<Model> {
}
Controller:
class ClienteController {
public ClienteController (DaoFactory factory) {
this.clienteFacade = new ClienteFacade(factory);
}
}
Assim no Interceptor eu injeto o DaoFactory, para fechá-lo no final da requisição.
Concluindo, eu tentei nessa estrutura tentar deixa uma coisa bem “separada”, usando uma arquitetua MVC onde o meu ClienteController trabalha com ClienteFacade e ClienteModel, passando para a View o ClienteModel. É no Model que faço as validações necessárias, deixando dessa forma meu controle mais “thin”. Não sei se é a ideal, pois não tenho muita experiência. Aceito sugestões, e obrigado pela atenção
nos controllers vc pode continuar recebendo no construtor o ClienteFacade… só que no interceptor vc não pode receber Facade pq tem várias implementações…
se o recurso q vc quer fechar é o DaoFactory, receba o DaoFactory no interceptor… no resto da aplicação pode receber os facades, mas os específicos, não o abstrato
[quote=Lucas Cavalcanti]nos controllers vc pode continuar recebendo no construtor o ClienteFacade… só que no interceptor vc não pode receber Facade pq tem várias implementações…
se o recurso q vc quer fechar é o DaoFactory, receba o DaoFactory no interceptor… no resto da aplicação pode receber os facades, mas os específicos, não o abstrato[/quote]
Legal. Eu não imaginava que o VRaptor injeta no Interceptor a mesm dependencia que eu injeto em um Facade qualquer. Por isso eu estava fazendo confusão e tentando fazer ele interceptar o “mesmo” factory do facade, passando o Facade pro interceptor enfim.
Pelo que entendi, como o DaoFactory tem o @Component, por padrão ele vai instanciar um e apenas um por requisição é isso? não importa quem vai receber o factory, pois será sempre o mesmo na mesma requisição. Mto legal.
se tiver só o @Component, ou ele junto com @RequestScoped ele instancia só um por requisição
se tiver o @Component e @SessionScoped ele instancia um por sessão de usuário
se tiver o @Component e @ApplicationScoped ele instancia um só pra aplicação inteira
se tiver o @Component e @PrototypeScoped ele instancia toda vez que for pedido no construtor