Problemas no uso de CDI com Factory Method

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!

[code]public class Copo {

@Inject @Transient
private Repositorio 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;
}


}[/code]

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.

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!

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.

[quote=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.[/quote]

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

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

[quote=cleciusjm]http://docs.jboss.org/weld/reference/latest/en-US/html_single/#lookup
[/quote]
Não funciona pois a classe ele tem que injetar a Instance<T>

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>.

[quote=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>.[/quote]
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!

[code]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;
}


}[/code]

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.

[quote=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.

[/quote]
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!

[quote=x@ndy][quote=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>.[/quote]
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!

[code]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;
}


}[/code][/quote]

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

[quote=cleciusjm]
Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…[/quote]

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!

[quote=x@ndy][quote=cleciusjm]
Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…[/quote]

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![/quote]

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.

[quote=diegosammet][quote=x@ndy][quote=cleciusjm]
Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…[/quote]

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![/quote]

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.[/quote]

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

[quote=x@ndy][quote=diegosammet][quote=x@ndy][quote=cleciusjm]
Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…[/quote]

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![/quote]

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.[/quote]

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

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

[quote=cleciusjm][quote=x@ndy][quote=diegosammet][quote=x@ndy][quote=cleciusjm]
Quem vai usar o Copo? Quem for instanciar o copo pode ter um Instance<Copo>…[/quote]

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![/quote]

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.[/quote]

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

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

[/quote]

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

[quote=diegosammet][quote=cleciusjm]
Na realidade, o método produtor lhe permitiria criar um estado consistente pra esse objeto.
[/quote]

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

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!