YMD YMD - 1 month ago 10
Java Question

How to create RESTful web service client by Jersey2.0 or above

There seems to be many examples about creating RESTful clients by Jersey 1.x, but not Jersey 2.0 or above.
I referred to other questions and the Jersey's web site, but I still cannot create a client for REST due to the differences between Jersey 2.0 and the previous one.
So I'd like to ask some advice.

So far, my coding is like this.

ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target("http://localhost:8080/CustomerBack2211/webresources/entities.customer");

Invocation.Builder invocationBuilder = target.request(MediaType.TEXT_XML_TYPE);
Response response = invocationBuilder.get();
System.out.println(response.getStatus());
System.out.println(response.readEntity(String.class));


This produces 406 error.

However, when I tried to test RESTful service by Glassfish server, the test works properly, and the server side class has its @GET methods having @Produces({"application/xml", "application/json"}).
So I don't see why the coding above produces 406 error on a Java application.

(i.e. the client side has @GET methods in the following way)

@GET
@Path("{id}")
@Produces({"application/xml", "application/json"})
public Customer find(@PathParam("id") Integer id) {
return super.find(id);
}

@GET
@Override
@Produces({ "application/xml"})
public List<Customer> findAll() {
return super.findAll();
}


Does any of you see what I'm doing wrong, or could you please suggest an example of a RESTful client?
Any advice will be helpful...thanks in advance!




In addition, I'd appreciate if you would offer information about how to invoke methods like GET, PUT and DELETE with appropriate parameters.
I just needed to put an ID number (i.e. integer values) when I was testing the server side class on Glassfish RESTful test. However, it seems that I need to set "Class" and/or "Entity" values as arguments, but I cannot see any information associated with them on the Jersey website.

Answer

For the first block of code:

406 means Not Acceptable.

Look at your request() method target.request(MediaType.TEXT_XML_TYPE). From the Javadoc of request() if states

Invocation.Builder request(MediaType... acceptedResponseTypes)

Start building a request to the targeted web resource and define the accepted response media types. Invoking this method is identical to:

webTarget.request().accept(types);

So basically, in your request, you are saying that you will only Accept: text/plain. Now look at your resource methods. Look at the @Produces. None of them "produce" text/plain. It's all json or xml. That's why you get the exception. Change the accept to application/xml (or MediaType.APPLICATION_XML) on the client side, and you should no longer get this error.

For the second question: I'm assuming you mean why does it work when you test it from the browser.

If you send a request from the browser by simply typing in the url, it will send out the request with many Accept types. If you have firebug (for FireFox) or the developer tools (for Chrome), if you send out a request, you will see a header similar to

Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

You can see application/xml in there. Even if application/xml wasn't there, the wild card */* is there, so basically almost all media types are acceptable as a return type when working in the browser.

For your last question:

Look at the API for SyncInvoker, which Invocation.Builder extends from. You will see different overrloaded put and post methods, most of which, as you mentioned accept an Entity.

There are a few different ways to build an Entity, all of which use one of the static methods. Here are some

  • Entity.entity( body, mediaType )
  • Entity.json( body )
  • Entity.xml( body )

And many more (see the Entity link above). But all of these static method return an Entity. So we could do something like

// resource method
@POST
@Consumes(MediaType.APPLICATION_XML)
public Response getResponse(Customer customer) { ... }

// some model class
@XmlRootElement
public class Customer { ... }

// client request
Customer customer = new Customer();
Response response = target.request().post(Entity.xml(customer));

Internally, the Customer will get converted to XML. If you used Entity.json is would get converted to JSON, BUT you need to make sure you have a JSON provider dependency. Jersey will not come with one by default. See more at Support for Common Media Type Representations


Also note, with your method find, when you try and make a request to the method, the request should end with an integer value, as that's the type specified for the {id} path parameter.

Comments