Erro de ClassCastException utilizando Herança no Controller

21 respostas
R

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:

public class AbstractController<T extends Persistent>{

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

}

Meus controllers ficaram da seguinte maneira:

public class ClasseController extends AbstractController<Classe> {

	public ClasseController(ClasseRepository repository, Result result) {
		super(repository, result);
	}
	
}
public class MetodoController extends AbstractController<Metodo> {

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

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?

21 Respostas

Lucas_Cavalcanti

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

R

Mesma coisa :frowning:

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?

R

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?

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(); }

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?

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

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

<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>
public class Classe{

	private int id;
	private String nome;
	private String pacote;
	private String descricao;
...
}
public class Metodo{

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

O erro de ClassCastException dá nesta linha:

entityList.addAll( repository.findByExample(entity) );
R

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…

Lucas_Cavalcanti

vc tah anotando seus controllers com o que?

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

vc tah usando o spring, guice ou pico?

R

Lucas Cavalcanti:
vc tah anotando seus controllers com o que?

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

vc tah usando o spring, guice ou pico?

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

Lucas_Cavalcanti

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

R

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…

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

R

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

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

Exemplo:

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

Lucas_Cavalcanti

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

R

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…

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)

R

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)

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

Lucas_Cavalcanti

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

R

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)

Lucas_Cavalcanti

troque esse google-collect pelo guava
https://github.com/caelum/vraptor/blob/master/vraptor-core/lib/mandatory/guava-r07.jar

R

Testes iniciais indicam que o problema está realmente resolvido, após a atualização do jar com essa versão snapshot (vraptor-3.2.1-20101214.180111-8.jar) e a atualização do guava.
Vou continuar testando e qualquer coisa aviso aqui. Valeu Lucas!

Criado 7 de dezembro de 2010
Ultima resposta 16 de dez. de 2010
Respostas 21
Participantes 2