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

L

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

}
P

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

L

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

[]s

L

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.

L

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

L

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

L

já sei onde é o problema…

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

L

já foi corrigido no fonte

T

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?

L

use a tag <fmt:formatNumber

T

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

L

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 ,

T

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

L

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

T

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

L

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.

T

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.

L

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

T

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.

L

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.

T

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.

T

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?

L

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

T

É, 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.

T

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?

L

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

T

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.

T

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.

T

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

validator.onErrorUsePageOf(this).formulario();

restante do código

L

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.

T

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