Injeção de Double nos parametros no vraptor [resolvido]

35 respostas
G

Tenho o seguinte controller:

@Path("/l10n/fetch-map/{coordX}/") public void coords(String coordX) { System.out.println(coordX); result.use(Results.nothing()); }

Quando acesso o URI /l10n/fetch-map/10/ funciona perfeitamente. Porém quando altero o parametro coordX para Double encontro o seguinte erro:

@Path("/l10n/fetch-map/{coordX}/") public void coords(Double coordX) { System.out.println(coordX); result.use(Results.nothing()); }

INFO: 22:51:45 DEBUG (VRaptorRequest.java:95) - Setting coordX with [10] SEVERE: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at java.util.ArrayList.RangeCheck(ArrayList.java:547) at java.util.ArrayList.get(ArrayList.java:322) at br.com.caelum.vraptor.http.route.DefaultParametersControl.fillIntoRequest(DefaultParametersControl.java:101) at br.com.caelum.vraptor.http.route.FixedMethodStrategy.matches(FixedMethodStrategy.java:71) at br.com.caelum.vraptor.http.route.DefaultRouter.parse(DefaultRouter.java:113) at br.com.caelum.vraptor.http.DefaultResourceTranslator.translate(DefaultResourceTranslator.java:65) at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:64) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:57)

Fazendo um debug no código noto que no código br.com.caelum.vraptor.http.route.DefaultParametersControl o request.parameters vem vazio.

public void fillIntoRequest(String uri, MutableRequest request) { Matcher m = pattern.matcher(uri); m.matches(); for (int i = 1; i <= m.groupCount(); i++) { String name = parameters.get(i - 1); request.setParameter(name, m.group(i)); } }

O mais interessante é quando eu coloco um double no formato 10,00 o controller não é encontrado:

INFO: 23:00:47 DEBUG (DefaultResourceTranslator.java:63) - trying to access /l10n/map/10,00/ INFO: 23:00:47 DEBUG (DefaultResourceTranslator.java:67) - found resource null

Onde posso cadastrar supostos bugs do vraptor sem ser no github?

35 Respostas

Lucas_Cavalcanti

olá garcia…

provavelmente o problema é essa virgula…

se vc usar a url …/10.00/ deve funcionar…

o VRaptor usa o Double.valueOf no parâmetro pra fazer a conversão…
e isso só funciona se tiver ponto, não funciona com vírgula…

se ficar difícil trocar isso no jsp, você pode criar um converter tipo:

@Convert(Double.class)
@ApplicationScoped
public class DoubleConverter implements Converter<Double> {

    public Double convert(String value, Class<? extends Double> type, ResourceBundle bundle) {
        if (value == null || value.equals("")) {
            return null;
        }
        try {
            return Double.valueOf(value.replace(',', '.');
        } catch (NumberFormatException e) {
			throw new ConversionError(MessageFormat.format(bundle.getString("is_not_a_valid_number"), value));
        }
    }

}
Paulo_Silveira

Oi Lucas

Talvez seja interessante a gente lancar uma exception mais adequada em vez de deixar levantar uma IndexOutOfBoundsException, algo que de a entender que a URI nao se encaixou com os esperados

G

Lucas, você me entendeu errado.

Quando eu coloco double = 10.0 dá IndexOutOfBoundsException. Aliás sempre que uso double como parametro de entrada no método dá isso. Se eu usar meu método como coords(String coordX) funciona, quando uso coords(Double coordX) não funciona. É lançada essa exception. Fiz um debug no código e notei que o vraptor-rc1 a classe DefaultParametersControl retorna como se o método não tivesse parametros. Se eu fizer coords(String coordX, Double blah) ele retorna como se o método tivesse apenas um parametro.

Já em outro teste, quando eu usei na URL 10,0 (e na entrada do método double) deu como “page not found”. Nesse caso não houve a IndexOutOfBoundsException.

Vou ver se faço mais uns debugs quando chegar em casa, que possa auxiliar na detecção do problema.

Abraços

Lucas_Cavalcanti

ok… é um bug então… tinha entendido que era só erro de conversão… vou verificar e corrigir o bug…

[]s

Lucas_Cavalcanti

já identifiquei o problema… vai estar funcionando na próxima versão…

o fato de não funcionar com vírgula, é que o VRaptor limita o formato dos doubles pra
numero.numero ou numero

talvez seja bom mudar esse padrão…

Obrigado!

G

lucascs:
já identifiquei o problema… vai estar funcionando na próxima versão…

o fato de não funcionar com vírgula, é que o VRaptor limita o formato dos doubles pra
numero.numero ou numero

talvez seja bom mudar esse padrão…

Obrigado!

Lucas, o normal mesmo dos decimais são usar com ponto mesmo. Mas como aqui no BR é com virgulas, quem save uma boa opção era basear-se no locale ou algo assim.

Lucas_Cavalcanti

o VRaptor faz o matching de URIs usando expressões regulares… é BEM complicado fazer isso baseado no locale :stuck_out_tongue:

De qualquer forma, dá pra criar um componente do VRaptor que faça isso futuramente de um jeito mais extensível

Lucas_Cavalcanti

olá garcia,

eu gerei um rc-2 com correção de vários bugs, alguns dos quais você apontou…

http://code.google.com/p/vraptor3/

se puder atualizar o seu vraptor, e me dizer se tudo funcionou, ficarei muito grato =)

G

Lucas, fiz os testes aqui e funcionou tudo bem. Digo, pelo menos os bugs que eu havia apontado.

Só tem um porém. Esse controller uso para informações de geoprocessamento, e quando coloco na URL um double negativo ele não consegue encontrar o recurso.

/l10n/map/10/51/ - funciona OK
/l10n/map/10.01/51.93/ - funciona OK
/l10n/map/-10.01/51.93/ - not-found

INFO: 22:15:55 DEBUG (DefaultResourceTranslator.java:63) - trying to access /l10n/map/-10.8540808/-11.7919526/
INFO: 22:15:55 DEBUG (DefaultResourceTranslator.java:67) - found resource null

Vou com calma tentar me interar com o código para já tentar te passar algo mais resolvido, hehe.

Abraços

Lucas_Cavalcanti

já sei onde é o problema…

não previ que poderiam passar numeros negativos :stuck_out_tongue:

Lucas_Cavalcanti

já foi corrigido no fonte

ThiagoInGuj

Aproveitando o tópico:

Usando o Converter Localizado: br.com.caelum.vraptor.converter.l10n do VRaptor eu consigo enviar como parametro num form um valor decimal com vírgula em
vez de ponto. O problema é que se um outro input der erro, o VRaptor repopula o meu input com o numero decimal com ponto. E se eu envio a requisicao com ponto,
o valor não é inserido como decimal mas sim como milhar.

Insiro 1,24.

deu erro

VRaptor popula com 1.24

Envio de novo

1.24 se torna 1240,00

Tem solução?

Lucas_Cavalcanti

use a tag <fmt:formatNumber

ThiagoInGuj

Sim, isso funciona. Mas eu queria saber como eu faço pra mexer na conversao do valor pra exibir na view.

Lucas_Cavalcanti

usando o fmt:formatNumber

<h1>Minha view legal</h1>
<fmt:formatNumber value="${oNumero}" />

se estiver com o locale setado corretamente ele vai imprimir o número com ,

ThiagoInGuj

Não foi isso que eu quis dizer, eu quero saber como eu posso ter o controle no back-end sobre a conversão que o VRaptor faz dos meus dados
inseridos no form na volta, isto é, a conversão que o VRaptor faz por exemplo de um string 1,99(vindo do form) para um double 1.99

Lucas_Cavalcanti

o double não é formatado… é um número… com o <fmt:formatNumber vc coloca o que vc quiser…

vamos supor que vc fez um input pra esse número, só vc colocar o format com o mesmo nome no value:

<input type="text" name="meuObjeto.numero" value="<fmt:formatNumber value="${meuObjeto.numero}"/>" />

isso funciona… se vc quiser mudar o padrão, mude o locale ou use o pattern:

<fmt:formatNumber value="$..." pattern="#.###,##" />

ou algo do tipo

ThiagoInGuj

Então Lucas, eu entendi como usa a tag <format:… mas a questão que eu quero saber é que eu envio 1,99 e, se de erro, o VRaptor popula o meu form com 1.99.

O que eu quero saber é como eu posso popular “na mão” esse meu input, isto é, eu quero que, quando der um erro, o meu form seja populado com as strings que
foram inseridas. Eu sei que se eu usar a tag format eu corrijo isso, mas eu quero saber como o VRaptor faz pra repopular esse form e, se possível, mexer aí.

Lucas_Cavalcanti

você testou o que eu falei pra vc usar? isso faz o que vc quer.

qdo dá erro de validação ou conversão, e vc usa o validator.onErrorXXXXX, o vraptor repassa os dados que vc mandou, em variaveis com o mesmo nome.

ThiagoInGuj

Funcionou sim.

Digamos que o VRaptor use essa classe pra fazer a conversao do String 1,99 que eu envio para setar o produto.setPreco(Double preco)

@Convert(Double.class)

@ApplicationScoped

public class DoubleConverter implements Converter {
public Double convert(String value, Class<? extends Double> type, ResourceBundle bundle) {  
    if (value == null || value.equals("")) {  
        return null;  
    }  
    try {  
        return Double.valueOf(value.replace(',', '.');  
    } catch (NumberFormatException e) {  
        throw new ConversionError(MessageFormat.format(bundle.getString("is_not_a_valid_number"), value));  
    }  
}

}

Mas digamos que tenha ocorrido um erro com outro input (não esse do double). Então o VRaptor vai repopular o meu form com o valor 1.99

O que eu quero é implementar um metodo double to string que o VRaptor use para repopular o meu form. Não quero que o VRaptor repopule o
meu form com 1.99. Sei que tem algo parecido no JSF, queria saber se tem no VRaptor.

Lucas_Cavalcanti

o vraptor não vai fazer o double to string… ele vai passar como double. quem faz o to string é o jsp. E vc muda isso usando o <fmt:formatNumber

G

O que você pode fazer é usar ${param[‘nomedapropriedade’]}.

Porém como o Lucas falou, o VRaptor apenas faz parser do valor como String para Double. O inverso é de responsabilidade da view, sendo assim somente com a tag fmt:formatNumber.

A propósito, o VRaptor não popula o teu form, quem popula é a view (JSP).

ThiagoInGuj

Tá certo. Valeu pela ajuda!

To tendo um problema aqui com o conversor @Convert(Double.class) que eu informei acima, pois o vraptor não o está chamando.
Engraçado que eu inseri um println para verificacao e, no redeploy do tomcat, o vraptor o reconheceu. Mas quando eu dou shut down
no tomcat e dou um start novamente, o vraptor não chama o conversor.

Lucas_Cavalcanti

se vc registrar os converters localizados daqui:

http://vraptor.caelum.com.br/documentacao/componentes-utilitarios-opcionais/

provavelmente vc não vai precisar usar seu próprio conversor.

em todo caso, se o seu converter não tiver o pacote br.com.caelum.vraptor.qqercoisa, ele deveria ter precedência sobre os do vraptor.

ThiagoInGuj

Eu havia registrado o conversor localizado br.com.caelum.vraptor.converter.l10n no meu web.xml

Quando eu removi esse registro do web.xml, o meu conversor anotado foi reconhecido.

ThiagoInGuj

Cara, por que que quando eu uso o conversor br.com.caelum.vraptor.converter.l10n do vraptor, ao inserir um valor numerico no meu form
do tipo 1.2, o vraptor converte isso em 12? Não deveria dar um erro se eu tento enviar 1.2 e o meu locale é do brasil?

Lucas_Cavalcanti

não… no formato pt-br, o ponto é separador de milhar, então ele é só ignorado.

ThiagoInGuj

É, só que isso pode dar merda. Muita gente acha que 1.2 é o mesmo que 1,2. Não tem como deixar o usuário digitar 1.2, pois se não vai dar merda.

ThiagoInGuj

E quando não usamos o conversor br.com.caelum.vraptor.converter.l10n do vraptor, se eu inserir 1.20 o vraptor insere normalmente 1.20, mas se eu inserir 1,20 o vraptor responde com o erro is_not_a_valid_number. Se 1,20, que no formato en-US a vírgula é separador de milhar, o vraptor reclama, por que não reclama quando eu insiro 1.20, que no brasil é separador de milhar?

Lucas_Cavalcanti

o conversor padrão usa Double.parseDouble… o l10n usa o NumberFormat, são jeitos diferentes.

o number format aceita bem mais números diferentes…

vc pode criar seu próprio conversor baseado nesse link acima, e trocando ponto por vírgula, se não tiver vírgula.
ou normalizar via javascript

ThiagoInGuj

Foi o que eu fiz, criei um conversor que retorna um erro se for inserido um valor com ponto. É que achei estranho porque se eu não implementar esse conversor, e confiar no javascript, basta alguém desabilitar javascript e inserir 1.12 que será inserido no banco 112 sem quaisquers problemas.

ThiagoInGuj

A propósito Lucas, quando o meu conversor gera um erro, tem como eu não entrar no método do controler, mas sim ir direto de volta para a página do form? Digo isso pois mesmo o meu conversor gerando o erro, o metodo do controler é acionado, e o validator dentro desse metodo verifica que o parametro não está preenchido e acrescenta o erro “nao.pode.ser.nulo” por exemplo.

ThiagoInGuj

Até o momento eu corrigi fazendo assim dentro do método do controller:

validator.onErrorUsePageOf(this).formulario();

restante do código

Lucas_Cavalcanti

a forma de corrigir é colocando esse validator.onErrorXXX mesmo.

não existe um jeito garantido de voltar pra última página. Existe o header referer, mas nem sempre os browsers mandam.

ThiagoInGuj

Beleza então. Valeu pela paciência! abs!

Criado 28 de setembro de 2009
Ultima resposta 22 de jun. de 2012
Respostas 35
Participantes 4