Erro de ClassCastException utilizando Herança no Controller

Pessoal,

Estou iniciando um novo projeto com o vraptor 3.1.3.
Percebi que agora está suportando herança nos controllers, entao fiz o seguinte:

[code]public class AbstractController{

protected final Repository<T> repository;
protected final Result result;

public AbstractController(Repository<T> repository, Result result) {
	this.repository = repository;
	this.result = result;
}

public void form() {
	...
}

public void list() {
	...
}

@Path("/edit/{entity.id}")
public void edit(T entity) {
	...
}

@Path("/del")
public void delete(T entity) {
	...
}

@Post
@Path("/save")
public void save(T entity) {
	...
}

}[/code]

Meus controllers ficaram da seguinte maneira:

[code]public class ClasseController extends AbstractController {

public ClasseController(ClasseRepository repository, Result result) {
	super(repository, result);
}

}[/code]

[code]public class MetodoController extends AbstractController {

public MetodoController(MetodoRepository repository, Result result) {
	super(repository, result);
}

}[/code]

E tudo funcionava as mil maravilhas…
Ate que resolvi adicionar um metodo de pesquisa Generico (utilizando o Example do Hibernate) no AbstractController.
Assim meu metodo find, ficou:

@Path("/find") public void find(T entity) throws RepositoryException{ List<T> entityList = new ArrayList<T>(); if (entity.getId() > 0) { entityList.add( repository.findById(entity.getId()) ); } else { entityList.addAll( repository.findByExample(entity) ); } ... }

Resultado: O findById funciona e o findByExample nao (apenas para o metodo find do abstract controller).

Debugando, percebi que ao passar o id, o objeto entity corresponde a classe correta. Ao chamar o findByExample o entity vem com um objeto errado.
O exemplo da view:

<form method="post" action="$base/classe/find"> <fieldset> <legend>Buscar</legend> <label>Código</label> <input type="text" name="entity.id"/> <label>Nome</label> <input type="text" name="entity.nome"/> <input type="submit" value="OK"/> </fieldset> </form>

<form method="post" action="$base/metodo/find"> <fieldset> <legend>Buscar</legend> <label>Código</label> <input type="text" name="entity.id"/> <label>Nome</label> <input type="text" name="entity.nome"/> <input type="submit" value="OK"/> </fieldset> </form>

Detalhe: Ao parar o servidor, vai funcionar o example com o primeiro form que eu tentar. Na segunda tentativa, se eu tentar o example no segundo form, vai dar o erro (java.lang.ClassCastException):

Buscando o Objeto Classe, o cast foi dado para “Metodo”

17:00:57,979 DEBUG [OgnlParametersProvider] Applying entity.nome with [Administrador] 17:00:57,987 DEBUG [OgnlParametersProvider] Applying entity.id with [] 17:00:57,990 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for AbstractController.find(Persistent) as [entity] 17:00:57,991 DEBUG [ParametersInstantiatorInterceptor] Parameter values for [DefaultResourceMethod: AbstractController.findAbstractController.find(Persistent)] are [admin.dominio.Metodo@3caf7a1f] 17:00:58,013 DEBUG [ToInstantiateInterceptorHandler] Invoking interceptor ExecuteMethodInterceptor 17:00:58,014 DEBUG [ExecuteMethodInterceptor] Invoking AbstractController.find(Persistent) br.com.caelum.vraptor.InterceptionException: an exception was raised while executing resource method at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:86) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:86) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:42) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:47) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at arq.infra.ErrorInterceptor.intercept(ErrorInterceptor.java:34) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:47) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:46) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:81) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65) at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:70) at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92) at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56) at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:242) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129) at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:242) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:243) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:201) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:163) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:108) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:556) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:401) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:242) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:267) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:245) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:260) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:662) Caused by: java.lang.ClassCastException: admin.dominio.Metodo at org.hibernate.criterion.Example.getEntityMode(Example.java:279) at org.hibernate.criterion.Example.toSqlString(Example.java:209) at org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition(CriteriaQueryTranslator.java:380) at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:114) at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:83) at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:92) at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1687) at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) at arq.hibernate.GenericDao.findByExample(GenericDao.java:108) at arq.controller.AbstractController.find(AbstractController.java:89) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:57)

Errei em algum ponto, ou algum bug (algo que o vrpator nao suporta ainda) detectado?

atualize para a versão 3.2.0, ela corrigiu alguns problemas de herança

Mesma coisa :frowning:

suba o servidor como debug, coloque um breakpoint no método find, e veja qual é a classe da entity…

e veja dentro do código do repository o que ele tá esperando…

de qqer forma, qual é o código do findByExample?

[quote=Lucas Cavalcanti]suba o servidor como debug, coloque um breakpoint no método find, e veja qual é a classe da entity…

e veja dentro do código do repository o que ele tá esperando…

de qqer forma, qual é o código do findByExample?[/quote]

Repositorio

public class GenericDao<T extends Persistent> implements Repository<T> { public List<T> findByExample(T entity){ return session.createCriteria(getPersistentClass()) .add( Example.create(entity).enableLike(MatchMode.EXACT) ) .list(); } }

Se eu chamar $base/sistema/find (após ter feito a busca uma primeira vez pela url $base/metodo/find - e encontrado os registros com sucesso), no debug se eu não passar o id, minha entity é metodo (deveria ser sistema). Se eu passar o id, minha entity vem correta (sistema).

@Path("/find") public void find(T entity) throws RepositoryException{ List<T> entityList = new ArrayList<T>(); beforeFind(); if (entity.getId() > 0) { entityList.add( repository.findById(entity.getId()) ); } else { entityList.addAll( repository.findByExample(entity) ); } customResult.put("entityList", entityList); afterFind(); redirectAfterFind(); }

está acontecendo algum redirect no meio do caminho?

o html tá apontando pro caminho certo?

vc tá usando o mesmo formulário para com id e sem id?

[quote=Lucas Cavalcanti]está acontecendo algum redirect no meio do caminho?

o html tá apontando pro caminho certo?

vc tá usando o mesmo formulário para com id e sem id?[/quote]

  1. nenhum redirect no meio do caminho.

  2. o html está apontando pro caminho certo (ver codigo abaixo).

  3. é o mesmo formulario sim. E sempre funciona a primeira vez depois que starto o serviço (funciona a primeira vez pra determinado formulario), quando passo para o segundo form, nao funciona.
    Detalhe: Apesar das classes terem campos diferentes, eu estou colocando apenas 2 campos, que por coincidencia são iguais (classes diferentes com atributos iguais):

    [code]

    Buscar
    Código

    Nome


    [/code]

<form method="post" action="$base/metodo/find"> <fieldset> <legend>Buscar</legend> <label>Código</label> <input type="text" name="entity.id"/> <label>Nome</label> <input type="text" name="entity.nome"/> <input type="submit" value="OK"/> </fieldset> </form>

[code]public class Classe{

private int id;
private String nome;
private String pacote;
private String descricao;


}[/code]

[code]public class Metodo{

private int id;
private String nome;
private Classe classe;


}[/code]

O erro de ClassCastException dá nesta linha:

Opsss Piorou a situação…

Notei que os outros metodos que usam herança nao estão funcionando também…
Tipo:
Se eu salvar um form cuja entidade é Sistema e depois for pra outro form cuja entidade é classe, ele salva o sistema duas vezes. Como as informações são diferentes, ele está salvando com valores diferentes mesmo…
Pelo que estou entendendo ele nao está identificando a que classe a entidade se refere… Provavelmente isto se dá porque o nome dos atributos no form é “entity” e não estou fazendo este mapeamento nos controllers filhos e sim só no AbstractController…

vc tah anotando seus controllers com o que?

@Resource e @Path? ou só @Resource?

vc tah usando o spring, guice ou pico?

[quote=Lucas Cavalcanti]vc tah anotando seus controllers com o que?

@Resource e @Path? ou só @Resource?

vc tah usando o spring, guice ou pico?

[/quote]

Os controllers filhos estão com @Resource.
O AbstractController só tem anotações nos @Path
To usando Spring.

vou tentar reproduzir isso aqui, mas não deveria estar funcionando se vc não colocar @Path na classe dos filhos… o vraptor deveria estar reclamando de rotas duplicadas

Em uma versao mais antiga do vraptor, eu não consegui usar herança da maneira como expus no problema acima. Nas classes filhas eu tinha que repetir o metodo e alterar os paths assim:

ClasseFilhaController

@Path("/edit/{livro.id}") public void edit(Livro livro) { super.edit(livro); }

Isso ai funciona, mas acaba com a abordagem que eu gostaria de fazer, usando herança nestes controllers…

Tenta fazer o seguinte:

anote a classe MetodoController com @Path("/metodo") e a classe SistemaController com @Path("/sistema")

e as urls das lógicas seria /metodo/edit/{…}, etc

[quote=Lucas Cavalcanti]Tenta fazer o seguinte:

anote a classe MetodoController com @Path("/metodo") e a classe SistemaController com @Path("/sistema")

e as urls das lógicas seria /metodo/edit/{…}, etc[/quote]

Acho que esqueci de mencionar isto, mas já estão…

Exemplo:

@Path("/sistema") @Resource public class SistemaController extends AbstractController<Sistema>

desculpe a demora…

tentei simular aqui, mas a única coisa que eu recebi foi uma NullPointerException nessa linha quando eu não preencho o id da entidade:

 if (entity.getId() > 0) {  

(entity é diferente de null mas id é null e é Long)

vc ainda tá com esse problema? tem como passar um projetinho simples que simula o bug?

Abraços

Ainda estou com esse problema sim.
Assim que chegar no trabalho lhe mando o projeto.
No meu caso o id é int, por isso nunca vem nulo (default é 0).
Testa dessa forma…

não consegui reproduzir aqui =(

tem como me passar um projetinho simples que simula esse bug?
pode ser por zip aqui (não precisa das libs)

[quote=Lucas Cavalcanti]não consegui reproduzir aqui =(

tem como me passar um projetinho simples que simula esse bug?
pode ser por zip aqui (não precisa das libs)[/quote]

Segue o projeto sem as libs.
Estou usando Velocity também.

Para simular, voce faz todas as operações (CRUD) com uma unica entidade (Sistema por exemplo) e depois faz as mesmas coisas com a outra entidade (Grupo, no caso).

aqui funcionou normalmente =(

diferenças:

Tenta mudar algumas dessas coisas e vê se muda o problema…
tenta também dar um clean no seu projeto, pode ser q tenha classes antigas que zoam as operações do vraptor.

se não der certo, me manda o log debug da requisição problemática

[]'s

Não estou conseguindo testar com esse jar que vc sugeriu. Está dando erro ao mandar procurar…

Estou usando o google-collect-1.0.jar

java.lang.NoSuchMethodError: com.google.common.base.Predicates.containsPattern(Ljava/lang/String;)Lcom/google/common/base/Predicate; br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.parametersThatStartWith(OgnlParametersProvider.java:244) br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.getParametersFor(OgnlParametersProvider.java:100) br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.getParametersFor(ParametersInstantiatorInterceptor.java:105) br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:77) br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53) br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:46) br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53) br.com.caelum.vraptor.util.hibernate.HibernateTransactionInterceptor.intercept(HibernateTransactionInterceptor.java:45) br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53) br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:44) br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53) br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:81) br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53) br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67) br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53) br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53) br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:70) br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92) br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56) br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)