[VRaptor] Vraptor does not support this interface or abstract type

15 respostas
renanpto

Boa Noite,

Temos um sistema implementado com VRaptor que a parte de entidades do hibernate foram abstraidas com interfaces, todo mapeamento do hibernate está correto.

Mas nos deparamos com um detalhe no funcionamento do VRaptor para fazer a criação dos objetos ao chegar nos controllers,…

Os controllers do VRaptor não sofreram mudanças apos a alteracao das classes do hibernate, pois o VRaptor precisa conhecer a classe concreta que deve ser criada para receber os parametros da requisicao…

O problema que mesmo especificando o objeto concreto no controllers, os relacionamentos da classe estão abstraidas pelas interfaces, assim para o VRaptor conseguir setar os parametros desse objeto ele deve estar os atributos já instaciados.

Exemplo de um modelo que esse problema pode ser avaliado…
Interface Pessoa e Endereco

inteface Pessoa {
   void setNome(String nome);
   String getNome();
   Endereco getEndereco();
   void setEndereco(Endereco e);
}

inteface Endereco {
   void setRua(String nome);
   String getRua();
}

Implementação:

public class PessoaImpl implements Pessoa {
   void setNome(String nome){
      .................
   }
   String getNome() {
   ........
   }
   Endereco getEndereco(){....}
   void setEndereco(Endereco e){....}
}
public class EnderecoImpl implements Endereco {
   void setRua(String nome){
      .................
   }
   String getRua() {
   ........
   }
}

Metodo do controller:

public void salvar(PessoaImpl pessoaImpl) {
..... salva a pessoa
}

Recebendo a requisicao o VRaptor não consegue instanciar a classe EnderecoImpl…

Queria saber se há alguma maneira que posso fazer para contornar esse problema e oferecer uma solucao para que o VRaptor consiga utilizar as implementacoes corretas…

Obrigado galera…

15 Respostas

G

Este comportamento está correto. Você tem um objeto do tipo Endereco dentro de PessoaImpl. Como o VRaptor vai saber se deve instanciar EnderecoImpl ou EnderecoBolinha ou até mesmo EnderecoDaMinhaCasa? Não há como.

G

Só para complementar…

Em Java você tem os métodos Class.getSuperclass() e Class.getInterfaces(), mas você não tem um Class.getImplementations(). Ou seja, dinamicamente você não tem como descobrir qual implementação correta a usar.

Lucas_Cavalcanti

só por curiosidade: qual é a motivação para as entidades serem interfaces?

renanpto

Sim, exatamente…

renanpto

É que existe um projeto “padrao” que está divido em modulos, esses modulos possuem classes de negocio que conhecem a interfaces das classes concretas…
Desse projeto, existe outros projetos paralelos (posso dizer filhos, mas diferentes) que utilizam alguns modulos em comum desse projeto “padrao” (gerenciadas pela Maven), mas suas entidades tendo peculariedades…
Dessa forma essas entidades especificas são abstraidas por uma interface e que é conhecida pela classe do projeto “padrao”…
Exemplo:
Interface Produto.

interface Produto {
  Integer getId();
  void setId(Integer id);
  String getNome();
  void setNome(String nome);
}

Implementacao especifica:

class ProdutoEspecifico implements Produto{ 
  /*Atributo especifico do Projeto. */
  private AtributoEspecifico atributoEspecifico;

  public Integer getId(){}
  public void setId(Integer id){}
  public String getNome(){}
  public  void setNome(String nome) {}
  public void setAtributoEspecifico(AtributoEspecifico s) {}
  public AtributoEspecifico getAtributoEspecifico() {}
}

Pelo modelo, a classe concreta ProdutoEspecifico é conhecida apenas pelo projeto “paralelo” e tem regras especificas do mapeamento do Hibernate.
Com isso, o projeto especifico consegue utilizar metodos de negocio de um modulo do projeto “padrao” sem nenhum problema… pois a classe especifica está abstraida pela interface Produto.
Esse reaproveitamento é feito apenas em classes de negocio…
Cada projeto tem os seus controllers e conhecem as implementacoes que atende as requisicoes…

renanpto

garcia-jj:
Só para complementar…

Em Java você tem os métodos Class.getSuperclass() e Class.getInterfaces(), mas você não tem um Class.getImplementations(). Ou seja, dinamicamente você não tem como descobrir qual implementação correta a usar.


Voce tem toda razao, não há como identificar a implementacao com base na interface ou classe abstrata…
Por isso os mapeamentos do JPA/Hibernate é necessário adicionar o atributo targetEntity que define a classe concreta que implementa tal interface.
Dinamicamente acredito que seja possivel, usando algumas alternativas (mapeados em txt ou xml, etc).

G

Eu não acho essa abordagem correta. Até porque se é ter uma interface e uma única implementação não há motivos para ter abstração. Pelo menos não nas entidades persistentes. Se você tem que definir o targetEntity sua implementação está amarrada, sendo assim não vejo ganho com tal abstração. Para mim o único ganho é de complexidade.

Mas se mesmo assim você quer usar isso, talvez você possa alterar alguma coisa nas classes do OGNL, para quando ele injetar o objeto tentar procurar pelo targetEntity e instanciar tal classe.

renanpto

garcia-jj:
Eu não acho essa abordagem correta. Até porque se é ter uma interface e uma única implementação não há motivos para ter abstração. Pelo menos não nas entidades persistentes. Se você tem que definir o targetEntity sua implementação está amarrada, sendo assim não vejo ganho com tal abstração. Para mim o único ganho é de complexidade.

Mas se mesmo assim você quer usar isso, talvez você possa alterar alguma coisa nas classes do OGNL, para quando ele injetar o objeto tentar procurar pelo targetEntity e instanciar tal classe.


Eu concordo com você, caso seu modelo tenha apenas uma unica implementação das classes persistentes.
No meu contexto, eu posso ter N projetos (clientes) que podem conhecer/utilizar as interfaces das entidades (justamente para aproveitar classes em comum).
Seguindo essa ideia:
Projeto padrao, dividido dessa forma:

projeto-padrao
[b](definicao interfaces e implmentacoes classes negocio)[/b]
projeto-padrao-modulo-a 
projeto-padrao-modulo-b
projeto-padrao-modulo-c
projeto-padrao-modulo-a-impl
projeto-padrao-modulo-b-impl
projeto-padrao-modulo-c-impl

Agora um projetos unicos, que tem seus proprios modelos de dados e que utilizam modulos do projeto-padrao.

projeto-xxxx
projeto-entity-impl (aqui estão os mapeamentos das classes persistentes)
[i] - depende do projeto-padrao-modulo-a e projeto-padrao-modulo-b[/i]
projeto-zzzz
projeto-entity-impl (aqui estão os mapeamentos das classes persistentes)
[i] - depende do projeto-padrao-modulo-c[/i]

A implementação está amarrada mesmo, mas cada projeto especifico tem seus proprios mapeamentos. Não havendo o vinculo com as implementacoes de classes persistentes do “projeto-padrao”.

O ganho que tenho com esse modelo, é que alterações em modulos do “projeto-padrao” serão refletidas em todos os projetos especificos que dependem dele. Não nos obrigando a sair fazendo Ctrl + C e Ctrl + V em todos os projetos especificos, só pq um bug em uma classe foi corrigido.

Pelo menos essa foi a maneira mais simples para incluir o reproveitamento de modulos em comum do sistema.

Lucas_Cavalcanti

e pq não ter a entidade concreta no projeto padrão?

em todo caso, dá pra ensinar o VRaptor a instanciar a classe concreta, a partir da interface.

para isso vc vai ter que sobrescrever o componente que usa o OGNL…
sugiro que vc use o último snapshot do VRaptor para fazer isso:
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.4.0-SNAPSHOT/vraptor-3.4.0-20110505.142301-2.jar

pois foi feita uma grande refatoração que facilita a extensão do ognl…

se quiser fazer isso posso te dar dicas de como fazer

renanpto

Lucas Cavalcanti:
e pq não ter a entidade concreta no projeto padrão?

em todo caso, dá pra ensinar o VRaptor a instanciar a classe concreta, a partir da interface.

para isso vc vai ter que sobrescrever o componente que usa o OGNL…
sugiro que vc use o último snapshot do VRaptor para fazer isso:
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.4.0-SNAPSHOT/vraptor-3.4.0-20110505.142301-2.jar

pois foi feita uma grande refatoração que facilita a extensão do ognl…

se quiser fazer isso posso te dar dicas de como fazer


Boa Noite Lucas,

Porque os projetos especificos pode/tem suas peculariedades, e um detalhe, o projeto padrao possui uma implementacao das classes persistentes que somente ele conhece (é um modelo padrao). Modulos que possuem funcionalidades em comum conhecem a classe concreta em runtime, por isso esses modulos podem ser reaproveitados pelos projetos especificos.
Apenas para esclarecer, o módulo é composto por classes de negócio que atendem funcionalidades especificas do produto.

Pense na seguinte situacao a nivel de negocio que estamos atendendo:

1 - Um produto/projeto com N funcionalidades;

2 - Oferecer ao cliente a possibilidade de customizar cada funcionalidade conforme a necessidade;

3 - Incluir novas funcionalidades sem afetar o produto padrão;

4 - Ganho na manutenção desses projetos;

5 - Re-aproveitamento de código.

Concerteza, quero fazer essa customização. O que tenho que fazer ?

Agradeço muito pela ajuda e o contato.

Lucas_Cavalcanti

bom, faz sentido customizar as lógicas de negócio, não as entidades… me parece um overengeneering bem forte, mas tudo bem…

com a última versão do VRaptor (do snapshot que eu gerei agora)
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.4.0-SNAPSHOT/vraptor-3.4.0-20110603.121952-3.jar
, implemente a seguinte classe:

@Component
public class CustomOgnlFacade extends OgnlFacade {
     //delegate constructor

     @Override
     protected NullHandler nullHandler() {
            final NullHandler delegate = super.nullHandler();

            return new NullHandler() {
                public <T> T instantiate(Class<T> baseType) {
                     if (é uma das suas interfaces marotas) {
                           return new ImplementacaoMarota();
                     }
                     return delegate.instantiate(baseType);
                }
            };
     }
}

isso deve resolver o seu problema… só tenta descobrir um jeito fácil de descobrir qual é a implementação da interface

renanpto

Lucas Cavalcanti:
bom, faz sentido customizar as lógicas de negócio, não as entidades… me parece um overengeneering bem forte, mas tudo bem…

com a última versão do VRaptor (do snapshot que eu gerei agora)
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.4.0-SNAPSHOT/vraptor-3.4.0-20110603.121952-3.jar
, implemente a seguinte classe:

@Component
public class CustomOgnlFacade extends OgnlFacade {
     //delegate constructor

     @Override
     protected NullHandler nullHandler() {
            final NullHandler delegate = super.nullHandler();

            return new NullHandler() {
                public <T> T instantiate(Class<T> baseType) {
                     if (é uma das suas interfaces marotas) {
                           return new ImplementacaoMarota();
                     }
                     return delegate.instantiate(baseType);
                }
            };
     }
}

isso deve resolver o seu problema… só tenta descobrir um jeito fácil de descobrir qual é a implementação da interface


Heheh, na verdade não é customização/reaproveitamento das entidades, pois cada projeto especifico possui uma implementacao das entidades que atendam aquelas interfaces.
Como disse antes a interface é so abstração para usar classes de negocio dos modulos do projeto padrao…
Gostei do if:

if (é uma das suas interfaces marotas) {
               return new ImplementacaoMarota();
      }

kkkkkk.
BLz, assim que conseguir testar eu aviso o final da história…
Obrigado Lucas. Ajudou muito.

renanpto

Lucas, a interface br.com.caelum.vraptor.http.ognl.NullHandler não é visivel fora do seu proprio pacote…

Ela está sem o modificador de acesso.

Lucas_Cavalcanti

oh shit =S

usa esse snapshot então:
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.4.0-SNAPSHOT/vraptor-3.4.0-20110603.181243-4.jar

renanpto

Lucas Cavalcanti:
oh shit =S

usa esse snapshot então:
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.4.0-SNAPSHOT/vraptor-3.4.0-20110603.181243-4.jar


Blza… funcionou… =D

Obrigado novamente.

Criado 1 de junho de 2011
Ultima resposta 3 de jun. de 2011
Respostas 15
Participantes 3