Java – a rest service that accepts and returns objects How to write client?
I have announced two rest web services A simple return of an object Others accept one object and return another
@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 }
Web service is defined as
@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; }
I can write client code to call a web service that does not accept anything but returns an object The client code is as follows
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(); }
But I don't understand how to call other accepted services and return objects I have tried different solutions on the Internet, but nothing is useful to me. Some solutions are only applicable to sending objects, and some are only applicable to receiving objects But no one does these two jobs on the same phone
The editor replied as suggested below that I have registered Jackson JAXB jsonprovider Class, but the automatic conversion to order object did not happen
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);
In the above program, I successfully get the string as {"Id": "1", "description": "this is the first command"} but get the direct object and throw an error. Messagebodyreader does not find media type = Application / JSON, type = class shopping cart. om. Order,genericType = class shopping. cart. om. Order.
Solution
If you take the time to understand the webtarget API and the different types returned from calling the webtarget method, you should better understand how to make a call This may be a bit confusing because almost all examples use method linking because it is a very convenient way, but in doing so, you miss all the actual classes involved in creating and sending requests Let's break it down
WebTarget. Path() returns only webtarget Nothing interesting
> WebTarget. Request() returns invocation Builder > Invocation. Builder. accept(..) Return to invocation Builder > Invocation. Builder. Get() calls syncinvoker of its superclass Get(), which is the actual request and returns a type according to the parameter get (class ReturnType) provided by us
Get (string. Class) is using to deserialize the response stream into a sting type response This is not a problem, because JSON is essentially just a string However, if you want to decompose JSON into POJO, you need a messagebodyreader, which can know how to decompose JSON into your POJO type Jackson provides a messagebodyreader, which relies on Jackson jaxrs JSON provider
<dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> <version>2.4.0</version> </dependency>
Most implementations will provide a wrapper for this module, such as Jersey media Jackson in Jersey or resteasy Jackson provider in resteasy But they are still using the basic Jackson - jaxrs - JSON - provider
Having said that, once you have this module on the classpath, it should be registered automatically, so messagebodyreader will be available If not, you can explicitly register with the client, such as client register(JacksonJaxbJsonProvider.class). Once you configure Jackson support, you can simply do something
MyPojo myPojo = client.target(..).path(...).request().accept(..).get(MyPojo.class);
For publishing / sending data, you can view different invocations again Builder method for example
Invocation.Builder builder = target.request();
If we want to publish, please check the different post methods available We can use
>Response post (entity entity) – our request may look like
Response response = builder.post(Entity.json(myPojo));
You will notice entity All post methods accept an entity, which is how the request knows what the entity type should be. The client will call the corresponding messagebodywriter and set the corresponding header > < T > t post (entity entity, class < T > responsetype) – there is also an overload. We can specify the type to be ungrouped instead of returning a response We can do it
MyPojo myPojo = builder.post(Entity.json(myPojo),MyPojo.class)
Please note that using response, we call its readentity (pojotype class) method reading from the response of the entity This advantage is that the response object contains a lot of useful information that we can use, such as title, etc Personally, I always get a response
Response response = builder.get(); MyPojo pojo = response.readEntity(MyPojo.class);
In addition, for the specific code you display, you are most likely to make it a @ post method Remember that @ get is mainly used to retrieve data, put for updating and post for creating This is a good rule of thumb to stick to when you first start So you can change the way
@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 it
WebTarget target = client.target(BASE).path("orders"); Response response = target.request().accept(...).post(Entity.json(order)); Order order = response.readEntity(Order.class);