web-dev-qa-db-fra.com

Consommation d'un objet JSON dans le service Jersey

J'ai fait des recherches sur Google pour essayer de savoir comment faire: j'ai un service Jersey REST. La demande qui appelle le service REST contient un objet JSON. Ma question est, à partir de l'implémentation de la méthode Jersey POST, comment puis-je accéder au JSON qui se trouve dans le corps de la requête HTTP?

Tous les conseils, astuces, pointeurs vers un exemple de code seraient grandement appréciés.

Merci...

--Steve

33
Steve

Je ne sais pas comment vous obtiendriez la chaîne JSON elle-même, mais vous pouvez certainement obtenir les données qu'elle contient comme suit:

Définissez une classe JAXB annotée Java classe (C) qui a la même structure que l'objet JSON qui est transmis à la demande.

par exemple. pour un message JSON:

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

Utilisez quelque chose comme:

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

Ensuite, vous pouvez définir une méthode dans votre classe de ressources avec un paramètre de type C. Lorsque Jersey invoque votre méthode, l'objet JAXB sera créé en fonction de l'objet JSON POSTé.

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

Comme déjà suggéré, changer le type de contenu @Consumes En text/plain Fonctionnera, mais cela ne semble pas juste du point de vue de l'API REST.

Imaginez que votre client doive POST JSON à votre API mais doit spécifier l'en-tête Content-Type comme text/plain. Ce n'est pas propre à mon avis. En termes simples, si votre API accepte JSON, alors l'en-tête de la demande doit spécifier Content-Type: application/json.

Afin d'accepter JSON mais de le sérialiser en un objet String plutôt qu'un POJO, vous pouvez implémenter un MessageBodyReader . Le faire de cette façon est tout aussi facile et vous n'aurez pas à faire de compromis sur vos spécifications API.

Cela vaut la peine de lire les documents pour MessageBodyReader afin que vous sachiez exactement comment cela fonctionne. Voici comment je l'ai fait:

Étape 1. Implémentez un MessageBodyReader personnalisé

@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);
  }
}

Le concept de base ci-dessus consiste à vérifier si le flux d'entrée devrait être converti en String (spécifié par Type genericType). Si c'est le cas, il suffit de transtyper le JSON dans le type spécifié (qui sera un String). Si le type attendu est une sorte de POJO, utilisez une bibliothèque JSON (par exemple Jackson ou GSON) pour le désérialiser en POJO.

Étape 2. Liez votre MessageBodyReader

Cela dépend du framework que vous utilisez. Je trouve que Guice et Jersey fonctionnent bien ensemble. Voici comment lier mon MessageBodyReader dans Guice:

Dans mon JerseyServletModule je lie le lecteur comme ça -

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

Le CustomJsonReader ci-dessus désérialise les charges utiles JSON en POJO ainsi que, si vous voulez simplement les objets JSON bruts, String.

L'avantage de procéder de cette façon est qu'il acceptera Content-Type: application/json. En d'autres termes, votre gestionnaire de requêtes peut être configuré pour consommer JSON, ce qui semble approprié:

@POST
@Path("/stuff")
@Consumes("application/json") 
public void doStuff(String json) {
  /* do stuff with the json string */
  return;
}
15
pestrella

Jersey prend en charge un accès de bas niveau au JSONObject analysé à l'aide des types Jettison JSONObject et JSONArray.

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

Par exemple:

{
  "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;
}

Voir documentation Jersey pour plus d'exemples.

13
Peter Centgraf

Cela vous donne accès à la publication brute.

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

Soumettez/POSTEZ le formulaire/HTTP.POST avec un paramètre avec le JSON comme valeur.

@QueryParam jsonString

public desolveJson (jsonString)

0
doyle