J'ai déclaré deux REST services Web. L'un qui renvoie simplement un objet. Et l'autre qui accepte un objet et renvoie un autre objet. POJO Order.Java est utilisé.
@XmlRootElement
public class Order {
private String id;
private String description;
public Order() {
}
@XmlElement
public String getId() {
return id;
}
@XmlElement
public String getDescription() {
return description;
}
// Other setters and methods
}
Webservice est défini comme
@Path("/orders")
public class OrdersService {
// Return the list of orders for applications with json or xml formats
@Path("/oneOrder")
@GET
@Produces({MediaType.APPLICATION_JSON})
public Order getOrder_json() {
System.out.println("inside getOrder_json");
Order o1 = OrderDao.instance.getOrderFromId("1");
System.out.println("about to return one order");
return o1;
}
@Path("/writeAndIncrementOrder")
@GET
@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_JSON})
public Order writeAndIncrementOrder(Order input) {
System.out.println("inside writeAndIncrementOrder");
Order o1 = new Order();
o1.setId(input.getId()+1000);
o1.setDescription(input.getDescription()+"10000");
System.out.println("about to return one order");
return o1;
}
Je pourrais écrire du code client pour appeler le service Web qui n'accepte rien mais renvoie un objet. Le code client est le suivant
import Java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.client.ClientConfig;
public class Test {
public static void main(String[] args) {
WebTarget target2 = client.target(getBaseURI()).path("rest").path("orders");
String o2 = target2.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(String.class);
System.out.println(o2);
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8090/FirstRESTProject").build();
}
Mais je ne comprends pas comment appeler un autre service qui accepte ainsi que renvoie un objet. J'ai essayé différentes solutions proposées sur internet. Mais rien n'a fonctionné pour moi. Certaines solutions ne fonctionnent que pour l'envoi d'objet et certaines ne fonctionnent que pour l'acceptation. Mais aucun n'a travaillé pour faire les deux en un seul appel.
EDIT Comme suggéré dans la réponse ci-dessous, j'ai enregistré JacksonJaxbJsonProvider.class Mais la conversion automatique en objet Order ne se produit pas.
String o2 = target2.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(String.class);
client.register(JacksonJaxbJsonProvider.class);
Order o4 = target2.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(Order.class);
Dans le programme ci-dessus, j'ai réussi à obtenir la chaîne sous la forme {"id": "1", "description": "Il s'agit du premier ordre"} .cart.om.Order, genericType = classe shopping.cart.om.Order.
Si vous prenez un peu de temps pour comprendre l'API WebTarget
, ainsi que les différents types renvoyés par les appels à la méthode de WebTarget
, vous devriez mieux comprendre comment passer des appels. Cela peut être un peu déroutant, car presque tous les exemples utilisent le chaînage de méthode, car c'est un moyen très pratique, mais ce faisant, vous manquez toutes les classes réelles impliquées dans la création et l'envoi de la demande. Laisse le décomposer un peu
WebTarget target = client.target(getBaseURI()).path("rest").path("orders");
WebTarget.path()
renvoie simplement le WebTarget
. Rien d'intéressant là-bas.
target.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(String.class)
WebTarget.request()
renvoie Invocation.Builder
Invocation.Builder.accept(..)
renvoie Invocation.Builder
Invocation.Builder.get()
appelle sa super classe SyncInvoker.get()
, qui fait la requête réelle et retourne un type, basé sur l'argument que nous fournissons à get(Class returnType)
Ce que vous faites avec get(String.class)
, c'est que le flux de réponse doit être désérialisé en une réponse de type Sting. Ce n'est pas un problème, car JSON est intrinsèquement juste une chaîne. Mais si vous voulez le démarsaler en POJO, vous devez avoir un MessageBodyReader
qui sait comment démarshal JSON à votre type POJO. Jackson fournit un MessageBodyReader
dans sa dépendance jackson-jaxrs-json-provider
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.4.0</version>
</dependency>
La plupart des implémentations fourniront un wrapper pour ce module, comme jersey-media-json-jackson
Pour Jersey ou resteasy-jackson-provider
Pour Resteasy. Mais ils utilisent toujours le sous-jacent jackson-jaxrs-json-provider
.
Cela étant dit, une fois que vous avez ce module sur le chemin de classe, est devrait être automatiquement enregistré, donc le MessageBodyReader
sera disponible. Sinon, vous pouvez l'enregistrer explicitement auprès du client, comme client.register(JacksonJaxbJsonProvider.class)
. Une fois que le support Jackson est configuré, vous pouvez simplement faire quelque chose comme
MyPojo myPojo = client.target(..).path(...).request().accept(..).get(MyPojo.class);
En ce qui concerne la publication/l'envoi de données, vous pouvez à nouveau regarder les différentes méthodes Invocation.Builder
. Par exemple
Invocation.Builder builder = target.request();
Si nous voulons publier, regardez les différentes méthodes post
disponibles. On peut utiliser
Response post(Entity<?> entity)
- Notre requête pourrait ressembler à quelque chose
Response response = builder.post(Entity.json(myPojo));
Vous remarquerez Entity
. Toutes les méthodes post
acceptent un Entity
, et c'est ainsi que la requête saura de quel type doit être le corps d'entité, et le client invoquera le MessageBodyWriter
approprié ainsi que définir l'en-tête approprié
<T> T post(Entity<?> entity, Class<T> responseType)
- Il y a une autre surcharge, où nous pouvons spécifier le type à démarsaler dans, au lieu de récupérer un Response
. Nous pourrions faire
MyPojo myPojo = builder.post(Entity.json(myPojo), MyPojo.class)
Notez qu'avec Response
, nous appelons sa méthode readEntity(Class pojoType)
pour lire le Response
, le corps de l'entité. L'avantage de ceci est que l'objet Response
est livré avec beaucoup d'informations utiles que nous pouvons utiliser, comme des en-têtes et autres. Personnellement, je reçois toujours le Response
Response response = builder.get();
MyPojo pojo = response.readEntity(MyPojo.class);
En passant, pour votre code particulier que vous montrez, vous voudrez probablement en faire une méthode @POST
. N'oubliez pas que @GET
Sert principalement à récupérer les données, PUT
à mettre à jour et POST
à créer. C'est une bonne règle de base à respecter lors du premier démarrage. Vous pouvez donc changer la méthode en
@Path("orders")
public class OrdersResource {
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes({MediaType.APPLICATION_JSON})
public Response createOrder(@Context UriInfo uriInfo, Order input) {
Order order = orderService.createOrder(input);
URI uri = uriInfo.getAbsolutePathBuilder().path(order.getId()).build();
return Response.create(uri).entity(order).build();
}
}
Ensuite, vous pouvez faire
WebTarget target = client.target(BASE).path("orders");
Response response = target.request().accept(...).post(Entity.json(order));
Order order = response.readEntity(Order.class);
Vous devez utiliser POST ou PUT à la place GET
essayez ce code
final Client client = new Client();
final Order input = new Order();
input.setId("1");
input.setDescription("description");
final Order output = client.resource(
"http://localhost:8080/orders/writeAndIncrementOrder").
header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON).
entity(input).post(Order.class);