====== Agrupación de Parámetros con @BeanParam ======
En los servicios Rest podemos agrupar los parámetros que recibe una invocación con la anotación [[https://docs.oracle.com/javaee/7/api/javax/ws/rs/BeanParam.html|@BeanParam]].
Para poder utilizarlo tenemos que tener actualizado FundeWeb a las versiones 2.0.85 y/o 2.1.39. Para aplicaciones que despliegan en Weblogic 12.1, la versión del Parent en el POM principal tienes que ser 2.0.38 (2.0.38-primefaces6) o superior. Para aplicaciones que despliegan en Weblogic 12.2, la actualización del Parent debería ser automática.
===== Ejemplo =====
Supongamos que tenemos un servicio Rest que acepta muchos parámetros:
package api.services;
import java.util.Map;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@Path("customers")
public class CustomersService {
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response saveCustomer(@CookieParam("token") String token, @FormParam("firstname") String firstname, @FormParam("lastname") String lastname, @FormParam("status") String status, @QueryParam("source") String source) {
String result = String.format("firstname = %s, lastname = %s, status = %s, token = %s, source = %s",
new Object[] { firstname, lastname, status, token, source });
return Response.ok(result).build();
}
}
Con la anotación [[https://docs.oracle.com/javaee/7/api/javax/ws/rs/BeanParam.html|@BeanParam]] podemos agruparlos en un //DTO// o //POJO//.
package api.services;
import java.util.Map;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@Path("customers")
public class CustomersService {
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response saveCustomer(@BeanParam CustomerDTO customer) {
String result = String.format("firstname = %s, lastname = %s, status = %s, token = %s, source = %s",
new Object[] { customer.getFirstname(),
customer.getLastname(),
customer.getStatus(),
customer.getToken(),
customer.getSource() });
return Response.ok(result).build();
}
}
Ahora la clase //CustomerDTO// contiene los parámetros junto a sus anotaciones Rest:
package api.services;
import javax.ws.rs.*;
public class CustomerDTO {
@CookieParam("token")
private String token;
@FormParam("firstname")
private String firstname;
@FormParam("lastname")
private String lastname;
@FormParam("status")
private String status;
@QueryParam("source")
private String source;
/* GET and SET */
...
}
Dentro de este DTO podemos utilizar las anotaciones: @PathParam, @QueryParam, @MatrixParam, @CookieParam y @HeaderParam.
===== Integración con Bean Validation =====
Para poder seguir usando Bean Validation, solo tenemos que poner la anotación //@Valid// delante de la anotación //@BeanParam//. Después las anotaciones de validación en los parámetros.
package api.services;
import java.util.Map;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.validation.Valid;
@Path("customers")
public class CustomersService {
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response saveCustomer(@Valid @BeanParam CustomerDTO customer) {
String result = String.format("firstname = %s, lastname = %s, status = %s, token = %s, source = %s",
new Object[] { customer.getFirstname(),
customer.getLastname(),
customer.getStatus(),
customer.getToken(),
customer.getSource() });
return Response.ok(result).build();
}
}
Y en el //DTO//:
package api.services;
import javax.ws.rs.*;
import javax.validation.constraints.Size;
public class CustomerDTO {
@Size(min = 4)
@CookieParam("token")
private String token;
@Size(min = 4)
@FormParam("firstname")
private String firstname;
@Length(min = 4)
@FormParam("lastname")
private String lastname;
@Size(max = 2)
@FormParam("status")
private String status;
@Size(max = 100, min = 10)
@QueryParam("source")
private String source;
/* GET and SET */
...
}
===== FAQs =====
=== Excepción ParamException$BeanParamException: HTTP 400 Bad Request ===
Después de configurar servicio y DTO de la forma en que se indica en esta Wiki, al realizar una petición puede surgir la excepción:
...
31 ene 2022 13:16:33,175 ERROR (WebApplicationExceptionMapper.java:36) - Usuario: - Unexpected Error.
com.sun.jersey.api.ParamException$BeanParamException: HTTP 400 Bad Request
at com.sun.jersey.server.impl.model.parameter.BeanParamValueInjectableProvider$BeanParamValueInjectable.getValue(BeanParamValueInjectableProvider.java:46)
at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:86)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153)
...
//FundeWeb 2.0//
**Solución**
Revisar los constructores del DTO y dejar **__única y exclusivamente__** el constructor vacío.
--- //[[ramon.ginel@ticarum.es|RAMON GINEL GEA]] 01/02/2022 09:27//
----
===== Bibliografia y Ejemplos =====
* [[https://docs.oracle.com/javaee/7/api/javax/ws/rs/BeanParam.html|JEE - JAX-RS - @BeanParam]]
* [[https://www.oscarblancarteblog.com/2019/01/17/bean-params/|Bean Params con @BeanParam]]
----
--- //[[juanmiguel.bernal@ticarum.es|JUAN MIGUEL BERNAL GONZALEZ]] 01/12/2020 13:56//