Skip to content

Commit e349979

Browse files
committed
feat: RequestBuilder changes to support JSON streaming feature
Fixes arf/planning-sdk-squad#901 The RequestBuilder.bodyContent() method is modified to no longer use the contentType parameter to determine which one of the other three input parameters should be used to create the request body. Instead, we now use the first non-null value using the order 'jsonContent', 'jsonPatchContent', then 'nonJsonContent'. This change is necessary for us to implement the JSON streaming feature, where the SDK user might serialize the JSON content himself and pass it in as a String or InputStream while also using a contentType that would otherwise indicate a JSON body.
1 parent 3b55ac6 commit e349979

File tree

2 files changed

+87
-21
lines changed

2 files changed

+87
-21
lines changed

src/main/java/com/ibm/cloud/sdk/core/http/RequestBuilder.java

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* (C) Copyright IBM Corp. 2015, 2019.
2+
* (C) Copyright IBM Corp. 2015, 2020.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
55
* the License. You may obtain a copy of the License at
@@ -13,22 +13,22 @@
1313

1414
package com.ibm.cloud.sdk.core.http;
1515

16+
import java.io.InputStream;
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
1620
import com.google.gson.Gson;
1721
import com.google.gson.JsonObject;
18-
import com.ibm.cloud.sdk.core.service.BaseService;
1922
import com.ibm.cloud.sdk.core.util.GsonSingleton;
2023
import com.ibm.cloud.sdk.core.util.StringHelper;
2124
import com.ibm.cloud.sdk.core.util.Validator;
25+
2226
import okhttp3.FormBody;
2327
import okhttp3.HttpUrl;
2428
import okhttp3.MediaType;
2529
import okhttp3.Request;
2630
import okhttp3.RequestBody;
2731

28-
import java.io.InputStream;
29-
import java.util.ArrayList;
30-
import java.util.List;
31-
3232
/**
3333
* Convenience class for constructing HTTP/HTTPS requests.
3434
*/
@@ -325,26 +325,33 @@ public RequestBuilder bodyContent(InputStream stream, String contentType) {
325325
return body(InputStreamRequestBody.create(MediaType.parse(contentType), stream));
326326
}
327327

328+
328329
/**
329-
* Sets the request body content from one of three different sources, based on the content type.
330+
* Sets the request body content from one of three different sources.
331+
* The three input sources are used in this precedence order:
332+
* <ol>
333+
* <li>If 'jsonContent' is not null, then use that.</li>
334+
* <li>If 'jsonPatchContent' is not null, then use that.</li>
335+
* <li>Else use 'nonJsonContent'.
336+
* </ol>
330337
*
331338
* @param contentType
332-
* the value of the "Content-Type" header associated with the outgoing request
339+
* the value of the "Content-Type" header associated with the request body
333340
* @param jsonContent
334-
* the body content to be used if the content type indicates JSON
341+
* a model instance to be serialized and used for the request body
335342
* @param jsonPatchContent
336-
* the body content to be used if the content type indicates JsonPatch
343+
* a collection of JsonPatchOperation instances to be serialized and used for the request body
337344
* @param nonJsonContent
338-
* the body content to be used if the content type indicates non-JSON content
345+
* an InputStream whose contents should be used directly as the request body
339346
* @return this
340347
*/
341348
public RequestBuilder bodyContent(String contentType, Object jsonContent, Object jsonPatchContent,
342349
InputStream nonJsonContent) {
343350
if (contentType != null) {
344351
Gson requestGson = GsonSingleton.getGsonWithoutPrettyPrinting().newBuilder().create();
345-
if (BaseService.isJsonMimeType(contentType)) {
352+
if (jsonContent != null) {
346353
this.bodyContent(requestGson.toJson(jsonContent), contentType);
347-
} else if (BaseService.isJsonPatchMimeType(contentType)) {
354+
} else if (jsonPatchContent != null) {
348355
this.bodyContent(requestGson.toJson(jsonPatchContent), contentType);
349356
} else {
350357
this.bodyContent(nonJsonContent, contentType);
@@ -354,16 +361,22 @@ public RequestBuilder bodyContent(String contentType, Object jsonContent, Object
354361
}
355362

356363
/**
357-
* Sets the request body content from one of three different sources, based on the content type.
364+
* Sets the request body content from one of three different sources.
365+
* The three input sources are used in this precedence order:
366+
* <ol>
367+
* <li>If 'jsonContent' is not null, then use that.</li>
368+
* <li>If 'jsonPatchContent' is not null, then use that.</li>
369+
* <li>Else use 'nonJsonContent'.
370+
* </ol>
358371
*
359372
* @param contentType
360-
* the value of the "Content-Type" header associated with the outgoing request
373+
* the value of the "Content-Type" header associated with the request body
361374
* @param jsonContent
362-
* the body content to be used if the content type indicates JSON
375+
* a model instance to be serialized and used for the request body
363376
* @param jsonPatchContent
364-
* the body content to be used if the content type indicates JsonPatch
377+
* a collection of JsonPatchOperation instances to be serialized and used for the request body
365378
* @param nonJsonContent
366-
* the body content to be used if the content type indicates non-JSON content
379+
* a string to be used directly as the request body
367380
* @return this
368381
*/
369382
public RequestBuilder bodyContent(String contentType, Object jsonContent, Object jsonPatchContent,

src/test/java/com/ibm/cloud/sdk/core/test/service/RequestBuilderTest.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ public void testConstructHttpUrlEmptyPath1() {
293293
assertNotNull(url);
294294
assertEquals("https://myserver.com/testservice/api/discovery", url.toString());
295295
}
296-
296+
297297
@Test
298298
public void testConstructHttpUrlEmptyPath2() {
299299
String[] pathSegments = { "" };
@@ -333,13 +333,66 @@ public void testConstructHttpUrlEmptyPathAndParams() {
333333
public void testConstructHttpUrlEmpty() {
334334
String[] pathSegments = { "v1/seg1", "seg2", "seg3"};
335335
String[] pathParameters = { "param1", "param2" };
336-
HttpUrl url = RequestBuilder.constructHttpUrl("", pathSegments, pathParameters);
336+
RequestBuilder.constructHttpUrl("", pathSegments, pathParameters);
337337
}
338338

339339
@Test(expected = IllegalArgumentException.class)
340340
public void testConstructHttpUrlNull() {
341341
String[] pathSegments = { "v1/seg1", "seg2", "seg3"};
342342
String[] pathParameters = { "param1", "param2" };
343-
HttpUrl url = RequestBuilder.constructHttpUrl(null, pathSegments, pathParameters);
343+
RequestBuilder.constructHttpUrl(null, pathSegments, pathParameters);
344+
}
345+
346+
/**
347+
* Test bodyContent() with a model instance.
348+
* @throws IOException
349+
*/
350+
@Test
351+
public void testBodyContent1() throws IOException {
352+
Truck truck = new Truck.Builder().vehicleType("Truck").make("Ford").engineType("raptor").build();
353+
final Request request = RequestBuilder.post(HttpUrl.parse(urlWithQuery))
354+
.bodyContent("application/json", truck, null, (InputStream) null).build();
355+
final RequestBody requestedBody = request.body();
356+
final Buffer buffer = new Buffer();
357+
requestedBody.writeTo(buffer);
358+
359+
assertEquals(GsonSingleton.getGsonWithoutPrettyPrinting().toJson(truck), buffer.readUtf8());
360+
assertEquals(HttpMediaType.JSON, requestedBody.contentType());
361+
}
362+
363+
/**
364+
* Test bodyContent() with an already serialized model instance (a String).
365+
* @throws IOException
366+
*/
367+
@Test
368+
public void testBodyContent2() throws IOException {
369+
Truck truck = new Truck.Builder().vehicleType("Truck").make("Ford").engineType("raptor").build();
370+
String jsonString = GsonSingleton.getGsonWithoutPrettyPrinting().toJson(truck);
371+
final Request request = RequestBuilder.post(HttpUrl.parse(urlWithQuery))
372+
.bodyContent("application/json", null, null, jsonString).build();
373+
final RequestBody requestedBody = request.body();
374+
final Buffer buffer = new Buffer();
375+
requestedBody.writeTo(buffer);
376+
377+
assertEquals(jsonString, buffer.readUtf8());
378+
assertEquals(MediaType.parse("application/json"), requestedBody.contentType());
344379
}
380+
381+
/**
382+
* Test bodyContent() with a multiple inputs (JSON input should win).
383+
* @throws IOException
384+
*/
385+
@Test
386+
public void testBodyContent3() throws IOException {
387+
Truck truck = new Truck.Builder().vehicleType("Truck").make("Ford").engineType("raptor").build();
388+
final Request request = RequestBuilder.post(HttpUrl.parse(urlWithQuery))
389+
.bodyContent("application/json", truck, "BAD JSON PATCH BODY", "BAD INPUTSTREAM REQUEST BODY").build();
390+
final RequestBody requestedBody = request.body();
391+
final Buffer buffer = new Buffer();
392+
requestedBody.writeTo(buffer);
393+
394+
assertEquals(GsonSingleton.getGsonWithoutPrettyPrinting().toJson(truck), buffer.readUtf8());
395+
assertEquals(HttpMediaType.JSON, requestedBody.contentType());
396+
}
397+
345398
}

0 commit comments

Comments
 (0)