Pregunta Consumo de objeto JSON en el servicio de Jersey


He estado buscando en Google mi trasero tratando de descubrir cómo hacer esto: tengo un servicio de REST de Jersey. 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 o sugerencia para el código de muestra sería muy apreciado.

Gracias...

--Steve


32
2017-11-02 17:08


origen


Respuestas:


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 de Java anotada JAXB (C) que tiene la misma estructura que el objeto JSON que se está pasando en la solicitud.

p.ej. para un mensaje JSON:

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

Use algo como:

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

Luego, puede definir un método en su clase de recurso con un parámetro de tipo C. Cuando Jersey invoca su método, el objeto JAXB se creará en base al objeto POSTed JSON.

@Path("/resource")
public class MyResource
{
  @POST
  public put(C c)
  {
     doSomething(c.A);
     doSomethingElse(c.B);
  }
}

11
2017-11-02 17:48



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

Imagine que su cliente debe enviar JSON a 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 una String objeto en lugar de un POJO puede implementar una costumbre MessageBodyReader. Hacerlo de esta manera es igual de fácil, y no tendrá que comprometer sus especificaciones de API.

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

Paso 1. Implementa una costumbre MessageBodyReader

@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 verificar si se espera que la corriente de entrada se convierta a String (especificado por Type genericType) Si es así, simplemente echa el JSON en el especificado type (que será un String) Si el tipo esperado es algún tipo de POJO, utilice una biblioteca JSON (por ejemplo, Jackson o GSON) para deserializarlo en un POJO.

Paso 2. Vincula tu MessageBodyReader

Esto depende de qué marco estás usando. Me parece que Guice y Jersey trabajan bien juntos. Así es como ato mi MessageBodyReader en Guice:

En mi JerseyServletModule Yo ato al lector como tal -

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

Lo anterior CustomJsonReader deserializará las cargas JSON en POJO y también, si solo quieres el JSON sin procesar, String objetos.

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
2018-02-07 12:23



Jersey admite el acceso de bajo nivel al JSONObject analizado utilizando los tipos JetSison 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;
}

Ver el Documentación de Jersey para más ejemplos.


11
2018-04-26 14:40



Esto le da acceso a la publicación en bruto.

@POST
@Path("/")
@Consumes("text/plain") 
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
    // do some stuff, 
    return someJson;
}

6
2018-06-12 13:20



Envíe / envíe el formulario / HTTP.POST con un parámetro con JSON como valor.

@QueryParam jsonString

public desolveJson (jsonString)


0
2017-11-02 20:23