Injetando no Entity

34 respostas
R

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

34 Respostas

O

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.

G

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?

O

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.

G

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

M

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

O

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

C

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.

T

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.

G

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.

T

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.

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

O

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

R

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…

R

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.

O

Vc tem como me explicar melhor isso ?

R

Qual parte você não entendeu?

F

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):
@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);
     } 
   }
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.
R

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?”

F

rodrigoy:
“É uma boa idéia alocar o máximo de inteligência no entity?”

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

K

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.

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.

P

Fabio Kung:
rodrigoy:
“É uma boa idéia alocar o máximo de inteligência no entity?”

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

foi uma boa observação essa sua

:wink:

O

Em sistemas complexos que vão além de operações CRUD é primordial o uso de operações de negócio nos entities.

K

okara:
‘kenobi’:

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

Em sistemas complexos que vão além de operações CRUD é primordial o uso de operações de negócio nos entities.

Sinceramente não gosto desse approach de desenvolvimento, entretanto sou flexível à mudança, se eu perceber que está correto o paradigma, seu ponto de vista.

Alguém pra argumentar à favor ?

T

Mas não é isso que a OO diz para fazer?

Na minha visão, o entity não persisti. O seu estado é persistido. É ai que começa a confusão. É o entity quem sabe gerenciar o seu próprio estado, e não uma outra camada do sistema.

Aqui eu encaro o seguinte: A view informa a fachada solicitando o cancelamento da duplicata. A fachada por sua vez recebe o entity e chama o método cancela (do entity) para que o seu estado corresponda a uma duplicata cancelada. Depois é só salvar o estado do entity. Ou seja:

public void cancelaDuplicata(Duplicata duplicata) {

duplicata.cancela();
duplicata.save(); // ou entityManager.save(duplicata), por exemplo

}

Ao meu ver, a manutenção vai ficar mais fácil. Por que não faz bem para a manutenabilidade do sistema?

F

Esse é mais um caso para o Shoes.

Kenobi:
Alguém pra argumentar à favor ?
Não vou ser eu Felipe! ;)

É claro que OO não resolve todos os problemas do mundo, mas separar os dados (seus Entities = structs) da lógica (suas Business classes = biblioteca de funções) é procedural demais.

A questão seria então debater se OO é melhor ou não que programação procedural para estes casos. Acredito que o tempo já tenha dado a resposta.

Thiago Senna:
Aqui eu encaro o seguinte: A view informa a fachada solicitando o cancelamento da duplicata. A fachada por sua vez recebe o entity e chama o método cancela (do entity) para que o seu estado corresponda a uma duplicata cancelada. Depois é só salvar o estado do entity. Ou seja:
public void cancelaDuplicata(Duplicata duplicata) {

duplicata.cancela();
duplicata.save(); // ou entityManager.save(duplicata), por exemplo

}
Também acho que é bem por aí. Essa fachada serve bem para demarcar uma transação/caso de uso e o domain model é responsável pela lógica de negócios.

A criação de classes a mais de fachada (essa com o método cancelaDuplicata, por exemplo) ainda é um pouco discutível, tendo em vista que (dependendo do contexto) essa "fachada" poderia ser diretamente a sua Servlet, Action, Componente, SessionBean, WebService, .

Eu disse dependendo do contexto pq alguns poucos cenários exigem essa camada a mais de fachadas (vale a pena um exemplo?). Nos tempos de hoje o reaproveitamento é alcançável expondo os serviços (webservices, rest, ejbs, ...) e quanto mais simples a coisa for, melhor.

Kenobi:
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.
Diria o contrário. Que tal uma relida nos artigos do shoes acima?
K

Realmente reli e baixei o livro de DDD do InfoQ.

Preciso começar a mudar a forma de pensar, que foram sendo injetadas na mente durante anos de Design Patterns publicados como boas práticas entre outros.

É um novo paradigma e conceito, precisa pensar analisar e amadurecer a arquitetura para tirar proveito de tal.

Chun, como disse, se provar que estou errado como foi o caso, eu mudo minha forma de pensar… afinal, insistir no erro é complicado.

Gosto de discutir idéias até pra adotar outra linha de pensamento e expandir as possibilidades :slight_smile:

F

Quem bom seria, se todos fossem assim!

R

Bom, vou passar um pouco da minha experiência aqui. Alocar o máximo de inteligência nos entities aproxima seu modelo de objetos ao modelo de negócios e isso é muito bom para a coesão e manutenção do sistema. Entities que refletem o negócio até exigem menor esforço de documentação do sistema.

Mas como todas as decisões arquiteturais, isso deixa efeitos colaterais no seu colo como já discutimos aqui. Para uma arquitetura Spring e EJB3 que são as abordagens mais utilizadas para Java, não é natural que um entity manipule, ou crie outros entities que não fazem parte de uma associação.

As coisas estão melhorando bastante, mas ainda tem muito a evoluir!

Um dos problemas que vejo é que as arquiteturas ou alguns workarounds que são definidos como “patterns” algumas vezes forçam os desenvolvedores a cometerem erros.

O

É verdade Rodrigo, parece que os grandes players do mercado não “incentivam” o uso do conceito de domain model.

B

Meio atrasado, mas vou tentar fazer uma humilde contribuicao.

Acho que muitos nao recomendam o modelo de dominio pois e dificil atingir uma boa velocidade de desenvolvimento! Estou tentando a um tempo ta dificil! E tbem cada caso e um caso imagina fazer um soft pro seu Jose da padaria usando DM, acho que realmente tem que dozar.

Voltando a discussao:

Sempre que penso em persistir um estado de um objeto me vem o Memento do GoF na mente!
Sera que nao seria uma boa aplicacao para o memento?

Po mas o memento so tem dados dentro dele sera um : Anemic, Fantoche? Cade a coesao?

Sera que o memento fere a OO como o DTO o Comand??

Nao sei, mas ainda acho que memento seria uma boa pedida para persistir o estado de um objeto ainda mais porque ele mante a encapsulamento do objeto!

Aguardo a opiniao de vcs…

Alguem pode me passar o link do livro DDD citado pelo Kenobi?

T

brunohansen:
Sempre que penso em persistir um estado de um objeto me vem o Memento do GoF na mente!
Sera que nao seria uma boa aplicacao para o memento?

Lembro do Shoes ter comentado sobre este assunto. Fiz uma busca e encontrei isso:

http://www.guj.com.br/posts/list/15/28889.java
http://www.guj.com.br/posts/list/60/24210.java

D
B

Thiago Senna:
brunohansen:
Sempre que penso em persistir um estado de um objeto me vem o Memento do GoF na mente!
Sera que nao seria uma boa aplicacao para o memento?

Lembro do Shoes ter comentado sobre este assunto. Fiz uma busca e encontrei isso:

http://www.guj.com.br/posts/list/15/28889.java
http://www.guj.com.br/posts/list/60/24210.java

Dei uma lida! Me pareceu que no inicio o shoes gostou da ideia de usar memento mas depois desaprovou por causa dos grandes sistema e da zona que eles se tornaram por causa dos mementos.

Mas nao vi nada de muito concreto! Sera que no mundo da engenharia de soft um dia vai existir algo de concreto?

B

Kenobi:
Preciso começar a mudar a forma de pensar, que foram sendo injetadas na mente durante anos de Design Patterns publicados como boas práticas entre outros.

Fiquei confuso com essa reflexao!
Vc quer mudar a forma de pensar que os padroes te proporcionaram ?
Se sim pq?

Aee duende valew pelo link!!!

S

Bom, até onde eu aprendi, o conceito de OO difere da estrutural exatamente pelo motivo de existir Entidades com Responsabilidades.

Então, não acho que seja errado colocar métodos de negócio dentro de um Entity, desde que esse método seja realmente pertinente a ele.

Utilizar Business Class pra fazer todo o trabalho, acaba transformando os Entitys em simples VO’s, com a facilidade da persistência.

Claro que tb não vamos exagerar e sair colocando 500 métodos de negócio em um Entity, mais questões como Persistir, atualizar, cancelar e apagar, acho que seja legal sim.

Um outro conceito, se eu tenho uma Entidade chamada Predio, a qual agrega várias salas e apartamentos, pq não colocar um método para atualizar todas as salas dentro da entidade Prédio, ao invés de utilizar uma Business só para isso ?

Agente acaba tendo que instanciar sempre uma Business e uma Entity para fazer o trabalho que resolveríamos apenas com a Entity.

Já utilizei essa arquitetura (se não estou enganado, chamam de Active Record) em alguns projetos, e deram bastante resultado.

Agora, voltando ao problema inicial, tem como injetar o Session dentro do Entity no EJB3 ou terei que usar um bom e velho LookUp ?

Criado 30 de novembro de 2006
Ultima resposta 23 de jan. de 2007
Respostas 34
Participantes 12