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