RESTful parte 3: Manejando colecciones de objetos y objetos complejos
Comenzamos este año nuevo con la continuación del (creo yo) más esperado tema de tutorial: RESTful. Y esta vez hablaremos sobre el manejo de colecciones y objetos complejos. Por ahora será de manera básica y veremos poco a poco cómo hacerlo más y más complejo.
¿Cómo hacer esto? Bien fácil:
Probaremos enviando la siguiente cadena en el método POST.
Y veremos que en la respuesta nos devuelve con el ID de la persona autogenerada.
Como se puede en esta imagen, está el envío de la data, y la respuesta del servidor.
Esto es bastante fácil, porque es lo mismo que se vió en el anterior post. Ahora veremos como se obtiene una lista.
Pero como va a recibir un parámetro, por método
Ahora, probemos con el "Test REST" de NetBeans (previo registro de objetos, claro está).
Notemos que el nombre del parametro query no necesariamente tiene que ser el mismo nombre del parámetro del método de Java. Es decir, esto es totalmente válido:
Pero antes de seguir, quiero recordar que esta parte del tutorial es aún básico. Por ahora no pretendamos poner un objeto que tenga una referencia cíclica, es decir, que tenga una propiedad que es otro objeto y que este tenga otra propiedad que apunte al primer objeto. Sí se puede hacer, pero por ahora no lo veremos porque para ello hay que hacer algunas modificaciones adicionales.
Crearemos una clase llamada
Y, en nuestra clase
Ahora, probemos con la siguiente cadena JSON (no olvidar que se selecciona POST (application/json)) para registrar nuestro objeto:
Y al obtener la lista de los objetos, se obtiene sin ningún problema. Ya sea en XML...
... o en JSON...
Si quieres conocer más sobre los formatos de JSON, visita aquí: http://www.json.org/json-es.html
Ya haré un post dedicado únicamente a los clientes de RESTful, tanto como para probar como para hacer una aplicación desktop, javascript, javafx, mobile, etc.
El siguiente post, cómo manejar los
http://kenai.com/projects/apuntes/downloads/download/PersonaRESTWeb%252FPersonasRESTWeb.tar.gz
Bendiciones!
Manejo de colecciones
Para comenzar, tomaremos el mismo proyecto que vimos en el último post y agregaremos otro recurso llamadoPersonaResource
con el path apuntando por /listaPersonas
. ¿Cómo hacer esto? Bien fácil:
- Crear una clase llamada
PersonaResource
dentro del paquetecom.apuntesdejava.rest
- Agregar las siguientes anotaciones al inicio de la declaración de la clase:
@Stateless @Path("/listaPersonas")
package com.apuntesdejava.rest;
import javax.ejb.Stateless;
import javax.ws.rs.Path;
@Stateless
@Path("/listaPersonas")
public class PersonasResource {
}
Guardando objetos en la colección
Esto es realmente fácil. Es como cualquier método en Java que recibe un objeto y lo guarda en el arreglo://...
static List<Persona> personas = new ArrayList<Persona>();
@POST
@Consumes({"application/xml", "application/json"})
public Response guardar(Persona p) {
p.setIdPersona(personas.size() + 1); //se le autoasigna un id al objeto
personas.add(p);
return Response.ok(p).build();
}
//...
Sabemos que el objeto vendrá en formato JSON o XML. Si tenemos dudas, probemos con el "Test RESTful Web services" de NetBeans.Probaremos enviando la siguiente cadena en el método POST.
{"nombre_persona":"Juan Perez",
"edad":"35",
"trabajador":"true",
"fechaNacimiento":"1976-01-01"}
Y veremos que en la respuesta nos devuelve con el ID de la persona autogenerada.
<?xml version="1.0" encoding="UTF-8"?>
<persona id_persona="1">
<fechaNacimiento>1976-01-01T00:00:00-05:00</fechaNacimiento>
<nombre_persona>Juan Perez</nombre_persona>
<sexo>0</sexo>
<trabajador>true</trabajador>
</persona>
Como se puede en esta imagen, está el envío de la data, y la respuesta del servidor.
Esto es bastante fácil, porque es lo mismo que se vió en el anterior post. Ahora veremos como se obtiene una lista.
Obteniendo objetos en la colección
Lo bueno de utilizar RESTful en Java es que no requiere declarar métodos extraños ni clases adicionales (hasta ahora). Entonces, si queremos que nuestra clase tenga un método que devuelva una lista de objetos de una lista en base a un criterio (por ejemplo, los que tengan uno determinado texto), podría ser como el que sigue: public List<Persona> buscar(String nombre) {
List<Persona> lista = new ArrayList<Persona>();
for (Persona persona : personas) {
if (persona.getNombre().indexOf(nombre) >= 0) {
lista.add(persona);
}
}
return lista;
}
¿Cierto? Bien, ahora lo convertiremos en servicio RESTful agregando la anotación GET
, además de qué tipos va a devolver. @GET
@Produces({"application/xml", "application/json"})
public List<Persona> buscar( String nombre) {
List<Persona> lista = new ArrayList<Persona>();
for (Persona persona : personas) {
if (persona.getNombre().indexOf(nombre) >= 0) {
lista.add(persona);
}
}
return lista;
}
Pero como va a recibir un parámetro, por método
@GET
(es decir, como parte del URL.. o query string) entonces hay que darle un nombre usando @QueryParam
. @GET
@Produces({"application/xml", "application/json"})
public List<Persona> buscar(@QueryParam("nombre") String nombre) {
List<Persona> lista = new ArrayList<Persona>();
for (Persona persona : personas) {
if (persona.getNombre().indexOf(nombre) >= 0) {
lista.add(persona);
}
}
return lista;
}
Ahora, probemos con el "Test REST" de NetBeans (previo registro de objetos, claro está).
Notemos que el nombre del parametro query no necesariamente tiene que ser el mismo nombre del parámetro del método de Java. Es decir, esto es totalmente válido:
@GET
@Produces({"application/xml", "application/json"})
public List<Persona> buscar(@QueryParam("name") String nombre) {
//...
}
Objetos complejos
Ahora bien, ya nos podemos imaginar que si permite exportar una simple colección de la manera más simple, también se puede exportar un objeto compuesto (es decir, un objeto que tenga propiedades que son otros objetos).Pero antes de seguir, quiero recordar que esta parte del tutorial es aún básico. Por ahora no pretendamos poner un objeto que tenga una referencia cíclica, es decir, que tenga una propiedad que es otro objeto y que este tenga otra propiedad que apunte al primer objeto. Sí se puede hacer, pero por ahora no lo veremos porque para ello hay que hacer algunas modificaciones adicionales.
Crearemos una clase llamada
Telefono
que tendrá las propiedades area
y numero
.public class Telefono {
private String numero;
private String area;
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getNumero() {
return numero;
}
public void setNumero(String numero) {
this.numero = numero;
}
}
Y, en nuestra clase
Persona
agregaremos una colección de la clase recién creada:
public class Persona {
//....
private List<Telefono> telefonos;
public List<Telefono> getTelefonos() {
return telefonos;
}
public void setTelefonos(List<Telefono> telefonos) {
this.telefonos = telefonos;
}
//....
Ahora, probemos con la siguiente cadena JSON (no olvidar que se selecciona POST (application/json)) para registrar nuestro objeto:
{
"nombre_persona":"Carl",
"telefonos" :[
{"area":"51","numero":"12345"},
{"area":"54","numero":"98765"}
]
}
Y al obtener la lista de los objetos, se obtiene sin ningún problema. Ya sea en XML...
... o en JSON...
Si quieres conocer más sobre los formatos de JSON, visita aquí: http://www.json.org/json-es.html
Ya haré un post dedicado únicamente a los clientes de RESTful, tanto como para probar como para hacer una aplicación desktop, javascript, javafx, mobile, etc.
El siguiente post, cómo manejar los
java.util.Map
y después, los métodos @DELETE
y @PUT
El código fuente
Aquí está el infaltable código fuente del proyectohttp://kenai.com/projects/apuntes/downloads/download/PersonaRESTWeb%252FPersonasRESTWeb.tar.gz
Bendiciones!
Hola! muchas gracias por tu nuevo post sobre RESTFul. La verdad es que yo tengo problemas con @DELETE, ya que aunque le indique como parámetro un @QueryParam para indicar el ID del objeto que quiero borrar, siempre toma el valor de 0 y nunca el que le paso realmente. Tengo una "solución" usando @PUT y haciendo un borrado lógico (indicando una fecha de borrado en vez de borrar el objeto de bbdd), pero no sé si hay una solución fácil para el @DELETE que no estoy viendo. Muchas gracias y un saludo! Laura
ResponderBorrarHola! Excelente este post de restful, me ha servido enormemente, pero tengo un predicamente, ya cree todos los ws que necesito, con los GET no tengo problema, envio un String y me retornan los objetos que necesito en formato JSON y los recibo bien en el cliente. Pero tengo problema con el POST, deseo enviar a el ws un objeto, yo cree el ws y lo pruebo con el testeador que me genera NetBeans, tomo el objeto, lo convierto en json con la libreria flexJson y la salida la copio y la pego en la interfaz del tester que genera Netbeans y bien, pero no he podido crear un cliente que le envie este objeto al ws, lo envio como objeto y marca error, y lo envio como json (el mismo que pego en el test) y me marca este error.
ResponderBorrarException in thread "main" com.sun.jersey.api.client.UniformInterfaceException: POST http://localhost:8080/GashTest/resources/auditoria?auditoria=%7B%22class%22:%22com.gash.entidades.Auditoria%22,%... 5%7D returned a response status of 500
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:563)
at com.sun.jersey.api.client.WebResource.post(WebResource.java:219)
at werest.ClienteAuditoria.registrar(ClienteAuditoria.java:46)
at gashagenttest.Main.main(Main.java:57)
Me puedes regalar una indicación de que puede ser o un link donde encuentre como crear un cliente en java que envíe objetos por post. Muchas gracias, exitos y que sigas creciendo tu blog, mantengo pendiente de él. Pablo
Hola Laura
ResponderBorrarfalta una parte que quiero llegar (pero te adelantaste) que cada objeto puede ser accedido desde un url unico, sin parametros query (de esos con ?param1=val1¶m2=val2...) algo así como http://... /rest/producto/01
El método @DELETE se hace a ese url unico. Creo que el siguiente post trataré de este url unico y cómo manejar los @DELETE.
De acuerdo, entonces esperaré de momento :)
ResponderBorrarYa he encontrado la solución navegando un poco, por si a alguien le interesa: http://docs.jboss.org/resteasy/docs/1.0.0.GA/userguide/pdf/RESTEasy_Reference_Guide.pdf
ResponderBorrarSaludos... le agradecería si me indica donde puedo encontrar un cliente para consumir este tipo de servicios que retorna una lista de objetos muchas gracias.
ResponderBorrarcompanero una pregunta por lo que puedo ver cuando haces el get de la lista de empleados pero que la etiqueta que usa es habra alguna posibilidad de cambiarla por otra etiqueta ?
ResponderBorrarmuchas gracias de manera adelantada
Existe alguna forma de en el lado del servidor enterarse cuando la conexion de la peticion se ha cortado? por ejemplo por un timeout?
ResponderBorrar