This is an automated email from the ASF dual-hosted git repository.
bschuchardt 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 14bc5d6 GEODE-6196 Replace use of org.json with Jackson JSON library
14bc5d6 is described below
commit 14bc5d66ab5be0f8d171352460157b3b4bfbadc5
Author: Bruce Schuchardt <[email protected]>
AuthorDate: Thu Mar 7 15:51:48 2019 -0800
GEODE-6196 Replace use of org.json with Jackson JSON library
removed TypedJson, replacing with QueryResultFormatter
most of TypedJson's internals were replaced so I just renamed it to
QueryResultFormatter to better show its intended purpose.
QueryResultFormatter uses a Jackson ObjectMapper so it will pay
attention to Jackson annotations placed on classes to be serialized.
Object traversal depth is limited to the element-count being passed
by the QueryDataFunction function. Element-count in collections
are also limited. There is a new constructor that lets you specify
separate elementCount and serializationDepth parameters.
---
.../geode/tools/pulse/PulseDataExportTest.java | 2 +-
.../geode/management/QueryDataDUnitTest.java | 4 +-
... QueryResultFormatterQueryIntegrationTest.java} | 40 +-
.../management/DataQueryEngineIntegrationTest.java | 19 +-
...=> QueryResultFormatterPdxIntegrationTest.java} | 18 +-
.../apache/geode/codeAnalysis/excludedClasses.txt | 1 +
.../internal/beans/DistributedSystemBridge.java | 3 +-
.../internal/beans/QueryDataFunction.java | 9 +-
.../internal/cli/json/QueryResultFormatter.java | 416 +++++++++++
.../management/internal/cli/json/TypedJson.java | 806 ---------------------
.../apache/geode/pdx/internal/json/PdxToJSON.java | 16 +-
.../sanctioned-geode-core-serializables.txt | 2 +-
...JsonTest.java => QueryResultFormatterTest.java} | 66 +-
13 files changed, 503 insertions(+), 899 deletions(-)
diff --git
a/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseDataExportTest.java
b/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseDataExportTest.java
index 5fb6cfa..0dbb0ed 100644
---
a/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseDataExportTest.java
+++
b/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseDataExportTest.java
@@ -57,6 +57,6 @@ public class PulseDataExportTest {
.hasStatusCode(200)
.hasResponseBody()
.isEqualToIgnoringWhitespace(
-
"{\"result\":[[\"java.lang.String\",\"value1\"],[\"java.lang.String\",\"value2\"],[\"java.lang.String\",\"value3\"]]}");
+ "{\"result\":[\"value1\",\"value2\",\"value3\"]}");
}
}
diff --git
a/geode-core/src/distributedTest/java/org/apache/geode/management/QueryDataDUnitTest.java
b/geode-core/src/distributedTest/java/org/apache/geode/management/QueryDataDUnitTest.java
index e878e6b..fa037cd 100644
---
a/geode-core/src/distributedTest/java/org/apache/geode/management/QueryDataDUnitTest.java
+++
b/geode-core/src/distributedTest/java/org/apache/geode/management/QueryDataDUnitTest.java
@@ -63,7 +63,7 @@ import
org.apache.geode.internal.cache.PartitionedRegionHelper;
import
org.apache.geode.internal.cache.partitioned.fixed.SingleHopQuarterPartitionResolver;
import org.apache.geode.management.internal.SystemManagementService;
import org.apache.geode.management.internal.beans.BeanUtilFuncs;
-import org.apache.geode.management.internal.cli.json.TypedJson;
+import org.apache.geode.management.internal.beans.QueryDataFunction;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.pdx.PdxInstanceFactory;
import org.apache.geode.pdx.internal.PdxInstanceFactoryImpl;
@@ -237,7 +237,7 @@ public class QueryDataDUnitTest implements Serializable {
// Query With Default values
assertThat(distributedSystemMXBean.getQueryCollectionsDepth())
- .isEqualTo(TypedJson.DEFAULT_COLLECTION_ELEMENT_LIMIT);
+ .isEqualTo(QueryDataFunction.DEFAULT_COLLECTION_ELEMENT_LIMIT);
assertThat(distributedSystemMXBean.getQueryResultSetLimit()).isEqualTo(DEFAULT_QUERY_LIMIT);
String jsonString =
distributedSystemMXBean.queryData(QUERIES_FOR_LIMIT[0], null, 0);
diff --git
a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/TypedJsonQueryIntegrationTest.java
b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/QueryResultFormatterQueryIntegrationTest.java
similarity index 65%
rename from
geode-core/src/integrationTest/java/org/apache/geode/cache/query/TypedJsonQueryIntegrationTest.java
rename to
geode-core/src/integrationTest/java/org/apache/geode/cache/query/QueryResultFormatterQueryIntegrationTest.java
index 98992c6..1e9373c 100644
---
a/geode-core/src/integrationTest/java/org/apache/geode/cache/query/TypedJsonQueryIntegrationTest.java
+++
b/geode-core/src/integrationTest/java/org/apache/geode/cache/query/QueryResultFormatterQueryIntegrationTest.java
@@ -24,21 +24,21 @@ import org.apache.geode.cache.query.data.Position;
import org.apache.geode.cache.util.ObjectSizer;
import org.apache.geode.management.internal.cli.json.GfJsonException;
import org.apache.geode.management.internal.cli.json.GfJsonObject;
-import org.apache.geode.management.internal.cli.json.TypedJson;
-import
org.apache.geode.management.internal.cli.json.TypedJsonPdxIntegrationTest;
+import org.apache.geode.management.internal.cli.json.QueryResultFormatter;
+import
org.apache.geode.management.internal.cli.json.QueryResultFormatterPdxIntegrationTest;
import org.apache.geode.test.junit.categories.OQLQueryTest;
/**
- * Integration tests for {@link TypedJson} querying {@link Portfolio}.
+ * Integration tests for {@link QueryResultFormatter} querying {@link
Portfolio}.
* <p>
*
- * Extracted from {@link TypedJsonPdxIntegrationTest}.
+ * Extracted from {@link QueryResultFormatterPdxIntegrationTest}.
* <p>
*
* TODO: add real assertions
*/
@Category({OQLQueryTest.class})
-public class TypedJsonQueryIntegrationTest {
+public class QueryResultFormatterQueryIntegrationTest {
private static final String RESULT = "result";
@@ -46,18 +46,19 @@ public class TypedJsonQueryIntegrationTest {
public void testUserObject() throws Exception {
Portfolio p = new Portfolio(2);
- TypedJson typedJson = new TypedJson(RESULT, p);
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, p);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
public void testUserObjectArray() throws Exception {
Portfolio[] portfolios = createPortfoliosAndPositions(2);
- TypedJson typedJson = new TypedJson(RESULT, portfolios);
+ QueryResultFormatter queryResultFormatter =
+ new QueryResultFormatter(100).add(RESULT, portfolios);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
@@ -65,24 +66,25 @@ public class TypedJsonQueryIntegrationTest {
Portfolio[] portfolios = createPortfoliosAndPositions(1000);
System.out.println("Size Of port " +
ObjectSizer.REFLECTION_SIZE.sizeof(portfolios));
- TypedJson typedJson = new TypedJson(RESULT, portfolios);
- System.out.println("Size Of json " +
ObjectSizer.REFLECTION_SIZE.sizeof(typedJson));
+ QueryResultFormatter queryResultFormatter =
+ new QueryResultFormatter(100).add(RESULT, portfolios);
+ System.out.println("Size Of json " +
ObjectSizer.REFLECTION_SIZE.sizeof(queryResultFormatter));
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
public void testQueryLike() throws Exception {
Portfolio[] portfolios = createPortfoliosAndPositions(2);
- TypedJson typedJson = new TypedJson(RESULT, null);
- typedJson.add("member", "server1");
- // checkResult(typedJson); -- fails
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, null);
+ queryResultFormatter.add("member", "server1");
+ // checkResult(queryResultFormatter); -- fails
for (int i = 0; i < 2; i++) {
- typedJson.add(RESULT, portfolios[i]);
+ queryResultFormatter.add(RESULT, portfolios[i]);
}
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
private Portfolio[] createPortfoliosAndPositions(final int count) {
@@ -94,8 +96,8 @@ public class TypedJsonQueryIntegrationTest {
return portfolios;
}
- private void checkResult(final TypedJson typedJson) throws GfJsonException {
- GfJsonObject gfJsonObject = new GfJsonObject(typedJson.toString());
+ private void checkResult(final QueryResultFormatter queryResultFormatter)
throws GfJsonException {
+ GfJsonObject gfJsonObject = new
GfJsonObject(queryResultFormatter.toString());
System.out.println(gfJsonObject);
assertThat(gfJsonObject.get(RESULT)).isNotNull();
}
diff --git
a/geode-core/src/integrationTest/java/org/apache/geode/management/DataQueryEngineIntegrationTest.java
b/geode-core/src/integrationTest/java/org/apache/geode/management/DataQueryEngineIntegrationTest.java
index 6a55a2b..43be476 100644
---
a/geode-core/src/integrationTest/java/org/apache/geode/management/DataQueryEngineIntegrationTest.java
+++
b/geode-core/src/integrationTest/java/org/apache/geode/management/DataQueryEngineIntegrationTest.java
@@ -32,7 +32,7 @@ import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.management.internal.ManagementConstants;
import org.apache.geode.management.internal.SystemManagementService;
import org.apache.geode.management.internal.beans.DataQueryEngine;
-import org.apache.geode.management.internal.cli.json.TypedJson;
+import org.apache.geode.management.internal.beans.QueryDataFunction;
import org.apache.geode.management.model.EmptyObject;
import org.apache.geode.management.model.Item;
import org.apache.geode.management.model.Order;
@@ -61,7 +61,8 @@ public class DataQueryEngineIntegrationTest {
* Number of elements to be shown in queryData operation if query results
contain collections like
* Map, List etc.
*/
- private static final int queryCollectionsDepth =
TypedJson.DEFAULT_COLLECTION_ELEMENT_LIMIT;
+ private static final int queryCollectionsDepth =
+ QueryDataFunction.DEFAULT_COLLECTION_ELEMENT_LIMIT;
@Rule
public ServerStarterRule server = new ServerStarterRule().withNoCacheServer()
@@ -97,7 +98,7 @@ public class DataQueryEngineIntegrationTest {
region.put("order1", order);
String expectedResult =
-
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"items\":[\"java.util.Collection\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_1\"],\"order\":[\"org.apache.geode.management.model.Order\",\"org.apache.geode.management.model.Order\"]}],\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"I
[...]
+
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"id\":\"test\",\"items\":[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":\"Book\",\"itemId\":\"ID_1\",\"order\":\"duplicate
org.apache.geode.management.model.Order\"}],\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":\"Book\",\"itemId\":\"ID_2\",\"order\":\"duplicate
org.apache.geode.management.model.Order\"}],\"2\":[\"org.apache.geode.management.mod
[...]
Object result = queryEngine.queryForJsonResult(QUERY_1, 0,
queryResultSetLimit,
queryCollectionsDepth);
String queryResult = (String) result;
@@ -130,7 +131,7 @@ public class DataQueryEngineIntegrationTest {
queryCollectionsDepth);
String expectedResult =
-
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"items\":[\"java.util.Collection\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_1\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"items\":[\"java.util.Collection\",{}],\"id\":[\"java.lang.String\",\"ORDER_ID_1\"]}]}],\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"B
[...]
+
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"id\":\"test\",\"items\":[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":\"Book\",\"itemId\":\"ID_1\",\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":\"ORDER_ID_1\",\"items\":[\"java.util.ArrayList\",{}]}]}],\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":\"Book\",\"itemId\":\"ID_2\",\"order\":[\"org.apache.geode.management.model.Orde
[...]
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
@@ -160,7 +161,7 @@ public class DataQueryEngineIntegrationTest {
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0,
queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
-
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"items\":[\"java.util.Collection\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"java.lang.String\",\"Book\"],\"itemId\":[\"java.lang.String\",\"ID_1\"],\"order\":[\"org.apache.geode.management.model.Order\",{\"items\":[\"java.util.Collection\",\"java.util.ArrayList\"],\"id\":[\"java.lang.String\",\"ORDER_ID_1\"]}]}],\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":[\"j
[...]
+
"{\"result\":[[\"org.apache.geode.management.model.Order\",{\"id\":\"ORDER_TEST\",\"items\":[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":\"Book\",\"itemId\":\"ID_1\",\"order\":[\"org.apache.geode.management.model.Order\",{\"id\":\"ORDER_ID_1\",\"items\":[\"java.util.ArrayList\",{\"0\":\"duplicate
org.apache.geode.management.model.Item\",\"1\":[\"org.apache.geode.management.model.Item\",{\"itemDescription\":\"Book\",\"itemId\":\"
[...]
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
@@ -276,7 +277,7 @@ public class DataQueryEngineIntegrationTest {
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0,
queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
-
"{\"result\":[[\"org.apache.geode.management.model.SubOrder\",{\"items\":[\"java.util.Collection\",{}],\"id\":[\"java.lang.String\",\"null1\"]}]]}";
+
"{\"result\":[[\"org.apache.geode.management.model.SubOrder\",{\"id\":\"null1\",\"items\":[\"java.util.ArrayList\",{}]}]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
@@ -299,7 +300,7 @@ public class DataQueryEngineIntegrationTest {
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0,
queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
-
"{\"result\":[[\"org.apache.geode.pdx.PdxInstance\",{\"ID\":[\"java.lang.Integer\",111],\"status\":[\"java.lang.String\",\"active\"],\"secId\":[\"java.lang.String\",\"IBM\"]}]]}";
+
"{\"result\":[[\"org.apache.geode.pdx.internal.PdxInstanceImpl\",{\"ID\":111,\"status\":\"active\",\"secId\":\"IBM\"}]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
@@ -317,7 +318,7 @@ public class DataQueryEngineIntegrationTest {
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0,
queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
-
"{\"result\":[[\"org.apache.geode.management.model.SubOrder[]\",[{\"items\":[\"java.util.Collection\",{}],\"id\":[\"java.lang.String\",\"null1\"]},null]]]}";
+
"{\"result\":[[\"[Lorg.apache.geode.management.model.SubOrder;\",[[\"org.apache.geode.management.model.SubOrder\",{\"id\":\"null1\",\"items\":[\"java.util.ArrayList\",{}]}],null]]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
@@ -335,7 +336,7 @@ public class DataQueryEngineIntegrationTest {
String queryResult = queryEngine.queryForJsonResult(QUERY_1, 0,
queryResultSetLimit,
queryCollectionsDepth);
String expectedResult =
-
"{\"result\":[[\"org.apache.geode.management.model.SubOrder[]\",[{\"items\":[\"java.util.Collection\",{}],\"id\":[\"java.lang.String\",\"null1\"]},null]]]}";
+
"{\"result\":[[\"[Lorg.apache.geode.management.model.SubOrder;\",[[\"org.apache.geode.management.model.SubOrder\",{\"id\":\"null1\",\"items\":[\"java.util.ArrayList\",{}]}],null]]]}";
assertThat(queryResult).isEqualToIgnoringWhitespace(expectedResult);
// If not correct JSON format this will throw a JSONException
diff --git
a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/json/TypedJsonPdxIntegrationTest.java
b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterPdxIntegrationTest.java
similarity index 85%
rename from
geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/json/TypedJsonPdxIntegrationTest.java
rename to
geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterPdxIntegrationTest.java
index bead9e6..dfe9f8c 100644
---
a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/json/TypedJsonPdxIntegrationTest.java
+++
b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterPdxIntegrationTest.java
@@ -34,12 +34,12 @@ import org.apache.geode.pdx.PdxInstanceFactory;
import org.apache.geode.pdx.internal.PdxInstanceFactoryImpl;
/**
- * Integration tests for {@link TypedJson}.
+ * Integration tests for {@link QueryResultFormatter}.
* <p>
*
* TODO: add actual assertions
*/
-public class TypedJsonPdxIntegrationTest {
+public class QueryResultFormatterPdxIntegrationTest {
private static final String RESULT = "result";
@@ -71,9 +71,10 @@ public class TypedJsonPdxIntegrationTest {
pdxInstanceFactory.writeObject("object", new SerializableObject(2));
PdxInstance pdxInstance = pdxInstanceFactory.create();
- TypedJson typedJson = new TypedJson(RESULT, pdxInstance);
+ QueryResultFormatter queryResultFormatter =
+ new QueryResultFormatter(100).add(RESULT, pdxInstance);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
@@ -83,13 +84,14 @@ public class TypedJsonPdxIntegrationTest {
pdxInstanceFactory.writeString("secId", "IBM");
PdxContainer pdxContainer = new PdxContainer(pdxInstanceFactory.create(),
1);
- TypedJson typedJson = new TypedJson(RESULT, pdxContainer);
+ QueryResultFormatter queryResultFormatter =
+ new QueryResultFormatter(100).add(RESULT, pdxContainer);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
- private void checkResult(TypedJson typedJson) throws GfJsonException {
- GfJsonObject gfJsonObject = new GfJsonObject(typedJson.toString());
+ private void checkResult(QueryResultFormatter queryResultFormatter) throws
GfJsonException {
+ GfJsonObject gfJsonObject = new
GfJsonObject(queryResultFormatter.toString());
System.out.println(gfJsonObject);
assertThat(gfJsonObject.get(RESULT)).isNotNull();
}
diff --git
a/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt
b/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt
index 9886bd5..23a7c42 100644
---
a/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt
+++
b/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt
@@ -77,6 +77,7 @@ org/apache/geode/internal/tcp/VersionedByteBufferInputStream
org/apache/geode/internal/util/concurrent/StoppableReadWriteLock
org/apache/geode/management/internal/cli/commands/ShowMetricsCommand$Category
org/apache/geode/management/internal/cli/exceptions/UserErrorException
+org/apache/geode/management/internal/cli/json/QueryResultFormatter$PreventReserializationModule
org/apache/geode/security/ResourcePermission
org/apache/geode/security/ResourcePermission$Operation
org/apache/geode/security/ResourcePermission$Resource
diff --git
a/geode-core/src/main/java/org/apache/geode/management/internal/beans/DistributedSystemBridge.java
b/geode-core/src/main/java/org/apache/geode/management/internal/beans/DistributedSystemBridge.java
index ff4405f..6b0d7fb 100644
---
a/geode-core/src/main/java/org/apache/geode/management/internal/beans/DistributedSystemBridge.java
+++
b/geode-core/src/main/java/org/apache/geode/management/internal/beans/DistributedSystemBridge.java
@@ -85,7 +85,6 @@ import
org.apache.geode.management.internal.beans.stats.GatewaySenderClusterStat
import
org.apache.geode.management.internal.beans.stats.MemberClusterStatsMonitor;
import
org.apache.geode.management.internal.beans.stats.ServerClusterStatsMonitor;
import org.apache.geode.management.internal.cli.CliUtil;
-import org.apache.geode.management.internal.cli.json.TypedJson;
/**
* This is the gateway to distributed system as a whole. Aggregated metrics
and stats are shown
@@ -208,7 +207,7 @@ public class DistributedSystemBridge {
* NUmber of elements to be shown in queryData operation if query results
contain collections like
* Map, List etc.
*/
- private int queryCollectionsDepth =
TypedJson.DEFAULT_COLLECTION_ELEMENT_LIMIT;
+ private int queryCollectionsDepth =
QueryDataFunction.DEFAULT_COLLECTION_ELEMENT_LIMIT;
/**
* used to issue queries
diff --git
a/geode-core/src/main/java/org/apache/geode/management/internal/beans/QueryDataFunction.java
b/geode-core/src/main/java/org/apache/geode/management/internal/beans/QueryDataFunction.java
index 997c283..9b1fb91 100644
---
a/geode-core/src/main/java/org/apache/geode/management/internal/beans/QueryDataFunction.java
+++
b/geode-core/src/main/java/org/apache/geode/management/internal/beans/QueryDataFunction.java
@@ -43,7 +43,7 @@ import
org.apache.geode.internal.cache.PartitionedRegionHelper;
import org.apache.geode.internal.cache.execute.InternalFunction;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.management.internal.ManagementConstants;
-import org.apache.geode.management.internal.cli.json.TypedJson;
+import org.apache.geode.management.internal.cli.json.QueryResultFormatter;
/**
* This function is executed on one or multiple members based on the member
input to
@@ -56,6 +56,11 @@ public class QueryDataFunction implements Function,
InternalEntity {
private static final Logger logger = LogService.getLogger();
+ /**
+ * Limit of collection length to be serialized in JSON format.
+ */
+ public static final int DEFAULT_COLLECTION_ELEMENT_LIMIT = 100;
+
private static final String MEMBER_KEY = "member";
private static final String RESULT_KEY = "result";
private static final String NO_DATA_FOUND = "No Data Found";
@@ -113,7 +118,7 @@ public class QueryDataFunction implements Function,
InternalEntity {
queryString = applyLimitClause(queryString, limit, queryResultSetLimit);
try {
- TypedJson result = new TypedJson(queryCollectionsDepth);
+ QueryResultFormatter result = new
QueryResultFormatter(queryCollectionsDepth);
Region region = cache.getRegion(regionName);
diff --git
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/QueryResultFormatter.java
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/QueryResultFormatter.java
new file mode 100644
index 0000000..1720902
--- /dev/null
+++
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/QueryResultFormatter.java
@@ -0,0 +1,416 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license
+ * agreements. See the NOTICE file distributed with this work for additional
information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache
License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express
+ * or implied. See the License for the specific language governing permissions
and limitations under
+ * the License.
+ */
+package org.apache.geode.management.internal.cli.json;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.core.type.WritableTypeId;
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationConfig;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.query.internal.StructImpl;
+import org.apache.geode.pdx.PdxInstance;
+
+/**
+ * A JSON serializer that has special handling for collections to limit the
number of elements
+ * written to the document. It also has special handling for PdxInstance and
query Structs.
+ */
+public class QueryResultFormatter {
+
+ private final ObjectMapper mapper;
+
+ /**
+ * map contains the named objects to be serialized
+ */
+ private final Map<String, List<Object>> map;
+
+ /**
+ * serializedObjects is used to prevent recursive serialization in cases
where
+ * there are cyclical references
+ */
+ private final Map<Object, Object> serializedObjects;
+
+ /**
+ * Create a formatter that will limit collection sizes to
maxCollectionElements
+ * and will limit object traversal to being the same but in depth.
+ *
+ * @param maxCollectionElements limit on collection elements and depth-first
object traversal
+ */
+ public QueryResultFormatter(int maxCollectionElements) {
+ this(maxCollectionElements, maxCollectionElements);
+ }
+
+ /**
+ * Create a formatter that will limit collection sizes to
maxCollectionElements
+ *
+ * @param maxCollectionElements limit on collection elements
+ * @param serializationDepth when traversing objects, how deep should we go?
+ */
+ private QueryResultFormatter(int maxCollectionElements, int
serializationDepth) {
+ this.map = new LinkedHashMap<>();
+
+ this.serializedObjects = new IdentityHashMap<>();
+ this.mapper = new ObjectMapper();
+
+ SimpleModule mapperModule =
+ new PreventReserializationModule(serializedObjects,
serializationDepth);
+
+ // insert a collection serializer that limits the number of elements
generated
+ mapperModule.addSerializer(Collection.class, new
CollectionSerializer(maxCollectionElements));
+ // insert a PdxInstance serializer that knows about PDX fields/values
+ mapperModule.addSerializer(PdxInstance.class, new PdxInstanceSerializer());
+ // insert a Struct serializer that knows about its format
+ mapperModule.addSerializer(StructImpl.class, new StructSerializer());
+ // insert a RegionEntry serializer because they're too messy looking
+ mapperModule.addSerializer(Region.Entry.class, new
RegionEntrySerializer());
+
+ mapper.registerModule(mapperModule);
+
+ // allow objects with no content
+ mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+ // use toString on Enums
+ mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
+ // sort fields alphabetically
+ mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
+ // add type information (Jackson has no way to force it to do this for all
values)
+ mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+
+ }
+
+ /**
+ * After instantiating a formatter add the objects you want to be formatted
+ * using this method. Typically this will be add("result", queryResult)
+ */
+ public synchronized QueryResultFormatter add(String key, Object value) {
+ List<Object> list = this.map.get(key);
+ if (list != null) {
+ list.add(value);
+ } else {
+ list = new ArrayList<>();
+ if (value != null) {
+ list.add(value);
+ }
+ this.map.put(key, list);
+ }
+ return this;
+ }
+
+ /* non-javadoc use Jackson to serialize added objects into JSON format */
+ @Override
+ public synchronized String toString() {
+ Writer writer = new StringWriter();
+ try {
+ boolean addComma = false;
+ writer.write('{');
+ for (Map.Entry<String, List<Object>> entry : this.map.entrySet()) {
+ if (addComma) {
+ writer.write(',');
+ }
+ mapper.writerFor(entry.getKey().getClass()).writeValue(writer,
entry.getKey());
+ writer.write(':');
+ writeList(writer, entry.getValue());
+ addComma = true;
+ }
+ writer.write('}');
+
+ return writer.toString();
+ } catch (IOException exception) {
+ new GfJsonException(exception).printStackTrace();
+ } catch (GfJsonException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ private Writer writeList(Writer writer, List<Object> values) throws
GfJsonException {
+ // for each object we clear out the serializedObjects recursion map so that
+ // we don't immediately see "duplicate" entries
+ serializedObjects.clear();
+ try {
+ boolean addComma = false;
+ int length = values.size();
+ writer.write('[');
+
+ if (length == 0) {
+ mapper.writeValue(writer, null);
+ } else {
+ for (int i = 0; i < length; i += 1) {
+ if (addComma) {
+ writer.write(',');
+ }
+ mapper.writerFor(values.get(i).getClass()).writeValue(writer,
values.get(i));
+
+ addComma = true;
+ }
+ }
+ writer.write(']');
+ } catch (IOException e) {
+ throw new GfJsonException(e);
+ }
+ return writer;
+ }
+
+
+ private static class PreventReserializationSerializer extends JsonSerializer
{
+
+ private JsonSerializer defaultSerializer;
+ Map<Object, Object> serializedObjects;
+ private final int serializationDepth;
+ int depth;
+
+ PreventReserializationSerializer(JsonSerializer serializer, Map
serializedObjects,
+ int serializationDepth) {
+ defaultSerializer = serializer;
+ this.serializedObjects = serializedObjects;
+ this.serializationDepth = serializationDepth;
+ }
+
+ boolean isPrimitiveOrWrapper(Class<?> klass) {
+ return klass.isAssignableFrom(Byte.class) ||
klass.isAssignableFrom(byte.class)
+ || klass.isAssignableFrom(Short.class) ||
klass.isAssignableFrom(short.class)
+ || klass.isAssignableFrom(Integer.class) ||
klass.isAssignableFrom(int.class)
+ || klass.isAssignableFrom(Long.class) ||
klass.isAssignableFrom(long.class)
+ || klass.isAssignableFrom(Float.class) ||
klass.isAssignableFrom(float.class)
+ || klass.isAssignableFrom(Double.class) ||
klass.isAssignableFrom(double.class)
+ || klass.isAssignableFrom(Boolean.class) ||
klass.isAssignableFrom(boolean.class)
+ || klass.isAssignableFrom(String.class) ||
klass.isAssignableFrom(char.class)
+ || klass.isAssignableFrom(Character.class) ||
klass.isAssignableFrom(java.sql.Date.class)
+ || klass.isAssignableFrom(java.util.Date.class)
+ || klass.isAssignableFrom(java.math.BigDecimal.class);
+ }
+
+ @Override
+ public void serializeWithType(Object value, JsonGenerator gen,
+ SerializerProvider serializers, TypeSerializer typeSer)
+ throws IOException {
+ if (value == null || isPrimitiveOrWrapper(value.getClass())) {
+ defaultSerializer.serializeWithType(value, gen, serializers, typeSer);
+ return;
+ }
+ depth += 1;
+ try {
+ if (depth > serializationDepth) {
+ gen.writeString("{}");
+ } else if (serializedObjects.containsKey(value)) {
+ gen.writeString("duplicate " + value.getClass().getName());
+ } else {
+ serializedObjects.put(value, value);
+ defaultSerializer.serializeWithType(value, gen, serializers,
typeSer);
+ }
+ } finally {
+ depth--;
+ }
+ }
+
+ @Override
+ public void serialize(Object value, JsonGenerator gen, SerializerProvider
serializers)
+ throws IOException {
+ if (value == null || isPrimitiveOrWrapper(value.getClass())) {
+ defaultSerializer.serialize(value, gen, serializers);
+ return;
+ }
+ if (serializedObjects.containsKey(value)) {
+ gen.writeStartObject(value);
+ gen.writeFieldName("duplicate");
+ gen.writeString("reference@" +
Integer.toHexString(System.identityHashCode(value)));
+ gen.writeEndObject();
+ } else {
+ serializedObjects.put(value, value);
+ defaultSerializer.serialize(value, gen, serializers);
+ }
+ }
+ }
+
+
+ private static class CollectionSerializer extends JsonSerializer<Collection>
{
+ private final int maxCollectionElements;
+
+ public CollectionSerializer(int maxCollectionElements) {
+ this.maxCollectionElements = maxCollectionElements;
+ }
+
+ @Override
+ public void serializeWithType(Collection value, JsonGenerator gen,
+ SerializerProvider serializers, TypeSerializer typeSer)
+ throws IOException {
+ gen.setCurrentValue(value);
+ WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen,
+ typeSer.typeId(value, JsonToken.START_OBJECT));
+ _serialize(value, gen);
+ typeSer.writeTypeSuffix(gen, typeIdDef);
+ }
+
+ @Override
+ public void serialize(Collection value, JsonGenerator gen,
SerializerProvider serializers)
+ throws IOException {
+ gen.writeStartObject();
+ _serialize(value, gen);
+ gen.writeEndObject();
+ }
+
+ void _serialize(Collection value, JsonGenerator gen) throws IOException {
+ Iterator<Object> objects = value.iterator();
+ for (int i = 0; i < maxCollectionElements && objects.hasNext(); i++) {
+ Object nextObject = objects.next();
+ gen.writeObjectField("" + i, nextObject);
+ }
+ }
+
+ @Override
+ public Class<Collection> handledType() {
+ return Collection.class;
+ }
+ }
+
+
+ private static class PdxInstanceSerializer extends
JsonSerializer<PdxInstance> {
+ @Override
+ public void serializeWithType(PdxInstance value, JsonGenerator gen,
+ SerializerProvider serializers, TypeSerializer typeSer)
+ throws IOException {
+ WritableTypeId writableTypeId = typeSer.typeId(value,
JsonToken.START_OBJECT);
+ typeSer.writeTypePrefix(gen, writableTypeId);
+ _serialize(value, gen);
+ typeSer.writeTypeSuffix(gen, writableTypeId);
+ }
+
+ @Override
+ public void serialize(PdxInstance value, JsonGenerator gen,
SerializerProvider serializers)
+ throws IOException {
+ gen.writeStartObject();
+ _serialize(value, gen);
+ gen.writeEndObject();
+ }
+
+ void _serialize(PdxInstance value, JsonGenerator gen) throws IOException {
+ for (String field : value.getFieldNames()) {
+ gen.writeObjectField(field, value.getField(field));
+ }
+ }
+
+ @Override
+ public Class<PdxInstance> handledType() {
+ return PdxInstance.class;
+ }
+ }
+
+ private static class StructSerializer extends JsonSerializer<StructImpl> {
+ @Override
+ public void serializeWithType(StructImpl value, JsonGenerator gen,
+ SerializerProvider serializers, TypeSerializer typeSer)
+ throws IOException {
+ typeSer.writeTypePrefix(gen, typeSer.typeId(value,
JsonToken.START_OBJECT));
+ _serialize(value, gen);
+ typeSer.writeTypeSuffix(gen, typeSer.typeId(value,
JsonToken.START_OBJECT));
+ }
+
+ @Override
+ public void serialize(StructImpl value, JsonGenerator gen,
SerializerProvider serializers)
+ throws IOException {
+ gen.writeStartObject();
+ _serialize(value, gen);
+ gen.writeEndObject();
+ }
+
+ void _serialize(StructImpl value, JsonGenerator gen) throws IOException {
+ String[] fields = value.getFieldNames();
+ Object[] values = value.getFieldValues();
+ for (int i = 0; i < fields.length; i++) {
+ gen.writeObjectField(fields[i], values[i]);
+ }
+ }
+
+ @Override
+ public Class<StructImpl> handledType() {
+ return StructImpl.class;
+ }
+ }
+
+ private static class RegionEntrySerializer extends
JsonSerializer<Region.Entry> {
+ @Override
+ public void serializeWithType(Region.Entry value, JsonGenerator gen,
+ SerializerProvider serializers, TypeSerializer typeSer)
+ throws IOException {
+ typeSer.writeTypePrefix(gen, typeSer.typeId(value,
JsonToken.START_OBJECT));
+ gen.writeObjectField(value.getKey().toString(), value.getValue());
+ typeSer.writeTypeSuffix(gen, typeSer.typeId(value,
JsonToken.START_OBJECT));
+ }
+
+ @Override
+ public void serialize(Region.Entry value, JsonGenerator gen,
SerializerProvider serializers)
+ throws IOException {
+ gen.writeStartObject();
+ gen.writeObjectField(value.getKey().toString(), value.getValue());
+ gen.writeEndObject();
+ }
+
+ @Override
+ public Class<Region.Entry> handledType() {
+ return Region.Entry.class;
+ }
+ }
+
+ /**
+ * A Jackson module that installs a serializer-modifier to detect and prevent
+ * reserialization of objects that have already been serialized. W/o this
+ * Jackson would throw infinite-recursion exceptions.
+ */
+ private static class PreventReserializationModule extends SimpleModule {
+ private final Map<Object, Object> serializedObjects;
+ private final int serializationDepth;
+
+ PreventReserializationModule(Map<Object, Object> serializedObjects, int
serializationDepth) {
+ this.serializedObjects = serializedObjects;
+ this.serializationDepth = serializationDepth;
+ }
+
+ @Override
+ public void setupModule(SetupContext context) {
+ // install a modifier that prevents recursive serialization in cases
where
+ // there are cyclical references
+ super.setupModule(context);
+ context.addBeanSerializerModifier(new BeanSerializerModifier() {
+ @Override
+ public JsonSerializer<?> modifySerializer(
+ SerializationConfig config, BeanDescription desc,
JsonSerializer<?> serializer) {
+ return new PreventReserializationSerializer(serializer,
serializedObjects,
+ serializationDepth);
+ }
+ });
+ }
+
+ }
+}
diff --git
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/TypedJson.java
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/TypedJson.java
deleted file mode 100644
index 5e64d33..0000000
---
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/TypedJson.java
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license
- * agreements. See the NOTICE file distributed with this work for additional
information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache
License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express
- * or implied. See the License for the specific language governing permissions
and limitations under
- * the License.
- */
-package org.apache.geode.management.internal.cli.json;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.geode.cache.Region;
-import org.apache.geode.cache.query.Struct;
-import org.apache.geode.cache.query.internal.StructImpl;
-import org.apache.geode.pdx.PdxInstance;
-
-/**
- * A limited functionality JSON parser. Its a DSF based JSON parser. It does
not create Object maps
- * and serialize them like JSONObject. It just traverses an Object graph in
depth first search
- * manner and appends key values to a String writer. Hence we prevent creating
a lot of garbage.
- *
- * Although it has limited functionality,still a simple use of add() method
should suffice for most
- * of the simple JSON use cases.
- */
-public class TypedJson {
-
- /**
- * Limit of collection length to be serialized in JSON format.
- */
- public static final int DEFAULT_COLLECTION_ELEMENT_LIMIT = 100;
-
- public static final Object NULL = GfJsonObject.NULL;
-
- /**
- * If Integer of Float is NAN
- */
- static final String NONFINITE = "Non-Finite";
-
- Map<Object, List<Object>> forbidden = new java.util.IdentityHashMap<Object,
List<Object>>();
-
- boolean commanate;
-
- private Map<String, List<Object>> map;
-
- private int queryCollectionsDepth;
-
- public TypedJson(String key, Object value, int queryCollectionsDepth) {
- List<Object> list = new ArrayList<Object>();
- this.map = new LinkedHashMap<String, List<Object>>();
- if (value != null) {
- list.add(value);
- }
- this.map.put(key, list);
- this.queryCollectionsDepth = queryCollectionsDepth;
- }
-
- public TypedJson(int queryCollectionsDepth) {
- this.map = new LinkedHashMap<String, List<Object>>();
- this.queryCollectionsDepth = queryCollectionsDepth;
- }
-
- public TypedJson() {
- this.map = new LinkedHashMap<String, List<Object>>();
- this.queryCollectionsDepth = DEFAULT_COLLECTION_ELEMENT_LIMIT;
- }
-
- public TypedJson(String key, Object value) {
- List<Object> list = new ArrayList<Object>();
- this.map = new LinkedHashMap<String, List<Object>>();
- if (value != null) {
- list.add(value);
- }
- this.map.put(key, list);
- this.queryCollectionsDepth = DEFAULT_COLLECTION_ELEMENT_LIMIT;
- }
-
- void bfs(Writer w, Object root) throws IOException {
- if (root == null || isPrimitiveOrWrapper(root.getClass())) {
- return;
- }
- LinkedList<Object> queue = new LinkedList<Object>();
- Map seen = new java.util.IdentityHashMap();
-
- seen.put(root, null);
-
- // Adds to end of queue
- queue.addFirst(root);
-
- while (!queue.isEmpty()) {
-
- // removes from front of queue
- Object r = queue.pollFirst();
- List<Object> childrens = getChildrens(w, r);
- // Visit child first before grand child
- for (Object n : childrens) {
-
- if (n == null) {
- continue;
- }
- if (!isPrimitiveOrWrapper(n.getClass())) {
- if (!seen.containsKey(n)) {
- queue.addFirst(n);
- seen.put(n, null);
- } else {
- List<Object> list = forbidden.get(r);
- if (list != null) {
- list.add(n);
- forbidden.put(r, list);
- } else {
- List<Object> newList = new ArrayList<Object>();
- newList.add(n);
- forbidden.put(r, newList);
- }
-
- }
- }
- }
- }
- }
-
- List<Object> getChildrens(Writer w, Object object) throws IOException {
- if (isSpecialObject(object)) {
- return this.visitSpecialObjects(w, object, false);
- } else {
- return this.visitChildrens(w, object, false);
- }
- }
-
- /**
- * User can build on this object by adding Objects against a key.
- *
- * TypedJson result = new TypedJson(); result.add(KEY,object); If users add
more objects against
- * the same key the newly added object will be appended to the existing key
forming an array of
- * objects.
- *
- * If the KEY is a new one then it will be a key map value.
- *
- * @param key Key against which an object will be added
- * @param value Object to be added
- * @return TypedJson object
- */
- public TypedJson add(String key, Object value) {
- List<Object> list = this.map.get(key);
- if (list != null) {
- list.add(value);
- } else {
- list = new ArrayList<Object>();
- list.add(value);
- this.map.put(key, list);
- }
- return this;
- }
-
- public String toString() {
- StringWriter w = new StringWriter();
- synchronized (w.getBuffer()) {
- try {
- return this.write(w).toString();
- } catch (Exception e) {
- return null;
- }
- }
- }
-
- public int length() {
- return this.map.size();
- }
-
- Writer write(Writer writer) throws GfJsonException {
- try {
- boolean addComma = false;
- final int length = this.length();
- Iterator<String> keys = map.keySet().iterator();
- writer.write('{');
-
- if (length == 1) {
- Object key = keys.next();
- writer.write(quote(key.toString()));
- writer.write(':');
-
- writeList(writer, this.map.get(key));
- } else if (length != 0) {
- while (keys.hasNext()) {
- Object key = keys.next();
- if (addComma) {
- writer.write(',');
- }
- writer.write(quote(key.toString()));
- writer.write(':');
-
- writeList(writer, this.map.get(key));
- commanate = false;
- addComma = true;
- }
- }
-
- writer.write('}');
-
- return writer;
- } catch (IOException exception) {
- throw new GfJsonException(exception);
- }
- }
-
- Writer writeList(Writer writer, List<Object> myArrayList) throws
GfJsonException {
- try {
- boolean addComma = false;
- int length = myArrayList.size();
-
- if (length == 0) {
- writer.write(']');
- writeValue(writer, null);
- writer.write(']');
- }
- if (length == 1) {
- writer.write('[');
- writeValue(writer, myArrayList.get(0));
- writer.write(']');
-
- } else if (length != 0) {
- writer.write('[');
- for (int i = 0; i < length; i += 1) {
- if (addComma) {
- writer.write(',');
- }
- writeValue(writer, myArrayList.get(i));
- commanate = false;
- addComma = true;
- }
- writer.write(']');
- }
-
- return writer;
- } catch (IOException e) {
- throw new GfJsonException(e);
- }
- }
-
- static String quote(String string) {
- StringWriter sw = new StringWriter();
- synchronized (sw.getBuffer()) {
- try {
- return quote(string, sw).toString();
- } catch (IOException ignored) {
- // will never happen - we are writing to a string writer
- return "";
- }
- }
- }
-
- static boolean shouldVisitChildren(Object object) {
- Class type = object.getClass();
- if (isPrimitiveOrWrapper(type)) {
- return false;
- }
- if (isSpecialObject(object)) {
- return false;
- }
- return true;
- }
-
- static boolean isPrimitiveOrWrapper(Class<?> klass) {
- return klass.isAssignableFrom(Byte.class) ||
klass.isAssignableFrom(byte.class)
- || klass.isAssignableFrom(Short.class) ||
klass.isAssignableFrom(short.class)
- || klass.isAssignableFrom(Integer.class) ||
klass.isAssignableFrom(int.class)
- || klass.isAssignableFrom(Long.class) ||
klass.isAssignableFrom(long.class)
- || klass.isAssignableFrom(Float.class) ||
klass.isAssignableFrom(float.class)
- || klass.isAssignableFrom(Double.class) ||
klass.isAssignableFrom(double.class)
- || klass.isAssignableFrom(Boolean.class) ||
klass.isAssignableFrom(boolean.class)
- || klass.isAssignableFrom(String.class) ||
klass.isAssignableFrom(char.class)
- || klass.isAssignableFrom(Character.class) ||
klass.isAssignableFrom(java.sql.Date.class)
- || klass.isAssignableFrom(java.util.Date.class)
- || klass.isAssignableFrom(java.math.BigDecimal.class);
- }
-
- static boolean isSpecialObject(Object object) {
- Class type = object.getClass();
- if (type.isArray() || type.isEnum()) {
- return true;
- }
- if ((object instanceof Collection) || (object instanceof Map) || (object
instanceof PdxInstance)
- || (object instanceof Struct) || (object instanceof Region.Entry)) {
- return true;
- }
- return false;
- }
-
- void writeVal(Writer w, Object value) throws IOException {
- w.write('{');
- addVal(w, value);
- w.write('}');
- }
-
- void addVal(Writer w, Object object) {
- if (object == null) {
- return;
- }
- if (shouldVisitChildren(object)) {
- visitChildrens(w, object, true);
- }
- }
-
- void writeKeyValue(Writer w, Object key, Object value, Class type) throws
IOException {
- if (commanate) {
- w.write(",");
- }
-
- if (value == null || value.equals(null)) {
- w.write(quote(key.toString()));
- w.write(':');
- w.write("null");
- commanate = true;
- return;
- }
- Class clazz = value.getClass();
- w.write(quote(key.toString()));
- w.write(':');
-
- if (type != null) {
- writeType(w, type, value);
- }
-
- if (isPrimitiveOrWrapper(clazz)) {
- writePrimitives(w, value);
- commanate = true;
- } else if (isSpecialObject(value)) {
- commanate = false;
- visitSpecialObjects(w, value, true);
- commanate = true;
- } else {
- commanate = false;
- writeVal(w, value);
- commanate = true;
- }
- endType(w, clazz);
- return;
- }
-
- void writePrimitives(Writer w, Object value) throws IOException {
- if (value instanceof Number) {
- w.write(numberToString((Number) value));
- return;
- }
-
- if (value instanceof String || value instanceof Character || value
instanceof java.sql.Date
- || value instanceof java.util.Date) {
- w.write(quote(value.toString()));
- return;
- }
- w.write(value.toString());
- }
-
- void writeArray(Writer w, Object object) throws IOException {
- if (commanate) {
- w.write(",");
- }
- w.write('[');
- int length = Array.getLength(object);
- int elements = 0;
- for (int i = 0; i < length && elements < queryCollectionsDepth; i += 1) {
- Object item = Array.get(object, i);
- if (i != 0) {
- w.write(",");
- }
- if (item != null) {
- Class clazz = item.getClass();
-
- if (isPrimitiveOrWrapper(clazz)) {
- writePrimitives(w, item);
- } else if (isSpecialObject(item)) {
- visitSpecialObjects(w, item, true);
- } else {
- writeVal(w, item);
- }
- } else {
- w.write("null");
- }
- elements++;
- commanate = false;
- }
- w.write(']');
- commanate = true;
- return;
- }
-
- List<Object> getArrayChildren(Object object) {
- List<Object> items = new ArrayList<Object>();
- int length = Array.getLength(object);
- int elements = 0;
- for (int i = 0; i < length && elements < queryCollectionsDepth; i += 1) {
- Object item = Array.get(object, i);
- items.add(item);
- }
- return items;
- }
-
- void writeEnum(Writer w, Object object) throws IOException {
- if (commanate) {
- w.write(",");
- }
- w.write(quote(object.toString()));
- commanate = true;
- return;
- }
-
- void writeTypedJson(Writer w, TypedJson object) throws IOException {
-
- if (commanate) {
- w.write(",");
- }
- w.write(quote(object.toString()));
- commanate = true;
- return;
- }
-
- void writeValue(Writer w, Object value) {
- try {
- if (value == null || value.equals(null)) {
- w.write("null");
- return;
- }
- this.bfs(w, value);
- Class rootClazz = value.getClass();
- writeType(w, rootClazz, value);
-
- if (isPrimitiveOrWrapper(rootClazz)) {
- writePrimitives(w, value);
- } else if (isSpecialObject(value)) {
- visitSpecialObjects(w, value, true);
- } else {
- writeVal(w, value);
- }
- endType(w, rootClazz);
- } catch (IOException e) {
- }
- }
-
- void startKey(Writer writer, String key) throws IOException {
- if (key != null) {
- writer.write('{');
- writer.write(quote(key.toString()));
- writer.write(':');
- }
- }
-
- void endKey(Writer writer, String key) throws IOException {
- if (key != null) {
- writer.write('}');
- }
- }
-
- List<Object> visitSpecialObjects(Writer w, Object object, boolean write)
throws IOException {
-
- List<Object> elements = new ArrayList<Object>();
-
- Class clazz = object.getClass();
-
- if (clazz.isArray()) {
- if (write) {
- writeArray(w, object);
- } else {
- return getArrayChildren(object);
- }
- }
-
- if (clazz.isEnum()) {
- if (write) {
- writeEnum(w, object);
- } else {
- elements.add(object);
- }
- return elements;
- }
-
- if (object instanceof TypedJson) {
- this.writeTypedJson(w, (TypedJson) object);
- return elements;
- }
-
- if (object instanceof Collection) {
- Collection collection = (Collection) object;
- Iterator iter = collection.iterator();
- int i = 0;
- if (write)
- w.write('{');
- while (iter.hasNext() && i < queryCollectionsDepth) {
- Object item = iter.next();
- if (write) {
- writeKeyValue(w, i, item, item != null ? item.getClass() : null);
- } else {
- elements.add(item);
- }
-
- i++;
- }
- if (write)
- w.write('}');
- return elements;
- }
-
- if (object instanceof Map) {
- Map map = (Map) object;
- Iterator it = map.entrySet().iterator();
- int i = 0;
- if (write)
- w.write('{');
- while (it.hasNext() && i < queryCollectionsDepth) {
- Map.Entry e = (Map.Entry) it.next();
- Object value = e.getValue();
- if (write) {
- writeKeyValue(w, e.getKey(), value, value != null ? value.getClass()
: null);
- } else {
- elements.add(value);
- }
-
- i++;
- }
- if (write)
- w.write('}');
- return elements;
- }
-
- if (object instanceof PdxInstance) {
- PdxInstance pdxInstance = (PdxInstance) object;
- if (write)
- w.write('{');
- for (String field : pdxInstance.getFieldNames()) {
- Object fieldValue = pdxInstance.getField(field);
- if (write) {
- writeKeyValue(w, field, fieldValue, fieldValue != null ?
fieldValue.getClass() : null);
- } else {
- elements.add(fieldValue);
- }
- }
- if (write)
- w.write('}');
- return elements;
- }
-
- if (object instanceof Struct) {
- StructImpl impl = (StructImpl) object;
- String fields[] = impl.getFieldNames();
- Object[] values = impl.getFieldValues();
-
- if (write)
- w.write('{');
- for (int i = 0; i < fields.length; i++) {
- Object fieldValue = values[i];
- if (write) {
- writeKeyValue(w, fields[i], fieldValue,
- fieldValue != null ? fieldValue.getClass() : null);
- } else {
- elements.add(fieldValue);
- }
-
- }
- if (write)
- w.write('}');
- return elements;
- }
-
- if (object instanceof Region.Entry) {
- Region.Entry entry = (Region.Entry) object;
- Object key = entry.getKey();
- Object value = entry.getValue();
-
-
- if (write) {
- w.write('{');
- writeKeyValue(w, key, value, value != null ? value.getClass() : null);
- w.write('}');
- } else {
- elements.add(value);
- }
-
- return elements;
- }
-
- return elements;
- }
-
- void writeType(Writer w, Class clazz, Object value) throws IOException {
- if (clazz != TypedJson.class) {
- w.write('[');
- w.write(quote(internalToExternal(clazz, value)));
- w.write(",");
- }
- }
-
- /**
- * Handle some special GemFire classes. We don't want to expose some of the
internal classes.
- * Hence corresponding interface or external classes should be shown.
- */
- String internalToExternal(Class clazz, Object value) {
- if (value != null && value instanceof Region.Entry) {
- return Region.Entry.class.getCanonicalName();
- }
- if (value != null && value instanceof PdxInstance) {
- return PdxInstance.class.getCanonicalName();
- }
- return clazz.getCanonicalName();
- }
-
- void endType(Writer w, Class clazz) throws IOException {
- if (clazz != TypedJson.class) {
- w.write(']');
- }
-
- }
-
- List<Object> visitChildrens(Writer w, Object object, boolean write) {
-
- List<Object> elements = new ArrayList<Object>();
-
- Method[] methods = getMethods(object);
-
- for (int i = 0; i < methods.length; i += 1) {
- try {
- Method method = methods[i];
- if (Modifier.isPublic(method.getModifiers()) &&
!Modifier.isStatic(method.getModifiers())) {
- String name = method.getName();
- String key = "";
- if (name.startsWith("get")) {
- if ("getClass".equals(name) || "getDeclaringClass".equals(name)) {
- key = "";
- } else {
- key = name.substring(3);
- }
- } else if (name.startsWith("is")) {
- key = name.substring(2);
- }
- if (key.length() > 0 && Character.isUpperCase(key.charAt(0))
- && method.getParameterTypes().length == 0) {
- if (key.length() == 1) {
- key = key.toLowerCase();
- } else if (!Character.isUpperCase(key.charAt(1))) {
- key = key.substring(0, 1).toLowerCase() + key.substring(1);
- }
- method.setAccessible(true);
- Object result = method.invoke(object, (Object[]) null);
- if (write) {
- List<Object> forbiddenList = forbidden.get(object);
- if (forbiddenList != null && forbiddenList.contains(result)) {
- writeKeyValue(w, key, result.getClass().getCanonicalName(),
method.getReturnType());
- } else {
- writeKeyValue(w, key, result, method.getReturnType());
- }
- } else {
- elements.add(result);
- }
-
-
- }
- }
- } catch (Exception ignore) {
- }
- }
- return elements;
- }
-
-
- /**
- * This method returns method declared in a Class as well as all the super
classes in the
- * hierarchy. If class is a system class it wont include super class methods
- */
- Method[] getMethods(Object object) {
- Class klass = object.getClass();
-
- // If klass is a System class then set includeSuperClass to false.
-
- boolean includeSuperClass = klass.getClassLoader() != null;
-
- Method[] decMethods = klass.getDeclaredMethods();
- Map<String, Method> decMethodMap = new HashMap<String, Method>();
- for (Method method : decMethods) {
- decMethodMap.put(method.getName(), method);
- }
-
- if (includeSuperClass) {
- Method[] allMethods = klass.getMethods();
- List<Method> allMethodList = Arrays.asList(allMethods);
- for (Method method : allMethodList) {
- if (decMethodMap.get(method.getName()) != null) {
- // skip. This will ensure overriden methods wont be added again.
- } else {
- decMethodMap.put(method.getName(), method);
- }
- }
- }
-
- Method[] methodArr = new Method[decMethodMap.size()];
- return decMethodMap.values().toArray(methodArr);
- }
-
-
- /**
- * Produce a string from a Number.
- *
- * @param number A Number
- * @return A String.
- */
- public static String numberToString(Number number) {
- if (number == null) {
- return "";
- }
- if (number instanceof Double) {
- if (((Double) number).isInfinite() || ((Double) number).isNaN()) {
- return "Non-Finite";
- }
- } else if (number instanceof Float) {
- if (((Float) number).isInfinite() || ((Float) number).isNaN()) {
- return "Non-Finite";
- }
- }
-
- // Shave off trailing zeros and decimal point, if possible.
-
- String string = number.toString();
- if (string.indexOf('.') > 0 && string.indexOf('e') < 0 &&
string.indexOf('E') < 0) {
- while (string.endsWith("0")) {
- string = string.substring(0, string.length() - 1);
- }
- if (string.endsWith(".")) {
- string = string.substring(0, string.length() - 1);
- }
- }
- return string;
- }
-
- public static Writer quote(String string, Writer w) throws IOException {
- if (string == null || string.length() == 0) {
- w.write("\"\"");
- return w;
- }
-
- char b;
- char c = 0;
- String hhhh;
- int i;
- int len = string.length();
-
- w.write('"');
- for (i = 0; i < len; i += 1) {
- b = c;
- c = string.charAt(i);
- switch (c) {
- case '\\':
- case '"':
- w.write('\\');
- w.write(c);
- break;
- case '/':
- if (b == '<') {
- w.write('\\');
- }
- w.write(c);
- break;
- case '\b':
- w.write("\\b");
- break;
- case '\t':
- w.write("\\t");
- break;
- case '\n':
- w.write("\\n");
- break;
- case '\f':
- w.write("\\f");
- break;
- case '\r':
- w.write("\\r");
- break;
- default:
- if (c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' &&
c < '\u2100')) {
- hhhh = "000" + Integer.toHexString(c);
- w.write("\\u" + hhhh.substring(hhhh.length() - 4));
- } else {
- w.write(c);
- }
- }
- }
- w.write('"');
- return w;
- }
-}
diff --git
a/geode-core/src/main/java/org/apache/geode/pdx/internal/json/PdxToJSON.java
b/geode-core/src/main/java/org/apache/geode/pdx/internal/json/PdxToJSON.java
index b1305dc..ea7b7fa 100644
--- a/geode-core/src/main/java/org/apache/geode/pdx/internal/json/PdxToJSON.java
+++ b/geode-core/src/main/java/org/apache/geode/pdx/internal/json/PdxToJSON.java
@@ -52,7 +52,6 @@ public class PdxToJSON {
public String getJSON() {
JsonFactory jf = new JsonFactory();
- // OutputStream os = new ByteArrayOutputStream();
HeapDataOutputStream hdos = new
HeapDataOutputStream(org.apache.geode.internal.Version.CURRENT);
try {
JsonGenerator jg = jf.createJsonGenerator(hdos, JsonEncoding.UTF8);
@@ -155,7 +154,7 @@ public class PdxToJSON {
jg.writeStartObject();
- Iterator iter = (Iterator) map.entrySet().iterator();
+ Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
@@ -227,21 +226,10 @@ public class PdxToJSON {
jg.writeEndArray();
} else {
throw new IllegalStateException(
- "PdxInstance returns unknwon pdxfield " + pf + " for type " + value);
+ "PdxInstance returns unknown pdxfield " + pf + " for type " + value);
}
}
- private <T> void getJSONStringFromArray1(JsonGenerator jg, T[] array, String
pf)
- throws JsonGenerationException, IOException {
- jg.writeStartArray();
-
- for (T obj : array) {
- writeValue(jg, obj, pf);
- }
- jg.writeEndArray();
- }
-
-
private void getJSONStringFromCollection(JsonGenerator jg, Collection<?>
coll, String pf)
throws JsonGenerationException, IOException {
jg.writeStartArray();
diff --git
a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
index 25aee89..4d46693 100644
---
a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
+++
b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
@@ -837,4 +837,4 @@
org/apache/geode/redis/internal/executor/sortedset/GeoRadiusParameters$SortOrder
org/apache/geode/security/AuthenticationFailedException,true,-8202866472279088879
org/apache/geode/security/AuthenticationRequiredException,true,4675976651103154919
org/apache/geode/security/GemFireSecurityException,true,3814254578203076926,cause:java/lang/Throwable
-org/apache/geode/security/NotAuthorizedException,true,419215768216387745,principal:java/security/Principal
\ No newline at end of file
+org/apache/geode/security/NotAuthorizedException,true,419215768216387745,principal:java/security/Principal
diff --git
a/geode-core/src/test/java/org/apache/geode/management/internal/cli/json/TypedJsonTest.java
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterTest.java
similarity index 61%
rename from
geode-core/src/test/java/org/apache/geode/management/internal/cli/json/TypedJsonTest.java
rename to
geode-core/src/test/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterTest.java
index 625cc26..888fa0f 100644
---
a/geode-core/src/test/java/org/apache/geode/management/internal/cli/json/TypedJsonTest.java
+++
b/geode-core/src/test/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterTest.java
@@ -19,7 +19,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import java.io.Writer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
@@ -29,25 +28,18 @@ import java.util.Map;
import org.junit.Test;
-/**
- * Extracted from {@link TypedJsonPdxIntegrationTest}.
- * <p>
- *
- * TODO: add actual assertions
- */
-public class TypedJsonTest {
+public class QueryResultFormatterTest {
private static final String RESULT = "result";
@Test
public void canBeMocked() throws Exception {
- TypedJson mockTypedJson = mock(TypedJson.class);
- Writer writer = null;
+ QueryResultFormatter mockQueryResultFormatter =
mock(QueryResultFormatter.class);
Object value = new Object();
- mockTypedJson.writeVal(writer, value);
+ mockQueryResultFormatter.add("key", value);
- verify(mockTypedJson, times(1)).writeVal(writer, value);
+ verify(mockQueryResultFormatter, times(1)).add("key", value);
}
@Test
@@ -57,9 +49,9 @@ public class TypedJsonTest {
list.add("TWO");
list.add("THREE");
- TypedJson typedJson = new TypedJson(RESULT, list);
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, list);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
@@ -69,9 +61,9 @@ public class TypedJsonTest {
intArray[i] = i;
}
- TypedJson typedJson = new TypedJson(RESULT, intArray);
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, intArray);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
@@ -81,25 +73,27 @@ public class TypedJsonTest {
list.add("BIG_COLL_" + i);
}
- TypedJson typedJson = new TypedJson(RESULT, list);
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, list);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
public void testEnumContainer() throws Exception {
EnumContainer enumContainer = new EnumContainer(Currency.DIME);
- TypedJson typedJson = new TypedJson(RESULT, enumContainer);
+ QueryResultFormatter queryResultFormatter =
+ new QueryResultFormatter(100).add(RESULT, enumContainer);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
public void testEnum() throws Exception {
- TypedJson typedJson = new TypedJson(RESULT, Currency.DIME);
+ QueryResultFormatter queryResultFormatter =
+ new QueryResultFormatter(100).add(RESULT, Currency.DIME);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
@@ -110,9 +104,9 @@ public class TypedJsonTest {
list.add(Currency.QUARTER);
list.add(Currency.NICKLE);
- TypedJson typedJson = new TypedJson(RESULT, list);
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, list);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
@@ -123,38 +117,40 @@ public class TypedJsonTest {
map.put("3", "THREE");
map.put("4", "FOUR");
- TypedJson typedJson = new TypedJson(RESULT, map);
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, map);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
public void testBigDecimal() throws Exception {
BigDecimal dc = new BigDecimal(20);
- TypedJson typedJson = new TypedJson(RESULT, dc);
+ QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, dc);
- checkResult(typedJson);
+ checkResult(queryResultFormatter);
}
@Test
public void testObjects() throws Exception {
Object object = new Object();
- TypedJson typedJson = new TypedJson(RESULT, object);
-
- checkResult(typedJson);
+ QueryResultFormatter queryResultFormatter = new QueryResultFormatter(100);
+ queryResultFormatter.add(RESULT, object);
+ checkResult(queryResultFormatter);
}
- private void checkResult(final TypedJson typedJson) throws GfJsonException {
- GfJsonObject gfJsonObject = new GfJsonObject(typedJson.toString());
- System.out.println(gfJsonObject);
+ private void checkResult(final QueryResultFormatter queryResultFormatter)
throws GfJsonException {
+ String jsonString = queryResultFormatter.toString();
+ System.out.println("queryResultFormatter.toString=" + jsonString);
+ GfJsonObject gfJsonObject = new GfJsonObject(jsonString);
+ System.out.println("gfJsonObject=" + gfJsonObject);
assertThat(gfJsonObject.get(RESULT)).isNotNull();
}
private enum Currency {
PENNY, NICKLE, DIME, QUARTER
- };
+ }
private static class EnumContainer {