This is an automated email from the ASF dual-hosted git repository.
jensdeppe pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 4b0854a GEODE-5016: Replace org.json with Jackson in geode-web-api
(#3267)
4b0854a is described below
commit 4b0854ac478c713c45b8927fc9dfdcaf909cfc16
Author: Jens Deppe <[email protected]>
AuthorDate: Fri Mar 8 05:48:03 2019 -0800
GEODE-5016: Replace org.json with Jackson in geode-web-api (#3267)
---
.../web/controllers/RestAccessControllerTest.java | 49 +++++++++--
.../internal/web/controllers/order1-array.json | 30 +++++++
.../web/controllers/AbstractBaseController.java | 97 ++++++++++++----------
.../web/controllers/CommonCrudController.java | 12 +--
.../web/controllers/FunctionAccessController.java | 14 +---
.../geode/rest/internal/web/util/JSONUtils.java | 3 +-
6 files changed, 136 insertions(+), 69 deletions(-)
diff --git
a/geode-web-api/src/integrationTest/java/org/apache/geode/rest/internal/web/controllers/RestAccessControllerTest.java
b/geode-web-api/src/integrationTest/java/org/apache/geode/rest/internal/web/controllers/RestAccessControllerTest.java
index 023a41f..0392240 100644
---
a/geode-web-api/src/integrationTest/java/org/apache/geode/rest/internal/web/controllers/RestAccessControllerTest.java
+++
b/geode-web-api/src/integrationTest/java/org/apache/geode/rest/internal/web/controllers/RestAccessControllerTest.java
@@ -15,6 +15,7 @@
package org.apache.geode.rest.internal.web.controllers;
import static org.apache.geode.test.matchers.JsonEquivalence.jsonEquals;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
@@ -65,6 +66,7 @@ import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.Declarable;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.LoaderHelper;
+import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionDestroyedException;
import org.apache.geode.cache.RegionEvent;
import org.apache.geode.cache.RegionShortcut;
@@ -72,6 +74,7 @@ import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.execute.FunctionService;
import org.apache.geode.internal.cache.HttpService;
import org.apache.geode.management.internal.RestAgent;
+import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.test.junit.rules.ServerStarterRule;
@RunWith(SpringJUnit4ClassRunner.class)
@@ -83,6 +86,7 @@ public class RestAccessControllerTest {
private static final String BASE_URL = "http://localhost/v1";
private static final String ORDER1_JSON = "order1.json";
+ private static final String ORDER1_ARRAY_JSON = "order1-array.json";
private static final String ORDER1_NO_TYPE_JSON = "order1-no-type.json";
private static final String ORDER2_JSON = "order2.json";
private static final String ORDER2_UPDATED_JSON = "order2-updated.json";
@@ -100,6 +104,9 @@ public class RestAccessControllerTest {
private MockMvc mockMvc;
+ private static Region<?, ?> orderRegion;
+ private static Region<?, ?> customerRegion;
+
@ClassRule
public static ServerStarterRule rule = new ServerStarterRule()
.withProperty("log-level", "warn")
@@ -113,6 +120,7 @@ public class RestAccessControllerTest {
@BeforeClass
public static void setupCClass() throws Exception {
loadResource(ORDER1_JSON);
+ loadResource(ORDER1_ARRAY_JSON);
loadResource(ORDER1_NO_TYPE_JSON);
loadResource(ORDER2_JSON);
loadResource(MALFORMED_JSON);
@@ -131,6 +139,9 @@ public class RestAccessControllerTest {
rule.createRegion(RegionShortcut.REPLICATE_PROXY, "empty",
f -> f.setCacheLoader(new SimpleCacheLoader()).setCacheWriter(new
SimpleCacheWriter()));
+
+ customerRegion = rule.getCache().getRegion("customers");
+ orderRegion = rule.getCache().getRegion("orders");
}
private static void loadResource(String name) throws Exception {
@@ -142,8 +153,8 @@ public class RestAccessControllerTest {
public void setup() {
mockMvc =
MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
- rule.getCache().getRegion("customers").clear();
- rule.getCache().getRegion("orders").clear();
+ customerRegion.clear();
+ orderRegion.clear();
}
@Test
@@ -159,6 +170,28 @@ public class RestAccessControllerTest {
.content(jsonResources.get(ORDER1_JSON))
.with(POST_PROCESSOR))
.andExpect(status().isConflict());
+
+ Order order = (Order) ((PdxInstance) orderRegion.get("1")).getObject();
+ assertThat(order).as("order should not be null").isNotNull();
+ }
+
+ @Test
+ @WithMockUser
+ public void postEntryWithJsonArrayOfOrders() throws Exception {
+ mockMvc.perform(post("/v1/orders?key=1")
+ .content(jsonResources.get(ORDER1_ARRAY_JSON))
+ .with(POST_PROCESSOR))
+ .andExpect(status().isCreated())
+ .andExpect(header().string("Location", BASE_URL + "/orders/1"));
+
+ mockMvc.perform(post("/v1/orders?key=1")
+ .content(jsonResources.get(ORDER1_ARRAY_JSON))
+ .with(POST_PROCESSOR))
+ .andExpect(status().isConflict());
+
+ List<PdxInstance> entries = (List<PdxInstance>) orderRegion.get("1");
+ Order order = (Order) entries.get(0).getObject();
+ assertThat(order).as("order should not be null").isNotNull();
}
@Test
@@ -168,7 +201,8 @@ public class RestAccessControllerTest {
.content(jsonResources.get(MALFORMED_JSON))
.with(POST_PROCESSOR))
.andExpect(status().isBadRequest())
- .andExpect(jsonPath("$.cause", is("JSON document specified in the
request is incorrect")));
+ .andExpect(
+ jsonPath("$.cause", is("Json doc specified is either not supported
or invalid!")));
}
@Test
@@ -238,7 +272,8 @@ public class RestAccessControllerTest {
.content(jsonResources.get(MALFORMED_JSON))
.with(POST_PROCESSOR))
.andExpect(status().isBadRequest())
- .andExpect(jsonPath("$.cause", is("JSON document specified in the
request is incorrect")));
+ .andExpect(
+ jsonPath("$.cause", is("Json doc specified is either not supported
or invalid!")));
}
@Test
@@ -349,7 +384,8 @@ public class RestAccessControllerTest {
.content(jsonResources.get(MALFORMED_JSON))
.with(POST_PROCESSOR))
.andExpect(status().isBadRequest())
- .andExpect(jsonPath("$.cause", is("JSON document specified in the
request is incorrect")));
+ .andExpect(
+ jsonPath("$.cause", is("Json doc specified is either not supported
or invalid!")));
}
@Test
@@ -436,7 +472,8 @@ public class RestAccessControllerTest {
.content(jsonResources.get(MALFORMED_JSON))
.with(POST_PROCESSOR))
.andExpect(status().isBadRequest())
- .andExpect(jsonPath("$.cause", is("JSON document specified in the
request is incorrect")));
+ .andExpect(
+ jsonPath("$.cause", is("Json doc specified in request body is
invalid!")));
}
@Test
diff --git
a/geode-web-api/src/integrationTest/resources/org/apache/geode/rest/internal/web/controllers/order1-array.json
b/geode-web-api/src/integrationTest/resources/org/apache/geode/rest/internal/web/controllers/order1-array.json
new file mode 100644
index 0000000..f7c2ab2
--- /dev/null
+++
b/geode-web-api/src/integrationTest/resources/org/apache/geode/rest/internal/web/controllers/order1-array.json
@@ -0,0 +1,30 @@
+[
+ {
+ "@type": "org.apache.geode.rest.internal.web.controllers.Order",
+ "purchaseOrderNo": 111,
+ "customerId": 101,
+ "description": "Purchase order for company - A",
+ "orderDate": "01/10/2014",
+ "deliveryDate": "01/20/2014",
+ "contact": "Nilkanthkumar N Patel",
+ "email": "[email protected]",
+ "phone": "020-2048096",
+ "totalPrice": 205,
+ "items": [
+ {
+ "itemNo": 1,
+ "description": "Product-1",
+ "quantity": 5,
+ "unitPrice": 10,
+ "totalPrice": 50
+ },
+ {
+ "itemNo": 1,
+ "description": "Product-2",
+ "quantity": 10,
+ "unitPrice": 15.5,
+ "totalPrice": 155
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
index 2466430..ccb8172 100644
---
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
+++
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/AbstractBaseController.java
@@ -28,15 +28,16 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
+import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.Logger;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.json.JSONTokener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
@@ -176,21 +177,24 @@ public abstract class AbstractBaseController implements
InitializingBean {
@SuppressWarnings("unchecked")
private <T> T casValue(String regionNamePath, String key, String jsonData) {
- JSONObject jsonObject;
try {
- jsonObject = new JSONObject(jsonData);
- String oldValue = jsonObject.get("@old").toString();
- String newValue = jsonObject.get("@new").toString();
+ JsonNode jsonObject = objectMapper.readTree(jsonData);
+ JsonNode oldValue = jsonObject.get("@old");
+ JsonNode newValue = jsonObject.get("@new");
- return (T) casValue(regionNamePath, key, convert(oldValue),
convert(newValue));
+ if (oldValue == null || newValue == null) {
+ throw new MalformedJsonException("Json doc specified in request body
is invalid!");
+ }
+
+ return (T) casValue(regionNamePath, key, convert(oldValue.toString()),
+ convert(newValue.toString()));
- } catch (JSONException je) {
+ } catch (IOException je) {
throw new MalformedJsonException("Json doc specified in request body is
invalid!", je);
}
}
- ResponseEntity<String> processQueryResponse(Query query, Object args[],
Object queryResult)
- throws JSONException {
+ ResponseEntity<String> processQueryResponse(Query query, Object args[],
Object queryResult) {
if (queryResult instanceof Collection<?>) {
Collection processedResults = new ArrayList(((Collection)
queryResult).size());
for (Object result : (Collection) queryResult) {
@@ -208,23 +212,25 @@ public abstract class AbstractBaseController implements
InitializingBean {
}
Collection<PdxInstance> convertJsonArrayIntoPdxCollection(final String
jsonArray) {
- JSONArray jsonArr = null;
try {
- jsonArr = new JSONArray(jsonArray);
- Collection<PdxInstance> pdxInstances = new ArrayList<PdxInstance>();
+ JsonNode array = objectMapper.readTree(jsonArray);
+ if (!array.isArray()) {
+ throw new MalformedJsonException(
+ "Json document specified in request body is not an array!");
+ }
+
+ Collection<PdxInstance> pdxInstances = new ArrayList<>();
- for (int index = 0; index < jsonArr.length(); index++) {
- // String element = jsonArr.getJSONObject(i).toString();
- // String element = jsonArr.getString(i);
- Object object = jsonArr.get(index);
- String element = object.toString();
+ for (int index = 0; index < array.size(); index++) {
+ JsonNode object = array.get(index);
+ String element = objectMapper.writeValueAsString(object);
PdxInstance pi = convert(element);
pdxInstances.add(pi);
}
return pdxInstances;
- } catch (JSONException je) {
+ } catch (IOException je) {
throw new MalformedJsonException("Json document specified in request
body is not valid!", je);
}
}
@@ -692,8 +698,9 @@ public abstract class AbstractBaseController implements
InitializingBean {
return (T) rawDataBinding;
} else {
final String typeValue = (String)
rawDataBinding.get(TYPE_META_DATA_PROPERTY);
- if (typeValue == null)
- return (T) new JSONObject();
+ if (typeValue == null) {
+ return (T) objectMapper.createObjectNode();
+ }
// Added for the primitive types put. Not supporting primitive types
if (NumberUtils.isPrimitiveOrObject(typeValue)) {
final Object primitiveValue = rawDataBinding.get("@value");
@@ -749,20 +756,25 @@ public abstract class AbstractBaseController implements
InitializingBean {
}
Object[] jsonToObjectArray(final String arguments) {
- final JSONTypes jsonType = validateJsonAndFindType(arguments);
- if (JSONTypes.JSON_ARRAY.equals(jsonType)) {
+ JsonNode node;
+ try {
+ node = objectMapper.readTree(arguments);
+ } catch (IOException e) {
+ throw new MalformedJsonException("Json document specified in request
body is not valid!");
+ }
+
+ if (node.isArray()) {
try {
- JSONArray jsonArray = new JSONArray(arguments);
- Object[] args = new Object[jsonArray.length()];
- for (int index = 0; index < jsonArray.length(); index++) {
- args[index] = jsonToObject(jsonArray.get(index).toString());
+ Object[] args = new Object[node.size()];
+ for (int index = 0; index < node.size(); index++) {
+ args[index] =
jsonToObject(objectMapper.writeValueAsString(node.get(index)));
}
return args;
- } catch (JSONException je) {
+ } catch (JsonProcessingException je) {
throw new MalformedJsonException("Json document specified in request
body is not valid!",
je);
}
- } else if (JSONTypes.JSON_OBJECT.equals(jsonType)) {
+ } else if (node.isObject()) {
return new Object[] {jsonToObject(arguments)};
} else {
throw new MalformedJsonException("Json document specified in request
body is not valid!");
@@ -807,14 +819,14 @@ public abstract class AbstractBaseController implements
InitializingBean {
ResponseEntity<String> updateMultipleKeys(final String region, final
String[] keys,
final String json) {
- JSONArray jsonArr = null;
+ JsonNode jsonArr;
try {
- jsonArr = new JSONArray(json);
- } catch (JSONException e) {
+ jsonArr = objectMapper.readTree(json);
+ } catch (IOException e) {
throw new MalformedJsonException("JSON document specified in the request
is incorrect", e);
}
- if (jsonArr.length() != keys.length) {
+ if (!jsonArr.isArray() || jsonArr.size() != keys.length) {
throw new MalformedJsonException(
"Each key must have corresponding value (JSON document) specified in
the request");
}
@@ -827,9 +839,9 @@ public abstract class AbstractBaseController implements
InitializingBean {
}
try {
- PdxInstance pdxObj = convert(jsonArr.getJSONObject(i).toString());
+ PdxInstance pdxObj =
convert(objectMapper.writeValueAsString(jsonArr.get(i)));
map.put(keys[i], pdxObj);
- } catch (JSONException e) {
+ } catch (JsonProcessingException e) {
throw new MalformedJsonException(
String.format("JSON document at index (%1$s) in the request body
is incorrect", i), e);
}
@@ -841,21 +853,22 @@ public abstract class AbstractBaseController implements
InitializingBean {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri(region,
StringUtils.arrayToCommaDelimitedString(keys)));
- return new ResponseEntity<String>(headers, HttpStatus.OK);
+ return new ResponseEntity<>(headers, HttpStatus.OK);
}
JSONTypes validateJsonAndFindType(String json) {
try {
- Object jsonObj = new JSONTokener(json).nextValue();
+ JsonParser jp = new JsonFactory().createParser(json);
+ JsonToken token = jp.nextToken();
- if (jsonObj instanceof JSONObject) {
+ if (token == JsonToken.START_OBJECT) {
return JSONTypes.JSON_OBJECT;
- } else if (jsonObj instanceof JSONArray) {
+ } else if (token == JsonToken.START_ARRAY) {
return JSONTypes.JSON_ARRAY;
} else {
return JSONTypes.UNRECOGNIZED_JSON;
}
- } catch (JSONException je) {
+ } catch (IOException je) {
throw new MalformedJsonException("JSON document specified in the request
is incorrect", je);
}
}
diff --git
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
index 6ffd726..ed411f0 100644
---
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
+++
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/CommonCrudController.java
@@ -23,7 +23,6 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.logging.log4j.Logger;
-import org.json.JSONException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -203,14 +202,9 @@ public abstract class CommonCrudController extends
AbstractBaseController {
if (functionResult instanceof List<?>) {
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri("servers"));
- try {
- String functionResultAsJson =
- JSONUtils.convertCollectionToJson((ArrayList<Object>)
functionResult);
- return new ResponseEntity<>(functionResultAsJson, headers,
HttpStatus.OK);
- } catch (JSONException e) {
- throw new GemfireRestException(
- "Could not convert function results into Restful (JSON)
format!", e);
- }
+ String functionResultAsJson =
+ JSONUtils.convertCollectionToJson((ArrayList<Object>)
functionResult);
+ return new ResponseEntity<>(functionResultAsJson, headers,
HttpStatus.OK);
} else {
throw new GemfireRestException(
"Function has returned results that could not be converted into
Restful (JSON) format!");
diff --git
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
index ed93ff2..18c2f51 100644
---
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
+++
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/controllers/FunctionAccessController.java
@@ -25,7 +25,6 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.logging.log4j.Logger;
-import org.json.JSONException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -254,15 +253,10 @@ public class FunctionAccessController extends
AbstractBaseController {
functionResult = results.getResult();
if (functionResult instanceof List<?>) {
- try {
- @SuppressWarnings("unchecked")
- String functionResultAsJson =
- JSONUtils.convertCollectionToJson((ArrayList<Object>)
functionResult);
- return new ResponseEntity<>(functionResultAsJson, headers,
HttpStatus.OK);
- } catch (JSONException e) {
- throw new GemfireRestException(
- "Could not convert function results into Restful (JSON)
format!", e);
- }
+ @SuppressWarnings("unchecked")
+ String functionResultAsJson =
+ JSONUtils.convertCollectionToJson((ArrayList<Object>)
functionResult);
+ return new ResponseEntity<>(functionResultAsJson, headers,
HttpStatus.OK);
} else {
throw new GemfireRestException(
"Function has returned results that could not be converted into
Restful (JSON) format!");
diff --git
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/util/JSONUtils.java
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/util/JSONUtils.java
index 8094d3f..7a1c2e4 100644
---
a/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/util/JSONUtils.java
+++
b/geode-web-api/src/main/java/org/apache/geode/rest/internal/web/util/JSONUtils.java
@@ -26,7 +26,6 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonGenerator.Feature;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
-import org.json.JSONException;
import org.springframework.util.Assert;
import org.apache.geode.cache.Region;
@@ -151,7 +150,7 @@ public abstract class JSONUtils {
}
}
- public static String convertCollectionToJson(Collection<Object> collection)
throws JSONException {
+ public static String convertCollectionToJson(Collection<Object> collection) {
HeapDataOutputStream outputStream =
new HeapDataOutputStream(org.apache.geode.internal.Version.CURRENT);