Consumir objeto JSON en el servicio Jersey


He estado buscando en Google mi trasero tratando de averiguar cómo hacer esto: Tengo un servicio de Jersey RESTO. La solicitud que invoca el servicio REST contiene un objeto JSON. Mi pregunta es, desde la implementación del método Jersey POST, ¿cómo puedo obtener acceso al JSON que está en el cuerpo de la solicitud HTTP?

Cualquier consejo, truco, punteros a código de muestra sería muy apreciado.

Gracias...

Steve Steve

 32
Author: Steve, 2009-11-02

5 answers

No estoy seguro de cómo llegaría a la cadena JSON en sí, pero ciertamente puede obtener los datos que contiene de la siguiente manera:

Defina una clase Java anotada (C) de JAXB que tenga la misma estructura que el objeto JSON que se está pasando en la solicitud.

Por ejemplo, para un mensaje JSON:

{
  "A": "a value",
  "B": "another value"
}

Usa algo como:

@XmlAccessorType(XmlAccessType.FIELD)
public class C
{
  public String A;
  public String B;
}

Entonces, puede definir un método en su clase de recurso con un parámetro de tipo C. Cuando Jersey invoque su método, el objeto JAXB será creado basado en el objeto JSON publicado.

@Path("/resource")
public class MyResource
{
  @POST
  public put(C c)
  {
     doSomething(c.A);
     doSomethingElse(c.B);
  }
}
 11
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-02 17:48:53

Como ya se ha sugerido, cambiar el Tipo de contenido @Consumes a text/plain funcionará, pero no parece correcto desde el punto de vista de la API REST.

Imagine que su cliente tiene que PUBLICAR JSON en su API pero necesita especificar el encabezado Content-Type como text/plain. No está limpio en mi opinión. En términos simples, si su API acepta JSON, el encabezado de la solicitud debe especificar Content-Type: application/json.

Para aceptar JSON pero serializarlo en un objeto String en lugar de un POJO, puede implementar un custom MessageBodyReader. Hacerlo de esta manera es igual de fácil, y no tendrás que comprometer tus especificaciones de API.

Vale la pena leer los documentos de MessageBodyReader para que sepas exactamente cómo funciona. Así es como lo hice:

Paso 1. Implementar un MessageBodyReader personalizado

@Provider
@Consumes("application/json")
public class CustomJsonReader<T> implements MessageBodyReader<T> {
  @Override
  public boolean isReadable(Class<?> type, Type genericType,
      Annotation[] annotations,MediaType mediaType) {
    return true;
  }

  @Override
  public T readFrom(Class<T> type, Type genericType, Annotation[] annotations,
      MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
      InputStream entityStream) throws IOException, WebApplicationException {

    /* Copy the input stream to String. Do this however you like.
     * Here I use Commons IOUtils.
     */
    StringWriter writer = new StringWriter();
    IOUtils.copy(entityStream, writer, "UTF-8");
    String json = writer.toString();

    /* if the input stream is expected to be deserialized into a String,
     * then just cast it
     */
    if (String.class == genericType)
      return type.cast(json);

    /* Otherwise, deserialize the JSON into a POJO type.
     * You can use whatever JSON library you want, here's
     * a simply example using GSON.
     */
    return new Gson().fromJson(json, genericType);
  }
}

El concepto básico anterior es comprobar si se espera que el flujo de entrada se convierta en un String (especificado por Type genericType). Si es así, entonces simplemente cast el JSON en el type especificado (que será un String). Si el tipo esperado es algún tipo de POJO, entonces use una biblioteca JSON (por ejemplo, Jackson o GSON) para deserializarlo a un POJO.

Paso 2. Bind your MessageBodyReader

Esto depende del framework que estés usando. Creo que Guice y Jersey trabajan bien juntos. Así es como enlazo mi MessageBodyReader en Guice:

En mi JerseyServletModule Ato al lector de esta manera --

bind(CustomJsonReader.class).in(Scopes.SINGLETON);

El anterior CustomJsonReader deserializará cargas útiles JSON en POJOs, así como, si simplemente desea el JSON en bruto, objetos String.

El beneficio de hacerlo de esta manera es que aceptará Content-Type: application/json. En otras palabras, su controlador de solicitud puede configurarse para consumir JSON, lo que parece apropiado:

@POST
@Path("/stuff")
@Consumes("application/json") 
public void doStuff(String json) {
  /* do stuff with the json string */
  return;
}
 15
Author: pestrella,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-07 12:56:55

Jersey admite el acceso de bajo nivel al JSONObject analizado utilizando los tipos de Jettison JSONObject y JSONArray.

<dependency>
    <groupId>org.codehaus.jettison</groupId>
    <artifactId>jettison</artifactId>
    <version>1.3.8</version>
</dependency>

Por ejemplo:

{
  "A": "a value",
  "B": "another value"
}


@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON) 
public void doStuff(JSONObject json) {
  /* extract data values using DOM-like API */
  String a = json.optString("A");
  Strong b = json.optString("B");
  return;
}

Vea la documentación de Jersey para más ejemplos.

 11
Author: Peter Centgraf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 07:24:25

Esto le da acceso a la publicación sin procesar.

@POST
@Path("/")
@Consumes("text/plain") 
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
    // do some stuff, 
    return someJson;
}
 6
Author: Will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-12 13:20:16

Enviar/PUBLICAR el formulario/HTTP.POST con un parámetro con el JSON como valor.

@QueryParam jsonString

Public desolveJson (jsonString)

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-02 20:23:40