Comment puis-je passer des objets complexes comme arguments à un service reposant?

j'ai réussi à mettre en place un test rapide de création d'un service "REST-like" qui renvoie un objet sérialisé à JSON, et qui a été assez facile et rapide (basé sur cet article).

mais tout en retournant des objets JSON-ified était facile comme peach, Je n'ai pas encore vu d'exemples traitant des paramètres d'entrée qui ne sont pas des primitives. Comment puis-je passer dans un objet complexe comme argument? J'utilise Apache CXF, mais les exemples utilisant D'autres cadres comme Jackson sont les bienvenus trop :)

côté Client serait probablement quelque chose comme construire un objet javascript, le passer dans JSON.stringify(complexObj), et de transmettre cette chaîne comme l'un des paramètres.

Le service serait probablement ressembler à quelque chose comme ceci

@Service("myService")
class RestService {
    @GET
    @Produces("application/json")
    @Path("/fooBar")
    public Result fooBar(@QueryParam("foo") double foo, @QueryParam("bar") double bar,
        @QueryParam("object") MyComplex object) throws WebServiceException {
    ...
    }
}

L'envoi d'objets sérialisés comme paramètres toucherait probablement rapidement la limite D'URL de 2KB imposée par Internet Explorer. Est-ce que vous recommanderiez D'Utiliser POST dans ces cas, et est-ce que je devrais changer beaucoup dans la fonction définitions?

30
demandé sur oligofren 2011-05-19 19:44:19

3 réponses

après avoir creusé un peu, j'ai vite découvert qu'il y avait essentiellement deux options:

Option 1

vous passez un "wrapper object" contenant tous les autres paramètres au service. Vous pourriez avoir besoin d'annoter cette classe wrapper avec des annotations JAXB comme @XmlRootElement pour que cela fonctionne avec le fournisseur basé sur Jettison, mais si vous utilisez Jackson à la place il n'y a pas besoin. Il suffit de définir le type de contenu au bon type et le lecteur de corps de message sera invoquer. Cela ne fonctionnera que pour les services de type POST bien sûr (AFAIK).

Exemple

ceci n'est qu'un exemple de transformation du service mentionné dans la question originale en un service utilisant un objet d'emballage.

@Service("myService")
class RestService {

    @POST
    @Produces("application/json")
    @Path("/fooBar")
    public Result fooBar(

          /** 
          * Using "" will inject all form params directly into a ParamsWrapper 
          * @see http://cxf.apache.org/docs/jax-rs-basics.html
          */
          @FormParam("") FooBarParamsWrapper wrapper

        ) throws WebServiceException {
            doSomething(wrapper.foo);
    }
}

class ParamsWrapper {
  double foo, bar;
  MyComplexObject object;
}

Option 2

vous pouvez fournir un format de chaîne spécial dans lequel vous empaquetez vos objets et puis implémenter soit un constructeur prenant une chaîne, une valeur statique de (String s) ou une chaîne statique (String s) dans la classe qui va prendre cette chaîne et créer un objet à partir d'elle. Ou tout à fait similaire, créer un ParameterHandler qui fait exactement la même chose.

AFAIK, seule la seconde version vous permettra d'appeler vos services à partir d'un navigateur utilisant JSONP (puisque JSONP est une astuce limitée à obtenir). J'ai choisi cette route pour pouvoir passer des tableaux d'objets complexes dans L'URI.

comme exemple de la façon dont cela fonctionne, prenez la classe de domaine suivante et service

Exemple

@GET
@Path("myService")
public void myService(@QueryParam("a") MyClass [] myVals) {
    //do something
}

class MyClass {
    public int foo;
    public int bar;

   /** Deserializes an Object of class MyClass from its JSON representation */
   public static MyClass fromString(String jsonRepresentation) {
           ObjectMapper mapper = new ObjectMapper(); //Jackson's JSON marshaller
           MyClass o= null;
           try {
                   o = mapper.readValue(jsonRepresentation, MyClass.class );
           } catch (IOException e) {
                    throw new WebApplicationException()
           }
           return o;
   }
}

A URI http://my-server.com/myService?a={"foo":1, "bar":2}&a={"foo":100, "bar":200} serait alors désérialisé en un tableau composé de deux objets MyClass.

28
répondu oligofren 2017-06-07 11:26:49

la solution la plus simple et la meilleure est d'envoyer votre objet sous forme de chaîne json et, Côté Serveur, d'implémenter une méthode qui décodera ce json et la map vers l'objet spécifié selon vos besoins.. et oui, il vaut mieux utiliser la poste.

1
répondu Koustuv Ganguly 2016-01-15 19:06:18

la réponse acceptée manque @BeanParam. Voir https://docs.jboss.org/resteasy/docs/3.0-rc-1/javadocs/javax/ws/rs/BeanParam.html pour plus de détails. Il vous permet de définir des paramètres de requête à l'intérieur d'un objet wrapper. E. g.

public class TestPOJO {

    @QueryParam("someQueryParam")
    private boolean someQueryParam;

    public boolean isSomeQueryParam() {
        return someQueryParam;
    }

    public boolean setSomeQueryParam(boolean value) {
        this.someQueryParam = value;
    }
}

... // inside the Resource class
@GET
@Path("test")
public Response getTest(@BeanParam TestPOJO testPOJO) {
    ...
}
1
répondu r_ganaus 2018-06-21 13:37:59