[RESOLVIDO] VRaptor3 e IoC

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?

Agradeço a atenção.

Conseguir ter dois componentes com a mesma classe mãe você consegue sem problemas.

Porém no seu caso o erro é que ao invés de injetar a classe abstrata você deve injetar a classe concreta.

Justamente. No construtor do Interceptor eu injeto a classe abstrata, pois cada controller vai receber por injeção seu facade específico:

@RequestScoped
class FacadeInterceptor implements Interceptor {
   
    
    private final Facade<Model> facade;

    public FacadeInterceptor(Facade<Model> facade) {
	    this.facade = facade;
    }

    public void intercept(InterceptorStack stack, ResourceMethod method, Object obj) throws InterceptionException {
		try {
			stack.next(method, obj);
		} finally {
			facade.rollback();
			facade.close();
		}
    }
}

Tirei o abstract da class Facade<T> mas continua o mesmo erro.

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.

Agradeço a atenção.

deixa eu entender o que vc quer fazer:

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&lt;ClienteModel&gt; {
    public ClienteFacade(DaoFactory factory) {
        super(factory);
    }
}

abstract class Facade&lt;Model&gt; {

}

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.

Obrigado pela atenção.

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