VRaptor + jQuery ajax - Não está passando os parâmetros

25 respostas
R

Boa tarde!

Eu estou tentando fazer um crud que usa Ajax para fazer o save, então no data desse ajax eu estou passando os inputs, assim:

{"obj.email": "[email removido]",  
"obj.groups[0]": 1,  
"obj.groups[1]": 2,  
"obj.groups[2]": 3,  
"obj.id": "1",  
"obj.name": "ADMINISTRATOR",  
"obj.status": "ATIVO",  
"obj.username": "admin"}

Porém, eu percebi que o VRaptor estava acionando o meu converter de User:

@Convert(User.class)
public class UserConverter implements Converter<User> {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	private UserDAO dao;

	public UserConverter(UserDAO dao) {
		this.dao = dao;
	}

	@Override
	public User convert(String value, Class<? extends User> type,
			ResourceBundle bundle) {
		try {
			return this.dao.get(Long.parseLong(value));
		} catch (NumberFormatException e) {
			logger.warn("Unable to convert to long. Value: '" + value + "'\n"
					+ e.getMessage());
		} catch (HibernateException e) {
			logger.warn("Unable to get this record. Value: '" + value + "'\n"
					+ e.getMessage());
		} catch (Exception e) {
			logger.warn("An error occured. Value: '" + value + "'\n"
					+ e.getMessage());
		}
		return new User();
	}
}

Como ele retorna uma instância de User, ele está chegando assim no meu controller:

User: {id:null, name:'null', status:'null', email:'null', username:'null', language:'null'}

Minha dúvida é: ele não deveria acionar o converter, certo?

É algo que eu estou passando errado no data do ajax? :frowning:

25 Respostas

L

ele só chama o converter se tiver um parametro do request que é o caminho para um user, por exemplo:

user=1
//ou
algumaCoisa.user=1
R

Então, nesse request não tem. Mas em outro request ele faz certinho. Será que ele não está chamando o converter por que ele não encontrou ninguém que populasse aquele dado? Pois no meu log, ele está chamando o converter e mandando value = “”…

17/01/13 16:24:31 WARN hamburgsud.frontend.converter.UserConverter:31 Unable to convert to long. Value: '' For input string: ""
Eu coloquei esse código para interceptar o que estava sendo enviado ao servidor:

$(document).ajaxSend(function(event, jqXHR, ajaxOptions){
	console.log(ajaxOptions);
});

Verifiquei a saída e ficou assim (eu dei uma arrumada para vizualizarmos melhor):

isAjax=true& obj.name=ADMINISTRATOR& obj.language=en& obj.email=[email removido]& obj.username=admin& obj.status=ATIVO& obj.id=1& obj.groups[0]=1& obj.groups[1]=2& obj.groups[2]=3
Essa primeira variável é para eu interceptar requisições ajax quando o usuário estiver deslogado e devolver um erro 403…

L

tenta trocar o obj.id=1 por obj=1

R

Mas ai ele vai carregar o User com id 1 no meu converter… A ideia é que ele não passe pelo converter dessa vez…

Essa é o update do meu CRUD, preciso pegar o que foi alterado e atualizar…

L

se nenhum dos parâmetros cair num user ele não deveria passar no converter…

tem certeza que não tem nenhum outro parametro perdido na requisição? dá uma olhada num firebug ou no @Path do método.

R

Eu dei uma olhada no Network > Header do Chrome:

Request URL:http://localhost:8080/user/save/
Request Method: POST
Status Code:200 OK

Request Headers
Accept:application/json, text/javascript, /; q=0.01
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:243
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Cookie:JSESSIONID=5771819C524F8DF3BBA791072DAEDFD1
Host:localhost:8080
Origin:http://localhost:8080
Pragma:no-cache
Referer:http://localhost:8080/user
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
X-Requested-With:XMLHttpRequest

Form Data
isAjax:true
"obj.name":ADMINISTRATOR
"obj.language":en
"obj.email":[email removido]
"obj.username":admin
"obj.status":ATIVO
"obj.id":1
"obj.groups[0]":1
"obj.groups[1]":2
"obj.groups[2]":3

Response Headers
Content-Type:application/json;charset=UTF-8
Date:Thu, 17 Jan 2013 19:12:28 GMT
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked

Na parte do Form Data ele lista os parâmetros da requisição… Eu vou tentar retirar a parte que manda o groups para ver se resolve alguma coisa…

EDIT

Antes de remover o group, eu vou colocar aspas entre os valores da requisição… Ele pode estar se perdendo…

L

tenta no servidor debugar e ver o request.getParameterMap(), ver o que tá lá

R

Fiz os dois testes. Ainda ocorre o mesmo problema… :cry:

L

viu os parâmetros que chegaram no servidor?

R

Ah! Eles estão vindo… Porém estão vindo com as aspas que eu coloquei, conforme aquele tópico…

Faz sentido ele não encontrar pois “obj.status” não existe, mas obj.status existe…

Eu preciso ou remover as aspas quando chega no servidor ou mudar a minha forma de enviar parâmetros via ajax…

e se eu fizesse assim no ajax:

data = { obj : { name : "ADMINISTRATOR", language : "en", email : "[email removido]", username : "admin", status : "ATIVO", id : "1", groups : [1, 2, 3] } }
O servidor iria entender?

L

o problema não é o servidor entender… é o como o jquery serializa isso na requisição… dá uma olhada como o browser faz lá no Form Data do chrome

R

É… o jQuery serializou de uma forma estranha:
isAjax:true
obj[name]:ADMINISTRATOR
obj[language]:en
obj[email]:[email removido]
obj[username]:admin
obj[status]:ATIVO
obj[id]:1
obj[groups][]:1
obj[groups][]:2
obj[groups][]:3

Então como que eu faço para remover as aspas dos names das variáveis?
Sobrescrevendo ParanamerProvider?

L

se vc fizer:

data = {  
   "obj.name" : "ADMINISTRATOR",  
   "obj.language" : "en",  
   ... 
}

deve funcionar

R

Isso funciona pois eu já usei assim…

Mas como que eu faço isso, já que eu vou pegar o atributo name do input dinamicamente?

Eu estou fazendo assim:

form.find('[name]').each(function(){ var self = $(this); var name = '"' + self.attr('name') + '"'; data[name] = self.val(); });
Se eu fizer sem essas aspas, ele dá aquela exception maluca…

L
data[self.attr('name')] = self.val();

deveria funcionar…

em todo caso, form.serialize() já faz isso que vc quer :wink:

R

O form.serialize() vai gerar uma String… Se eu passar essa String para o data, vai funcionar?

Mas existe um tipo de elemento que eu estou usando que não é um input… O form.serialize() não iria considerá-lo, e para considerá-lo, eu precisaria transformá-lo em checkbox, o que seria um pouco chato de ser feito…

De todo jeito, isso:

form.find('[name]').each(function(){ var self = $(this); // var name = '"' + self.attr('name') + '"'; data[self.attr('name')] = self.val(); });
Não é a mesma coisa que isso:

form.find('[name]').each(function(){ var self = $(this); // var name = '"' + self.attr('name') + '"'; var name = self.attr('name'); data[name] = self.val(); });
E dessa forma (sem as aspas) dava aquela exception…

L

o data funciona com string sim

se o cara não é um input é o que? o serialize funciona com select e textarea tb.

R
Ele é um ul... Ele tem um atributo chamado "data-name" e eu faço um processo diferente para ele:
form.find('[data-name]').each(function(){
				var self = $(this);
				var name = '"' + self.attr('data-name') + '"';
	
				if (self.hasClass('selectable')) {
					var position = 0;
					self.children().each(function(){
						self = $(this);
						if (self.hasClass('ui-selected'))
							data[name.replace(/\{0\}/g, position++)] = self.val();
					});
				} else if (self.hasClass('ui-selected'))
					data[name] = self.val();
			});
Eu fiz isso para poder usar com o jquery-ui selectable, então dá para usar com tables, ul... Desde que usem o selectable...

Eu vou mudar a minha função para gerar uma String igual o form.serialize() faz... Vou usá-lo e complementar com o que eu vou gerar para o selectable.

L

vc pode fazer ao invés do data[name] = self.val():

form.append($('<input/>' {name: name, value: self.val(), type: "hidden"});

isso só precisa rodar antes do form.serialize();

R

Mas ai eu vou pesar o formulário… No caso do IE8, usar o append deixa muito lento…

Antes de fazer essa conversão eu vou gerar a String, usando um array e depois fazendo um join(’&’)…

R

Tentei com o form.serialize() e ele volta a dar aquela exception:

br.com.caelum.vraptor.http.InvalidParameterException: Exception when trying to instantiate Target(name=obj, type=class hamburgsud.frontend.model.User) at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.handleException(VRaptorInstantiator.java:95) at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:87) at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:80) at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.instantiateOrAddError(IogiParametersProvider.java:80) at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.instantiateParameters(IogiParametersProvider.java:73) at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.getParametersFor(IogiParametersProvider.java:63) at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.getParametersFor(ParametersInstantiatorInterceptor.java:126) at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:83) at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44) at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91) at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58) at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 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:680) Caused by: java.lang.NullPointerException at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator$VRaptorTypeConverter.setPropertiesAfterConversions(VRaptorInstantiator.java:143) at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator$VRaptorTypeConverter.instantiate(VRaptorInstantiator.java:134) at br.com.caelum.iogi.MultiInstantiator.instantiate(MultiInstantiator.java:20) at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:85) ... 42 more
Eu removi os groups para ver se não era problema por passar “[” e “]”…

Ainda não funcionou… Que coisa estranha…

EDIT
Testei também trocando os colchetes: var name = self.attr('data-name').replace(/\[/g, '%5B').replace(/\]/g, '%5D');

L

tenta colocar o jar do ognl no classpath, isso parece um bug do IOGI…

precisava tentar reproduzir esse problema no blank-project pra gente tentar corrigir.

R

Eu coloquei o jar do ognl e funcionou sem as aspas… Mas ai meus objetos imutáveis deixaram de funcionar. Estive pensando em pegar uma versão mais nova do IOGI, você acha que resolve esse problema ou eu devo tornar minhas classes mutáveis? Esse projeto está no começo, então tem pouca coisa para mudar…

Eu poderia fazer assim?

&lt;dependency org="br.com.caelum" name="vraptor" rev="3.4.1" conf="default"&gt;
			&lt;exclude org="jfree"/&gt;
			&lt;exclude name="iogi"/&gt;
		&lt;/dependency&gt;
		&lt;dependency org="br.com.caelum" name="iogi" rev="0.9.1" conf="default" /&gt;
L

vc pode tentar isso sim… mas seria bom tentar debugar o código pra entender o que tá acontecendo e corrigir…

por isso seria legal tentar reproduzir isso no blank-project

R

Eu fiz os testes com o Blank-project, não consegui reproduzir o problema… :shock:

Vou continuar tentando.

Criado 17 de janeiro de 2013
Ultima resposta 24 de jan. de 2013
Respostas 25
Participantes 2