web-dev-qa-db-fra.com

Jersey, comment POST une liste d'objets JSON?

Je suis en train de créer un service Web RESTful en Java avec Jersey 1.11 et j'ai des problèmes pour mettre en oeuvre une méthode qui utilise une liste d'entités JSON. La méthode d'instance unique fonctionne bien.

L'erreur que je reçois est:

Status 400 - Bad Request. The request sent by the client was syntactically incorrect.

Ma signature de méthode ressemble à ceci:

@POST
@Path("/some-path/{someParam}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public String createBatch(List<MyEntity> myEnts, @PathParam("someParam") String someParam)
{
   ... 
}

Le JSON que j'envoie dans les demandes est un tableau d'objets JSON MyEntity:

[{"field1" : value1, "field2" : value2}, {"field1" : value3, "field2" : value4}, ...]

Des questions similaires avaient déjà été posées et une suggestion directe consistait à changer le type de média utilisé en texte et à désérialiser manuellement le JSON mais je préférerais une solution plus propre.

Le code JSON que j'envoie est-il même valide dans ce contexte ou ai-je besoin d'un {} de niveau supérieur, c'est-à-dire d'une entité d'encapsulation? Cela semblerait aussi un peu peu naturel.

Je vous remercie,

/ David

10
OG Dude

Je pense que PathParam et un paramètre qui devrait être décrit par Jersey (JAX-RS) ne sont pas possibles. Veuillez essayer de supprimer le paramètre PathParam.

Et si vous avez besoin du second paramètre, créez une nouvelle classe comme celle-ci.

@XmlRootElement(name = "example")
public class Example {
  @XmlElement(name = "param")
  private String param;
  @XmlElement(name = "entities")
  private List<MyEntity> entities;
}

et modifiez également votre méthode:

@POST
@Path("/some-path")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public String createBatch(Example example)
{
   ... 
}

votre JSON devrait ressembler à ceci:

{
 "param":"someParam",
 "entities":[
   {"field1" : value1, "field2" : value2}, {"field1" : value3, "field2" : value4}, ...]
}
6
Zelldon

Ok, donc au final, j'ai résolu ceci en utilisant une simple classe wrapper afin de générer { items : [{ <myEnityInstanceJson1> }, { <myEnityInstanceJson2> }, ... ]}. Je suppose qu’il ya un moyen d’avoir un générique wrapper mais pour le moment, cela suffira:

@XmlRootElement
public class MyEntityWrapper implements Serializable {

    private static final long serialVersionUID = 1L;

    private List<MyEntity> items;

    public MyEntityWrapper() {
        this.items = new ArrayList<MyEntity>();
    }

    public MyEntityWrapper(List<MyEntity> items) {
        this.items = items;
    }

    public List<MyEntity> getItems() {
        return items;
    }

    public void setItems(List<MyEntity> items) {
        this.items = items;
    }
}
4
OG Dude

La classe Wrapper fonctionne. MyEntity[] myEnts ne fonctionne pas.

C'est ce que j'ai fait et cela a fonctionné. 

public String createBatch(@PathParam("someParam") String someParam,
                                                  String content)

Utilisez ObjectMapper pour convertir en liste d'objets.

List<MyEntity> entities = om.readValue(content, 
                                       new TypeReference<List<MyEntity>>(){}).
1
Arun Kumar

Le problème est le type de liste générique, qui n'est pas disponible au moment de l'exécution en raison de l'effacement du type. Ainsi, Jersey ne saura pas quel type de POJO à annuler. 

Je pense que la solution la plus simple (que je connaisse, du moins lorsque vous utilisez Jackson dans votre MessageBodyReader) dans ce cas serait simplement d'utiliser un tableau Java normal au lieu de la liste, la signature de la méthode devient alors:

public String createBatch(@PathParam("someParam") String someParam, MyEntity[] myEnts)

Et oui, la combinaison de @PathParam et d'un paramètre de corps consommé/non mêlé devrait suffire.

1
David

Ceci est JSON valide pour un tableau:

{"elements": [
        {"field1" : value1, "field2" : value2}, 
        {"field1" : value3, "field2" : value4},
        ...]
};

(voir here pour un exemple)

Vous n'avez pas besoin d'envoyer de texte, vous pouvez l'envoyer au format JSON. De plus, votre MyEntity devrait avoir @XmlRootElement dessus (voir ici , section 5.2 pour un exemple).

Vous n'avez pas besoin de PathParam dans vos arguments, someParam est disponible lorsque la demande est publiée si vous laissez la @Path("/some-path/{someParam}") dans votre signature de méthode.

0
Bizmarck