Solucionado (ver solução)
Solucionado
(ver solução)
14
respostas

@Inject CDI

Nas aulas feitas de vraptor 4 + CDI pede-se que para injetar dependências além de utilizar o @Inject devemos criar um construtor com e sem parâmetro, ficando um pequeno exemplo:

@Inject
private Dao dao;

public Controller(Dao dao) {
  this.dao = dao;
}

@Deprecated
public Controller() {

}

Recentemente tenho pesquisado e estudo um pouco mais sobre o CDI, onde vi que não tem necessidade de tais construtores bastando apenas informar o @Inject

@Inject
private Dao dao;

Nos meus projetos retirei todos os construtores e tudo continuou funcionando perfeitamente, até porque se estou usando um framework para injetar dependência é porque eu quero facilidade então nada mais justo do que apenas utilizar o @Inject.

Queria saber por que nas aulas é pedido que crie os construtores.

14 respostas

Quando se usa CDI é obrigatório o uso de um construtor padrão. É esse construtor que CDI por debaixo dos panos chamará para então, via reflection, injetar o artefato indicado.

Isso não é exclusivo de CDI, é padrão de qualquer container, seja servlet, EJB, etc.

Lembre-se que se você não reescreveu o construtor padrão, ele já existe. Caso tenha adicionado outro construtor, você perderá o padrão e precisará adicioná-lo.

Contudo, há uma exceção. Se você tem um construtor anotado com @inject, ou seja, faz injeção no construtor, esse será o construtor chamado, sem haver necessidade do construtor padrão. Mas só pode haver um constructor injetado com @inject.

solução!

When a CDI bean is initialized, the container will use its default constructor. When there is another constructor annotated with the @Inject annotation, then the container will automatically use this constructor instead, and in this way the argument passed in the constructor will be injected in the bean. A thing to notice here is that we can only have one constructor injection point. If we create another @Inject annotated constructor, the behaviour of the container is unpredictable.

Aliás, não é uma boa prática injectar diretamente no atributo. Se você faz isso, você estará omitindo a dependência do construtor e se você usa Javadoc quando gerar a documentação da classe, se você injetou via construtor, terá bem documentado as dependências da classe. Sem falar que se você fizer teste unitário não conseguirá passar as dependências mockadas ou não para a classe sem auxílio de um framework.

Não sei como o VRator esta estruturado, mas o mais elegante seria:

private Dao dao;

@Inject
public Controller(Dao dao) {
  this.dao = dao;
}

É assim que faço com todos os meus sistemas, desde que CDI foi lançada (fui earlier adopter da tecnologia).

Aliás, Matheus, talvez essa exigência extra do Vraptor seja para manter compatibilidade com versões antigas ou algum trick do framework. Não sei dizer o que é.

Entendido, mas se fosse obrigatório para o funcionamento da injeção então teria que parar de funcionar meus @Inject algo que não aconteceu.

É isso que eu queria entender melhor, porque sou obrigado a criar os construtores sendo que sem eles tudo funciona.

Posta um código de uma classe que você escreveu e que funciona. Não precisa ser toda.. apenas os atributos e construtores se tiver.

Se você colocar um construtor diferente do padrão seu @Inject não vai funcionar. Por isso quero ver o código que você escreveu. Se você não adicionou um construtor diferente do padrão, por padrão, em Java, a classe possui o construtor padrão então o @Inject funcionará.

Isso não é exclusivo de CDI, se você trabalha com EJB ou outro container é a mesma coisa.

Injetar diretamente no atributo é uma má prática. Só vejo sentido fazer isso para efeito didático. Mas a questão nem é essa de boa prática ou má prática. É você entender o funcionamento do CDI para ficar seguro.

O exemplo que você deu:

@Inject
private Dao dao;

public Controller(Dao dao) {
  this.dao = dao;
}

@Deprecated
public Controller() {

}

Eu não consigo entender, porque ou você faz inject direto no atributo ou no construtor. Sendo assim, nesse caso, não faz sentido os dois construtores ai. Sendo assim, é algo do Vrator e não do CDI que você precisa investigar.

Entendi, vou fazer o teste e criar outro construtor para ver se irá parar a injeção dos atributo e irei começar fazer injeção via construtor, fica bem mais fácil do que repetir toda hora o @Inject para todos os atributos, agora ficou claro para mim os "porque's".

Código do meu GenericController:

public abstract class GenericController<T> {

    @Inject
    private Dao dao;
    @Inject
    private Result result;
    @Inject
    private Validator validator;
    private boolean redirect = true;

    // começa os métodos

}

Obrigado Flávio, vou adotar as boas práticas a partir de agora, hoje mesmo irei reescrever minhas classes.

Então, no seu exemplo você tem o construtor padrão e isso já basta para CDI funcionar. Está conforme a Spec.

Então, eu só não consigo entender foi o exemplo inicial que você deu. Estou confiando que aquilo é código do Vrator, se for, tem que consultar a documentação para saber o motivo daquela redundância.

Por fim, sua classe ficar assim:

public abstract class GenericController<T> {

    private Dao dao;
    private Result result;
    private Validator validator;
    private boolean redirect = true;

    // começa os métodos

    @Inject
  public GenericController(Dao dao, Result result, Validator validator) {
     // atribui cada dependência ao atributo da classe
}

Agora, se o VRator tem alguma restrição nisso, eu não sei dizer.

Perfeito Flávio, muito obrigado, agora ja consigo saber porque funciona sem o construtor pois ele esta buscando o padrão que o CDI ja utiliza e sei que por boas práticas o @Inject deve estar no construtor, tudo resolvido.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software