REST service that accepts and returns object. How to write client?

北城以北 提交于 2019-12-02 20:56:14
Paul Samsotha

If you take a little bit of time to understand the WebTarget API, as well as the different types returned from calls to WebTarget's method, you should get a better understanding of how to make calls. It may be a little confusing, as almost all the example use method chaining, as it's a very convenient way, but doing this, you miss all the actual classes involved in create and sending the request. Let break it down a bit

WebTarget target = client.target(getBaseURI()).path("rest").path("orders");

WebTarget.path() simply returns the WebTarget. Nothing interesting there.

target.path("oneOrder").request().accept(MediaType.APPLICATION_JSON).get(String.class)

  • WebTarget.request() returns Invocation.Builder
  • Invocation.Builder.accept(..) returns Invocation.Builder
  • Invocation.Builder.get() calls its super class's SyncInvoker.get(), which makes the actual request, and returns a type, based on the argument we provide to get(Class returnType)

What you're doing with get(String.class) is saying that the response stream should be deserialized into a Sting type response. This is not a problem, as JSON is inherently just a String. But if you want to unmarshal it to a POJO, then you need to have a MessageBodyReader that knows how to unmarshal JSON to your POJO type. Jackson provides a MessageBodyReader in it's jackson-jaxrs-json-provider dependency

<dependency>
  <groupId>com.fasterxml.jackson.jaxrs</groupId>
  <artifactId>jackson-jaxrs-json-provider</artifactId>
  <version>2.4.0</version>
</dependency>

Most implementations will provider a wrapper for this module, like jersey-media-json-jackson for Jersey or resteasy-jackson-provider for Resteasy. But they are still using the underlying jackson-jaxrs-json-provider.

That being said, once you have that module on the classpath, is should be automatically registered, so the MessageBodyReader will be available. If not you can register it explicitly with the client, like client.register(JacksonJaxbJsonProvider.class). Once you have the Jackson support configured, then you can simply do something like

MyPojo myPojo = client.target(..).path(...).request().accept(..).get(MyPojo.class);

As for posting/sending data, you can again look at the different Invocation.Builder methods. For instance

Invocation.Builder builder = target.request();

If we want to post, look at the different post methods available. We can use

  • Response post(Entity<?> entity) - Our request might look something like

    Response response = builder.post(Entity.json(myPojo));
    

    You'll notice the Entity. All the post methods accept an Entity, and this is how the request will know what type the entity body should be, and the client will invoke the approriate MessageBodyWriter as well as set the appropriate header

  • <T> T post(Entity<?> entity, Class<T> responseType) - There's another overload, where we can specify the type to unmarshal into, instead of getting back a Response. We could do

    MyPojo myPojo = builder.post(Entity.json(myPojo), MyPojo.class)
    

Note that with Response, we call its readEntity(Class pojoType) method to read from the Response, the entity body. The advantage of this, is that the Response object comes with a lot of useful information we can use, like headers and such. Personally, I always get the Response

    Response response = builder.get();
    MyPojo pojo = response.readEntity(MyPojo.class);

As an aside, for your particular code you are showing, you most likely want to make it a @POST method. Remember @GET is mainly for retrieving data, PUT for updating, and POST for creating. That is a good rule of thumb to stick to, when first starting out. So you might change the method to

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

Then you can do

WebTarget target = client.target(BASE).path("orders");
Response response = target.request().accept(...).post(Entity.json(order));
Order order = response.readEntity(Order.class);

You should use POST or PUT instead GET

try this 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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!