Injetando no Entity

Prezados(as),

Tem como injetar as coisas num entity no EJB 3.0? Testei aqui e não funciona (pelo menos não no JBOSS). O código é mais ou menos esse:

@Entity
public class Duplicata {

   private Long id;
   private Date vencto;
   private BigDecimal valor;
   private String cedente;

   // injetando uma estratégia de serviço...
   @EJB
   private CancelarDuplicataSvc cancelarSvc;

   // etc...

}

Por um acaso o Spring faz isso?

Aguardo!

Rodrigo Yoshima

Boa pergunta.
Tentei implemtar o conceito de domain model (classe com comportamento) no EJB3 e senti que a plataforma não foi feita para isso, forçando a você fazer classes “burras” e jogando toda a lógica apenas nas sessions.
Tentei fazer injeção e não consegui não.

Hummm… Pelo que estou estudando na especificação, me parece que esta injeção de dependência serve apenas para session beans, interceptors e message driven beans.

A propósito, para que você deseja ter a referencia de um EJB dentro de um entity?

Para criar classes “inteligentes” com comportamento seria interessante delegar os métodos do entity para um EJB.
Neste caso eu poderia criar um Especification ou Strategy (patterns) usando um session bean.
No exemplo dele, acho que seria assim:


@Entity
 public class Duplicata {
 
    private Long id;
    private Date vencto;
    private BigDecimal valor;
    private String cedente;
 
    // injetando uma estratégia de serviço...
    @EJB
    private CancelarDuplicataSvc cancelarSvc;
 
   public void cancelar() {
      cancelarSvc.cancelar(this);
   } 
 }

Tentei fazer isso também e não consegui.

Bom, pessoalmente acredito que esta não seja uma boa estratégia, pois o entity, principalmente se você está utilizando EJB, é um objeto que vai trafegar pela rede e não seria muito bom que ele carregasse uma instância de um stub de EJB dentro dele…

Sugiro criar um session bean com estas operações e passar o entity como parâmetro. Caso insista nesta estratégia eu sugiro que você considere a possibilidade de utilizar uma classe java normal (mesmo que esta seja um delegate para acessar um session).

Não, os Entity não fazem parte do Contexto do Spring.

É Guerra, no meu caso foi a melhor alternativa que eu tinha pensado na época.
Delegar para uma classe que
chamava o session via JNDI.

Eu não acho que é uma alternativa legal chamar serviços de dentro do Entity. Na minha opinião, o entity deve ter inteligência, mas não a ponto de acessar outros serviços. Devem ter inteligências mais simples.

Afinal, na prática, inteligências pesadas envolvem várias entidades do banco, vários processamentos etc. Isso acho legal ficar em uma interface de serviço mesmo.

Será que não está faltando ai uma entidade chamada Duplicata? E esse objeto por sua vez tivesse o método cancelar()?

IMHO, é muito esquisito colocar um serviço dentro de uma entidade.

[color=red]ALTERADO[/color]: aff, viajei. O objeto Duplicata já existe. Bem, acho que o próprio objeto deveria conter a lógica para cancelar a duplicata.

Na minha opinião, colocar um método cancelar na clase Duplicata, sendo que este deve acessar um serviço remoto e atualizar o banco de dados, acho a mesma coisa que criar o método “inserir” dentro da própria classe Duplicata.

Acho que o correto seria criar um método cancelar() dentro da classe Duplicada para que ele gerenciasse o estado interno de uma instância quando a duplicada fosse cancelada. Desta forma existiria um serviço que pegaria uma instância de Duplicata detached, chamaria o método cancelar() e sincronizaria seu estado com o banco a partir de um EntityManger. Desta forma separaríamos a lógica de negócios do método cancelar() com a execução de um serviço que sincroniza isto com o banco de dados e possivelmente pode ser executado remotamente.

Esta é minha visão arquitetural de como resolver este problema. Aguardo a opinião do pessoal a respeito.

[quote=Guerr@]Na minha opinião, colocar um método cancelar na clase Duplicata, sendo que este deve acessar um serviço remoto e atualizar o banco de dados, acho a mesma coisa que criar o método “inserir” dentro da própria classe Duplicata.

Acho que o correto seria criar um método cancelar() dentro da classe Duplicada para que ele gerenciasse o estado interno de uma instância quando a duplicada fosse cancelada. Desta forma existiria um serviço que pegaria uma instância de Duplicata detached, chamaria o método cancelar() e sincronizaria seu estado com o banco a partir de um EntityManger. Desta forma separaríamos a lógica de negócios do método cancelar() com a execução de um serviço que sincroniza isto com o banco de dados e possivelmente pode ser executado remotamente.

Esta é minha visão arquitetural de como resolver este problema. Aguardo a opinião do pessoal a respeito.[/quote]

Em minha opinião, é isso que você citou que deveria ser feito. :smiley:

Guerra é bem interessante essa sua visão.
Vc poderia dar um exemplo.

O Okara complementou a minha visão:

 @Entity
  public class Duplicata {
  
     private Long id;
     private Date vencto;
     private BigDecimal valor;
     private String cedente;
  
     // injetando uma estratégia de serviço...
     @EJB
     private CancelarDuplicataSvc cancelarSvc;
  
    public void cancelar() {
       cancelarSvc.cancelar(this);
    } 
  }

A idéia é ter o serviço para utilizar um strategy… Logicamente esse serviço não seria chamado remotamente…

Pelo que me lembro, a definição do Fowler ou do Evans é que um service seria uma tarefa que não é alocada “naturalmente” a um entity.

O problema é que se a arquitetura nos força a alocar tarefas a services por conta de dificuldades técnicas, acho que temos um problema.

Na minha idéia, quanto mais responsabilidades alocadas a entities melhor…

Rodrigo Y.

Vc tem como me explicar melhor isso ?

Qual parte você não entendeu?

Rodrigo, não dá pra injetar nada no Entity Bean pois ele não é mais gerenciado pelo conteiner (só o seu estado persistente é gerenciado pelo EntityManager).

Nesse caso a coisa vai ficar um pouco procedural mesmo, com a lógica de cancelar em um session bean.

Ou você pode talvez usar um pouco de injecão de dependências (gerenciada por você mesmo):

[code] @Entity
public class Duplicata {

  private Long id;
  private Date vencto;
  private BigDecimal valor;
  private String cedente;

  private Cancelador cancelador;
  public Duplicata(Cancelador cancelador) {
    this.cancelador = cancelador;
  }

 public void cancelar() {
    cancelador.cancelar(this);
 } 

}[/code]
No session bean você injeta o Cancelador adequado na sua duplicata. Só precisa de um construtor padrão (não precisa ser público), obrigatório para toda @Entity.

Sim, é o que tenho feito, geralmente usando um Factory para injetar as dependências…

A discussão tomou um outro rumo muito bom: “É uma boa idéia alocar o máximo de inteligência no entity?”

[quote=rodrigoy]“É uma boa idéia alocar o máximo de inteligência no entity?”
[/quote]

Eu uso bastante bom senso…
Minha resposta vazia seria: “desde que a inteligência seja suficientemente relacionada à entidade”

[quote=Guerr@]Na minha opinião, colocar um método cancelar na clase Duplicata, sendo que este deve acessar um serviço remoto e atualizar o banco de dados, acho a mesma coisa que criar o método “inserir” dentro da própria classe Duplicata.

Acho que o correto seria criar um método cancelar() dentro da classe Duplicada para que ele gerenciasse o estado interno de uma instância quando a duplicada fosse cancelada. Desta forma existiria um serviço que pegaria uma instância de Duplicata detached, chamaria o método cancelar() e sincronizaria seu estado com o banco a partir de um EntityManger. Desta forma separaríamos a lógica de negócios do método cancelar() com a execução de um serviço que sincroniza isto com o banco de dados e possivelmente pode ser executado remotamente.

Esta é minha visão arquitetural de como resolver este problema. Aguardo a opinião do pessoal a respeito.[/quote]

Acho complicado adicionar um método de negócio num entity, mesmo que esse trate dele mesmo.

Na minha visão, Entity deveriam persistir somente e negócios na camada business.

Logo você nunca chamaria cancelar duplicada de um entity e sim o passaria como parâmetro para uma business class tratar isso. Mesmo que a regra de negócio trate somente a entidade em questão, não acho elegante e nem faz bem para a manutenibilidade do sistema.