Binding from Multiple Bindable values

Instead of binding just query values, it is also possible to bind any Bindable value to a POJO (e.g. to bind HttpRequest, @PathVariable, @QueryValue and @Header to a single POJO). This can be achieved with the @RequestBean annotation and a custom Bean class with fields with Bindable annotations, or fields that can be bound by type (e.g. HttpRequest, BasicAuth, Authentication, etc.).

For example:

Binding Bindable values to POJO

  1. @Controller("/api")
  2. public class MovieTicketController {
  3. // You can also omit query parameters like:
  4. // @Get("/movie/ticket/{movieId}
  5. @Get("/movie/ticket/{movieId}{?minPrice,maxPrice}")
  6. public HttpStatus list(@Valid @RequestBean MovieTicketBean bean) {
  7. return HttpStatus.OK;
  8. }
  9. }

Binding Bindable values to POJO

  1. @Controller("/api")
  2. class MovieTicketController {
  3. // You can also omit query parameters like:
  4. // @Get("/movie/ticket/{movieId}
  5. @Get("/movie/ticket/{movieId}{?minPrice,maxPrice}")
  6. HttpStatus list(@Valid @RequestBean MovieTicketBean bean) {
  7. HttpStatus.OK
  8. }
  9. }

Binding Bindable values to POJO

  1. @Controller("/api")
  2. open class MovieTicketController {
  3. // You can also omit query parameters like:
  4. // @Get("/movie/ticket/{movieId}
  5. @Get("/movie/ticket/{movieId}{?minPrice,maxPrice}")
  6. open fun list(@Valid @RequestBean bean: MovieTicketBean): HttpStatus {
  7. return HttpStatus.OK
  8. }
  9. }

which uses this bean class:

Bean definition

  1. @Introspected
  2. public class MovieTicketBean {
  3. private HttpRequest<?> httpRequest;
  4. @PathVariable
  5. private String movieId;
  6. @Nullable
  7. @QueryValue
  8. @PositiveOrZero
  9. private Double minPrice;
  10. @Nullable
  11. @QueryValue
  12. @PositiveOrZero
  13. private Double maxPrice;
  14. public MovieTicketBean(HttpRequest<?> httpRequest,
  15. String movieId,
  16. Double minPrice,
  17. Double maxPrice) {
  18. this.httpRequest = httpRequest;
  19. this.movieId = movieId;
  20. this.minPrice = minPrice;
  21. this.maxPrice = maxPrice;
  22. }
  23. public HttpRequest<?> getHttpRequest() {
  24. return httpRequest;
  25. }
  26. public String getMovieId() {
  27. return movieId;
  28. }
  29. @Nullable
  30. public Double getMaxPrice() {
  31. return maxPrice;
  32. }
  33. @Nullable
  34. public Double getMinPrice() {
  35. return minPrice;
  36. }
  37. }

Bean definition

  1. @Introspected
  2. class MovieTicketBean {
  3. private HttpRequest<?> httpRequest
  4. @PathVariable
  5. String movieId
  6. @Nullable
  7. @QueryValue
  8. @PositiveOrZero
  9. Double minPrice
  10. @Nullable
  11. @QueryValue
  12. @PositiveOrZero
  13. Double maxPrice
  14. }

Bean definition

  1. @Introspected
  2. data class MovieTicketBean(
  3. val httpRequest: HttpRequest<Any>,
  4. @field:PathVariable val movieId: String,
  5. @field:QueryValue @field:PositiveOrZero @field:Nullable val minPrice: Double,
  6. @field:QueryValue @field:PositiveOrZero @field:Nullable val maxPrice: Double
  7. )

The bean class has to be introspected with @Introspected. It can be one of:

  1. Mutable Bean class with setters and getters

  2. Immutable Bean class with getters and an all-argument constructor (or @Creator annotation on a constructor or static method). Arguments of the constructor must match field names so the object can be instantiated without reflection.

Since Java does not retain argument names in bytecode, you must compile code with -parameters to use an immutable bean class from another jar. Another option is to extend Bean class in your source.