Conversores personalizados para @RequestParam

gekyzo

Ciro

Posted on November 7, 2022

Conversores personalizados para @RequestParam

En la publicación anterior vimos cómo crear conversores personalizados para propiedades dentro de una clase anotada con @RequestBody.

En esta ocasión veremos cómo hacer la misma lógica para parámetros anotados como @RequestParam.

Refactorizando el ejemplo de la publicación anterior, supongamos que tenemos el siguiente controlador:

@RestController
@AllArgsConstructor
@RequestMapping("transactions")
public class CreateTransactionController {

  @PostMapping
  public ResponseEntity<CreateTransactionOutputDto> createTransaction(
      @RequestParam Double amount,
  ) {
    //
  }

}
Enter fullscreen mode Exit fullscreen mode

Y enviamos una petición a este endpoint con los siguientes parámetros:

POST '{{apiUrl}}/transactions?amount=45.13'
Enter fullscreen mode Exit fullscreen mode

Por defecto Spring será capaz de enlazar cada elemento de la petición con su correspondiente parámetro de nuestro controlador, siempre y cuando encuentre el conversor adecuado para ello.

No tendremos problemas si declaramos parámetros de tipo primitivo o sus wrappers, pero en caso de querer enlazarlos a una clase, debemos crear un conversor.

Cómo mapear Value Objects

Supongamos ahora que actualizamos el tipo de clase del parámetro de la siguiente manera:

// file: Money
public record Money(Double value) {...} // <- Creamos un record para encapsular un elemento de tipo Money

// file: CreateTransactionController
@PostMapping
  public ResponseEntity<CreateTransactionOutputDto> createTransaction(
      @RequestParam Money amount,   // <- Actualizamos el tipo parámetro
  ) {
    //
  }
Enter fullscreen mode Exit fullscreen mode

Para que Spring sea capaz de convertir estos datos correctamente, creamos el conversor extendiendo de org.springframework.core.convert.converter.Converter:

import org.springframework.core.convert.converter.Converter;

public class MoneyConverter implements Converter<String, Money> {   // <- Implementamos la interfaz Converter

  @Override
  public Money convert(String source) {

    return new Money(Double.parseDouble(source));   // <- Implementamos la conversión con la lógica que deseemos
  }

}
Enter fullscreen mode Exit fullscreen mode

Una vez más, se trata de un código muy simple. Únicamente es necesario implementar la infertaz Converter indicando como tipo de parámetros la clase de entrada y la de salida, en este caso indicamos que se va a convertir una String en la clase Money.

Por último, debemos indicar a Spring que se utilice este conversor para mapear las instancias de la clase Money, incluyendo el nuevo conversor dentro del registro de formateadores:

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

  @Override
  public void addFormatters(FormatterRegistry registry) {

    registry.addConverter(new MoneyConverter());    // <- Instanciamos e incluimos nuestro conversor
  }

}
Enter fullscreen mode Exit fullscreen mode

Una vez hecho esto, Spring será capaz de utilizar nuestro conversor cuando intente mapear propiedades de tipos distintos a los primitivos/wrappers o las clases para las que ya cuenta con conversores.

💖 💪 🙅 🚩
gekyzo
Ciro

Posted on November 7, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related