--- title: Conversores --- # Quando usar um Conversor? Quando recebemos um parametro do browser, recebemos como uma String. Por isso é necessário um conversor para fazer a tradução deste parametro para seu respectivo objeto. O VRaptor já possui registrado conversores para todos os tipos definidos na `Java Language Specification`. Para os tipos primitivos, caso o parâmetro seja recebido como `null`, será retornado o valor padrão do campo. Por exemplo, se você receber um `int` cujo valor seja `null`, o converter irá retornar `0`. Já para os tipos objetos, se o parâmetro recebido for `null` ou vazio, o valor retornado será `null`. Por exemplo, se recebermos os seguintes parâmetros do browser: | cliente.id | 10 | | cliente.idade | null | {: .content-table} para a classe abaixo: ~~~ #!java public class Cliente { private Long id; private int idade; // getters and setters } ~~~ Ao injetar os dados da requisição na classe, o VRaptor irá usar o conversor `LongConverter` para o campo `id` e o conversor `PrimitiveIntegerConverter` para o campo `idade`. Neste caso, o atributo `id` receberá o valor `10`, e o campo `idade` receberá o valor `0`, pois o parametro recebido é `null`. Você pode obter a lista completa dos conversores padrão do vraptor aqui. ##BigDecimal, Double e Float localizados São suportados utilizando o padrão de localização da sua aplicação. `Double` e `Float` são suportados tanto o tipo primitivo quanto o tipo objeto. ##Trabalhando com datas e calendários `Calendar` e `Date` são suportados por padrão usando a localização da sua aplicação. Existem conversores para os principais tipos do Joda-time como `DateTime`, `LocalDate`, `LocalDateTime` e `LocalTime`. Os conversores do Joda-time estão disponíveis usando o plugin [vraptor-jodatime](/pt/docs/plugins/#joda-time). Se você está usando JDK 8, você pode tirar proveito dos conversores do pacote `java.time`, que estão disponíveis usando o plugin [vraptor-java8](/pt/docs/plugins/#vraptor-java-8). ##Mensagem de erro de conversão Quando o VRaptor tenta converter um objeto, e ocorrer algum erro, é retornada para a apicação uma exception indicando o erro de conversão. Por exemplo, se você receber um parametro com valor `A` para um campo `Integer`, a conversão irá falhar e você receberá uma `ConversionException` internacionalizada. Para exibir as mensagens na sua aplicação, basta adicionar as seguintes chaves no seu resource bundle: ~~~ #!properties is_not_a_valid_number = {0} não é um número válido. is_not_a_valid_integer = {0} não é um inteiro válido. is_not_a_valid_character = {0} não é um caracter válido. is_not_a_valid_enum_value = {0} não é uma opção válida. is_not_a_valid_date = {0} não é uma data válida. is_not_a_valid_boolean = {0} não é um valor boolean válido. is_not_a_valid_time = {0} não é um horário válido. is_not_a_valid_datetime = {0} não é uma data e horário válidos. ~~~ ##Definindo a localização (Locale) da aplicação A localização dos componentes pode ser alterada utilizando a seguinte configuração no web.xml: ~~~ #!xml javax.servlet.jsp.jstl.fmt.locale pt_BR ~~~ Ou vocẽ pode iniciar o servidor de aplicações ou servlet container com o parâmetro: ~~~ -Duser.language=pt -Duser.region=BR ~~~ ##Criando seu próprio converter Todos os conversores devem implementar a interface `Converter` do vraptor. A classe concreta definirá o tipo que ela é capaz de converter e será invocada com o valor do parâmetro do request e o tipo alvo. ~~~ #!java public interface Converter { T convert(String value, Class type); } ~~~ Além disso, seu conversor deve ser anotado com o tipo que seu conversor é capaz de converter, para isso utilize a anotação `@Convert`: ~~~ #!java @Convert(Long.class) public class LongConverter implements Converter { ... } ~~~ Por fim, lembre-se de dizer se seu conversor pode ser instanciado em um escopo de `Application`, `Session` ou `Request`, assim como recursos e componentes quaisquer do VRaptor. Por exemplo, um conversor que não requer nenhuma informação do usuário logado pode ser registrado no escopo de `Application` e instanciado uma única vez: ~~~ #!java @Convert(Long.class) @ApplicationScoped public class LongConverter implements Converter { ... } ~~~ A seguir, a implementação de `LongConverter` mostra como tudo isso pode ser utilizado de maneira bem simples: ~~~ #!java @Convert(Long.class) @ApplicationScoped public class LongConverter implements Converter { public Long convert(String value, Class type) { if (isNullOrEmpty(value)) { return null; } try { return Long.valueOf(value); } catch (NumberFormatException e) { throw new ConversionException(new ConversionMessage("is_not_a_valid_integer", value)); } } } ~~~ ##Populando outras propriedades de um objeto convertido Nos exemplos acima, usamos os converters para converter um parâmetro do request em um objeto, por exemplo, parâmetro `pais` converter em um objeto `Pais`. Porém há casos onde precisamos apenas criar um objeto com alguma propriedade populada. Exemplo: para o parametro `pais.nome` podemos ter um objeto `Pais` com o atributo `nome` preenchido. Neste caso, o `value` recebido no método será o valor do atributo `nome`. Basta então criar um converter como no exemplo abaixo: ~~~ #!java @Convert(Pais.class) @ApplicationScoped public class PaisConverter implements Converter { public Pais convert(String value, Class type) { Pais pais = new Pais(); if (!isNullOrEmpty(value)) { pais.setNome(value) } return pais; } } ~~~ ##Sobrescrevendo o comportamento dos conversores existentes Você pode sobrescrever qualquer converter já existente no VRaptor. Para isso basta estender a classe anotando-a com `@Specializes` e também adicionando a anotação `@Convert` com o tipo que será especializado. Um bom exemplo para isso é sobrescrever o conversor `BigDecimalConverter` para alterar o formato do valor. ~~~ #!java @Specializes @Convert(BigDecimal.class) public class MeuBigDecimalConverter extends BigDecimalConverter { @Override public BigDecimal convert(String value, Class type) { // seu código aqui return super.convert(value, type); } } ~~~ Você pode utilizar o `@Specializes` sempre que quiser reaproveitar a implementação da `superclasse`, caso contrário poderá criar um `@Alternative` com prioridade maior que a implementação do VRaptor. Como por exemplo: ~~~ #!java @Alternative @Priority(Interceptor.Priority.APPLICATION) @Convert(BigDecimal.class) public class MeuBigDecimalConverter implements Converter{ @Override public BigDecimal convert(String value, Class type) { return // seu código aqui } } ~~~ Por padrão todo `Converter` do VRaptor tem prioridade `LIBRARY_BEFORE`.