web-dev-qa-db-ja.com

RESTオブジェクトを受け入れて返すサービス。クライアントを書く方法は?

2つのREST Webサービス。1つは単にオブジェクトを返す。もう1つはオブジェクトを受け入れて別のオブジェクトを返す。POJOOrder.Javaが使用されている。

@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サービスは次のように定義されます

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

オブジェクトを返す以外は何も受け入れないWebサービスを呼び出すクライアントコードを作成できます。クライアントコードは次のとおりです

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

しかし、オブジェクトを受け取るだけでなくオブジェクトを返す他のサービスを呼び出す方法がわかりません。インターネットで提供されているさまざまなソリューションを試しました。しかし、何も私にとってはうまくいきませんでした。一部のソリューションはオブジェクトの送信にのみ機能し、一部のソリューションは受け入れにのみ機能します。しかし、1回の呼び出しで両方を行うために働いた人はいませんでした。

[〜#〜] edit [〜#〜]以下の回答で示唆したように、私はJacksonJaxbJsonProvider.classを登録しましたが、Orderオブジェクトへの自動変換は行われていません。

        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);

上記のプログラムでは、{"id": "1"、 "description": "これが1次です"として文字列を正常に取得しますが、直接オブジェクトを取得すると、メディアtype = application/json、type = class shopping .cart.om.Order、genericType = class shopping.cart.om.Order。

13
Kaushik Lele

WebTarget API、およびWebTargetのメソッドの呼び出しから返されるさまざまなタイプを理解するのに少し時間がかかる場合、よりよく理解する必要があります。呼び出し方法の。ほとんどすべての例はメソッドチェーンを使用しているため、少し混乱するかもしれませんが、これは非常に便利な方法ですが、これを行うと、リクエストの作成と送信に関与する実際のクラスがすべて失われます。少し分解しましょう

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

WebTarget.path()は、単にWebTargetを返します。面白いことは何もありません。

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

  • WebTarget.request()Invocation.Builder を返します
  • Invocation.Builder.accept(..)Invocation.Builderを返します
  • Invocation.Builder.get()は、スーパークラスの SyncInvoker.get() を呼び出します。これにより、実際の要求が行われ、get(Class returnType)に提供する引数に基づいて型が返されます

get(String.class)で行っていることは、応答ストリームをStingタイプの応答に逆シリアル化する必要があるということです。 JSONは本質的に単なる文字列であるため、これは問題ではありません。しかし、それをPOJOに非整列化する場合は、JSONをPOJO型に非整列化する方法を知っているMessageBodyReaderが必要です。 JacksonはMessageBodyReaderを提供します jackson-jaxrs-json-provider 依存関係

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

ほとんどの実装は、Jerseyのjersey-media-json-jacksonやResteasyのresteasy-jackson-providerなど、このモジュールのラッパーを提供します。しかし、彼らはまだ基礎となるjackson-jaxrs-json-providerを使用しています。

つまり、クラスパスでそのモジュールを取得すると、shouldが自動的に登録されるため、MessageBodyReaderが使用可能になります。そうでない場合は、client.register(JacksonJaxbJsonProvider.class)のように、クライアントに明示的に登録できます。ジャクソンのサポートを設定したら、次のように簡単に実行できます

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

データの送信/送信に関しては、さまざまなInvocation.Builderメソッドを再度見ることができます。例えば

Invocation.Builder builder = target.request();

投稿したい場合は、利用可能な異なる post メソッドを見てください。使用できます

  • Response post(Entity<?> entity)-リクエストは次のようになります

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

    Entity に気付くでしょう。すべてのpostメソッドはEntityを受け入れます。これにより、リクエストはエンティティ本体のタイプを認識し、クライアントは適切なMessageBodyWriterを呼び出すだけでなく、適切なヘッダーを設定します

  • <T> T post(Entity<?> entity, Class<T> responseType)-Responseを取得する代わりに、非整列化する型を指定できるオーバーロードがあります。できる

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

Responseでは、そのreadEntity(Class pojoType)メソッドを呼び出して、エンティティ本体であるResponseから読み取ることに注意してください。この利点は、Responseオブジェクトに、ヘッダーなどの使用可能な多くの有用な情報が付属していることです。個人的には、常にResponseを取得します

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

余談ですが、表示している特定のコードについては、@POSTメソッドにすることをお勧めします。 @GETは主にデータの取得用、PUTは更新用、POSTは作成用です。それは最初に始めるとき、固執する良い経験則です。そのため、メソッドを

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

その後、あなたはできる

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

GETの代わりにPOSTまたはPUTを使用する必要があります

このコードを試してください

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);
4
Dmitry Zaytsev