Problemas no uso de CDI com Factory Method

17 respostas
X

Boa noite pessoal.

Estou trabalhando e um novo projeto e surgiu a oportunidade de utilizar CDI e estou com um problema.

Na classe abaixo utilizo um factory method para retornar uma entidade e gostaria de usar CDI para injetar o repositório, porém eu obtenho uma NullPointerException na linha novoCopo.repositorio.persistir(novoCopo);

Aparentemente se eu crio uma classe ele não faz a injeção de dependência! Já testei o código e a injeção funciona se eu não crio a classe! Se alguém tiver alguma ideia de como fazer isso agradeço!

public class Copo {
...	
	@Inject @Transient
	private Repositorio<Copo> repositorio;
	
	public static Copo novo(String nome, int volume){
		Copo novoCopo = new Copo();
		novoCopo.setNome(nome);
		novoCopo.setVolume(volume);
		
		novoCopo.repositorio.persistir(novoCopo);
		return novoCopo;
	}
...	
}

17 Respostas

D

Para o CDI funcionar o Copo instanciado tem que ser gerenciado/instanciado pelo Weld ou injetor de depência que esteja utilizando.
Você está fazendo apenas uma instância simples do Copo (“new Copo()”).

Isso deve funcionar:

@ManagedBean
public class CopoBean {

    @Inject
    private Repositorio<Copo> repositorio;

   public Copo salvar(String nome, int volume) {
      Copo copo = new Copo();
   
      copo.setNome(nome);
      copo.setNome(volume);

      repositorio.persistir(copo);

      return copo;
   }

}

Repare que não é você que instância o ManagedBean, ou servlet, ou etc, quem cria essa instância é que é responsável pela instaciação dos seus atributos (injeção de dependência), seja CDI, Spring, Guice, etc.

X

Isso funciona e eu já havia testado, mas não é o que eu preciso, mesmo assim obrigado!

O que eu necessito é que o repositório fique dentro da classe Copo e que eu possa injeta-lo, no seu caso ele caso meu repositório começa a ser um DAO!

C

O problema é que o modo como copo é criado no seu código é através de new, ou seja, ele não é gerenciado pelo weld, logo não recebe injeção, portanto o fluxo da sua aplicação deve se arquitetado de tal forma que copo seja injetado e não criado manualmente.

Um exemplo seria a injeção de um objeto do tipo Instance<Copo> para produzir novas instancias do objeto gerenciadas.

Te recomendou ma boa leitura na documentação do weld, é muito completa.

X

cleciusjm:
O problema é que o modo como copo é criado no seu código é através de new, ou seja, ele não é gerenciado pelo weld, logo não recebe injeção, portanto o fluxo da sua aplicação deve se arquitetado de tal forma que copo seja injetado e não criado manualmente.

Um exemplo seria a injeção de um objeto do tipo Instance<Copo> para produzir novas instancias do objeto gerenciadas.

Te recomendou ma boa leitura na documentação do weld, é muito completa.

Já dei uma olhada na documentação do Weld mas não achei nada para isso, encontrei algo no Guice, onde tem uma injeção estática

C

http://docs.jboss.org/weld/reference/latest/en-US/html_single/#lookup

X

cleciusjm:
http://docs.jboss.org/weld/reference/latest/en-US/html_single/#lookup

Não funciona pois a classe ele tem que injetar a Instance<T>

C

Isso na classe que usa a classe copo, ou seja, dessa forma voce consegue ter o seu @Inject do repository dentro da classe copo.
Quem irá utilizar o copo deve ser gerenciado pelo weld e ter a injeção do Instance<Copo>.

X
cleciusjm:
Isso na classe que usa a classe copo, ou seja, dessa forma voce consegue ter o seu @Inject do repository dentro da classe copo. Quem irá utilizar o copo deve ser gerenciado pelo weld e ter a injeção do Instance<Copo>.
Só que a classe Copo é criada pela própria classe copo através de um Factory Method e esse é justamente o problema! Se o copo fosse injetado não haveria problema, bem como se fosse usado um DAO ao invés de um repositório!
public class Copo {
...	
	@Inject @Transient
	private Repositorio&lt;Copo&gt; repositorio;
	
	public static Copo novo(String nome, int volume){
		Copo novoCopo = new Copo();
		novoCopo.setNome(nome);
		novoCopo.setVolume(volume);
		
		novoCopo.repositorio.persistir(novoCopo);
		return novoCopo;
	}
...	
}
J

Na sua arquitetura, teria algum problema em definir o seu repositorio como static ?

Não resolve o que você quer, que é injetar um repositorio a cada objeto novo, mas é uma solução diferente.

Não sei se isso é valido, mas foi algo que acabei pensando.

X

johnny quest:
Na sua arquitetura, teria algum problema em definir o seu repositorio como static ?

Não resolve o que você quer, que é injetar um repositorio a cada objeto novo, mas é uma solução diferente.

Não sei se isso é valido, mas foi algo que acabei pensando.


Na verdade não tem problema algum!

PS: Havia esquecido! Não é possível fazer isso caso o EntityManager seja criado no contexto de uma thread local! Ai você vai ter problemas!

C
x@ndy:
cleciusjm:
Isso na classe que usa a classe copo, ou seja, dessa forma voce consegue ter o seu @Inject do repository dentro da classe copo. Quem irá utilizar o copo deve ser gerenciado pelo weld e ter a injeção do Instance<Copo>.
Só que a classe Copo é criada pela própria classe copo através de um Factory Method e esse é justamente o problema! Se o copo fosse injetado não haveria problema, bem como se fosse usado um DAO ao invés de um repositório!
public class Copo {
...	
	@Inject @Transient
	private Repositorio&lt;Copo&gt; repositorio;
	
	public static Copo novo(String nome, int volume){
		Copo novoCopo = new Copo();
		novoCopo.setNome(nome);
		novoCopo.setVolume(volume);
		
		novoCopo.repositorio.persistir(novoCopo);
		return novoCopo;
	}
...	
}

Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>...

X

cleciusjm:

Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…

Então eu poderia fazer simplesmente @Inject Copo!

O problema é que assim eu obtenho uma instancia do objeto em um estado inconsistente o que não é minha ideia! A Fabrica tem a função justamente de devolver um objeto totalmente consistente!

D

x@ndy:
cleciusjm:

Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…

Então eu poderia fazer simplesmente @Inject Copo!

O problema é que assim eu obtenho uma instancia do objeto em um estado inconsistente o que não é minha ideia! A Fabrica tem a função justamente de devolver um objeto totalmente consistente!

Vai na documentação do Java EE6 e leia sobre o que é um método produtor, anotado com @Produces… 99% de chance de resolver o seu problema.

X

diegosammet:
x@ndy:
cleciusjm:

Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…

Então eu poderia fazer simplesmente @Inject Copo!

O problema é que assim eu obtenho uma instancia do objeto em um estado inconsistente o que não é minha ideia! A Fabrica tem a função justamente de devolver um objeto totalmente consistente!

Vai na documentação do Java EE6 e leia sobre o que é um método produtor, anotado com @Produces… 99% de chance de resolver o seu problema.

O problema não é o método produtor. De uma olhada na questão inicial!

C

x@ndy:
diegosammet:
x@ndy:
cleciusjm:

Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…

Então eu poderia fazer simplesmente @Inject Copo!

O problema é que assim eu obtenho uma instancia do objeto em um estado inconsistente o que não é minha ideia! A Fabrica tem a função justamente de devolver um objeto totalmente consistente!

Vai na documentação do Java EE6 e leia sobre o que é um método produtor, anotado com @Produces… 99% de chance de resolver o seu problema.

O problema não é o método produtor. De uma olhada na questão inicial!

Na realidade, o método produtor lhe permitiria criar um estado consistente pra esse objeto.

D

cleciusjm:
x@ndy:
diegosammet:
x@ndy:
cleciusjm:

Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…

Então eu poderia fazer simplesmente @Inject Copo!

O problema é que assim eu obtenho uma instancia do objeto em um estado inconsistente o que não é minha ideia! A Fabrica tem a função justamente de devolver um objeto totalmente consistente!

Vai na documentação do Java EE6 e leia sobre o que é um método produtor, anotado com @Produces… 99% de chance de resolver o seu problema.

O problema não é o método produtor. De uma olhada na questão inicial!

Na realidade, o método produtor lhe permitiria criar um estado consistente pra esse objeto.

Exato, se ele tivesse pelo menos lido essa parte da especificação teria entendido o que eu disse.

X

diegosammet:
cleciusjm:

Na realidade, o método produtor lhe permitiria criar um estado consistente pra esse objeto.

Exato, se ele tivesse pelo menos lido essa parte da especificação teria entendido o que eu disse.

cleciusjm e diegosammet, pelo que eu li na documentação o produtor é chamado pelo container para criar um objeto e depois injeta-lo! O produtor funciona como uma fabrica, permitindo que um objeto mais complexo seja criado bem como devido o escopo desse objeto!

Pegando o meu exemplo, tenho um objeto Copo e dentro dele existe um objeto Repositorio que necessita ser injetado! O objeto Repositorio tem um produtor pois alem de ser genérico ele tambem necessita de um EntityManager que passado para ele durante a construção!

Se eu injetar o objeto Copo tudo funciona perfeitamente! Até o colega dobau deu um exemplo! Só que isso não é o que eu quero pois minha entidade é criada em um estado inconsistente!

A meu ver um produtor para o copo não resolve o problema pois necessito passar parâmetros para ele de modo que eu tenho que cria-lo ao invés de injeta-lo. Os parâmetros só estarão disponíveis em runtime isso é um cadastro. Posso receber esses dados de diferentes fontes de modo que não são parâmetros injetados que possam ser usados por um produtor!

Bom, conforme vocês eu estou errado e existe uma forma de passar esses parâmetros de modo que posso usar um método produtor então peço aos dois que por favor me esclareçam como posso fazer!

Criado 17 de janeiro de 2013
Ultima resposta 19 de jan. de 2013
Respostas 17
Participantes 5