This is an automated email from the ASF dual-hosted git repository.
jinmeiliao pushed a commit to branch support/1.12
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/support/1.12 by this push:
new 1985b51 GEODE-8489: "Select *" query by DistributedSystemMBean should
not hon… (#5507)
1985b51 is described below
commit 1985b510e077cef9d1c3c5677c45dcd505b211cc
Author: Jinmei Liao <[email protected]>
AuthorDate: Mon Sep 21 07:53:38 2020 -0700
GEODE-8489: "Select *" query by DistributedSystemMBean should not hon…
(#5507)
* null value fields are serialized as well
* move QueryResultFormatterTest to core
---
.../DistributedSystemMBeanIntegrationTest.java | 117 ++++++++++-----------
.../internal/json/AbstractJSONFormatter.java | 1 +
.../internal/json/QueryResultFormatter.java | 4 +
.../internal}/json/QueryResultFormatterTest.java | 29 ++++-
.../apache/geode/management/model/Employee.java | 94 +++++++++++++++++
5 files changed, 181 insertions(+), 64 deletions(-)
diff --git
a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemMBeanIntegrationTest.java
b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemMBeanIntegrationTest.java
index 8b47b0a..2c662f0 100644
---
a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemMBeanIntegrationTest.java
+++
b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemMBeanIntegrationTest.java
@@ -21,6 +21,7 @@ import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
@@ -30,6 +31,7 @@ import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.management.DistributedSystemMXBean;
import org.apache.geode.management.internal.json.QueryResultFormatter;
+import org.apache.geode.management.model.Employee;
import org.apache.geode.test.junit.assertions.TabularResultModelAssert;
import org.apache.geode.test.junit.rules.GfshCommandRule;
import org.apache.geode.test.junit.rules.MBeanServerConnectionRule;
@@ -37,7 +39,8 @@ import org.apache.geode.test.junit.rules.ServerStarterRule;
public class DistributedSystemMBeanIntegrationTest {
- public static final String SELECT = "select * from /testRegion r where
r.id=1";
+ public static final String SELECT_ALL = "select * from /testRegion r where
r.id=1";
+ public static final String SELECT_FIELDS = "select id, title from
/testRegion r where r.id=1";
@ClassRule
public static ServerStarterRule server = new ServerStarterRule()
@@ -53,6 +56,8 @@ public class DistributedSystemMBeanIntegrationTest {
@Rule
public GfshCommandRule gfsh = new GfshCommandRule();
+ private DistributedSystemMXBean bean;
+
private static Date date;
private static java.sql.Date sqlDate;
private static LocalDate localDate;
@@ -63,87 +68,81 @@ public class DistributedSystemMBeanIntegrationTest {
localDate = LocalDate.of(2020, 1, 1);
sqlDate = java.sql.Date.valueOf(localDate);
date = new Date(sqlDate.getTime());
- Data data = new Data(1, date, sqlDate, localDate);
- testRegion.put(1, data);
+ Employee employee = new Employee();
+ employee.setId(1);
+ employee.setName("John");
+ employee.setTitle("Manager");
+ employee.setStartDate(date);
+ employee.setEndDate(sqlDate);
+ employee.setBirthday(localDate);
+ testRegion.put(1, employee);
}
- // this is to make sure dates are formatted correctly
- @Test
- public void queryUsingMBean() throws Exception {
+ @Before
+ public void setup() throws Exception {
connectionRule.connect(server.getJmxPort());
+ bean = connectionRule.getProxyMXBean(DistributedSystemMXBean.class);
+ }
+
+ // this is to make sure dates are formatted correctly and it does not honor
the json annotations
+ @Test
+ public void queryAllUsingMBean() throws Exception {
SimpleDateFormat formater =
new SimpleDateFormat(QueryResultFormatter.DATE_FORMAT_PATTERN);
String dateString = formater.format(date);
- DistributedSystemMXBean bean =
connectionRule.getProxyMXBean(DistributedSystemMXBean.class);
- String result = bean.queryData(SELECT, "server", 100);
+ String result = bean.queryData(SELECT_ALL, "server", 100);
System.out.println(result);
assertThat(result)
+ .contains("id")
+ .contains("title")
+ .contains("address")
+ .doesNotContain("Job Title")
.contains("\"java.util.Date\",\"" + dateString + "\"")
.contains("\"java.sql.Date\",\"" + dateString + "\"")
.contains("\"java.time.LocalDate\",\"2020-01-01\"");
}
+ @Test
+ public void queryFieldsUsingMbeanDoesNotHonorAnnotations() throws Exception {
+ String result = bean.queryData(SELECT_FIELDS, "server", 100);
+ System.out.println(result);
+ assertThat(result).contains("id").contains("title");
+ }
+
// this is simply to document the current behavior of gfsh
- // gfsh doesn't attempt tp format the date objects as of now
+ // gfsh doesn't attempt to format the date objects as of now, and it respect
the json annotations
+ // when listing out the headers
@Test
- public void queryUsingGfsh() throws Exception {
+ public void queryAllUsingGfshDoesNotFormatDate() throws Exception {
gfsh.connectAndVerify(server.getJmxPort(),
GfshCommandRule.PortType.jmxManager);
TabularResultModelAssert tabularAssert =
- gfsh.executeAndAssertThat("query --query='" + SELECT + "'")
+ gfsh.executeAndAssertThat("query --query='" + SELECT_ALL + "'")
.statusIsSuccess()
.hasTableSection();
- tabularAssert.hasColumn("id").containsExactly("1");
- tabularAssert.hasColumn("date").containsExactly(date.getTime() + "");
- tabularAssert.hasColumn("sqlDate").containsExactly(sqlDate.getTime() + "");
- tabularAssert.hasColumn("localDate")
+ // note gfsh doesn't show id field and shows "title" field as "Job Title"
when doing select *
+ tabularAssert.hasColumns().asList().containsExactlyInAnyOrder("name",
"address", "startDate",
+ "endDate", "birthday", "Job Title");
+ tabularAssert.hasColumn("startDate").containsExactly(date.getTime() + "");
+ tabularAssert.hasColumn("endDate").containsExactly(sqlDate.getTime() + "");
+ tabularAssert.hasColumn("birthday")
.asList().asString().contains("\"year\":2020,\"month\":\"JANUARY\"");
}
- public static class Data {
- private int id;
- private Date date;
- private java.sql.Date sqlDate;
- private LocalDate localDate;
-
- public Data() {}
-
- public Data(int id, Date date, java.sql.Date sqlDate, LocalDate localDate)
{
- this.id = id;
- this.date = date;
- this.sqlDate = sqlDate;
- this.localDate = localDate;
- }
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public Date getDate() {
- return date;
- }
-
- public void setDate(Date date) {
- this.date = date;
- }
-
- public java.sql.Date getSqlDate() {
- return sqlDate;
- }
-
- public void setSqlDate(java.sql.Date sqlDate) {
- this.sqlDate = sqlDate;
- }
+ @Test
+ public void queryFieldsUsingGfshDoesNotHonorAnnotations() throws Exception {
+ gfsh.connectAndVerify(server.getJmxPort(),
GfshCommandRule.PortType.jmxManager);
+ gfsh.executeAndAssertThat("query --query='" + SELECT_FIELDS + "'")
+ .statusIsSuccess()
+ .hasTableSection().hasColumns().asList()
+ .containsExactlyInAnyOrder("id", "title");
+ }
- public LocalDate getLocalDate() {
- return localDate;
- }
+ @Test
+ public void documentZeroResultsBehavior() throws Exception {
+ String result = bean.queryData("select * from /testRegion r where r.id=0",
"server", 100);
+ assertThat(result).isEqualTo("{\"result\":[{\"message\":\"No Data
Found\"}]}");
- public void setLocalDate(LocalDate localDate) {
- this.localDate = localDate;
- }
+ result = bean.queryData("select id, title from /testRegion r where
r.id=0", "server", 100);
+ assertThat(result).isEqualTo("{\"result\":[{\"message\":\"No Data
Found\"}]}");
}
}
diff --git
a/geode-core/src/main/java/org/apache/geode/management/internal/json/AbstractJSONFormatter.java
b/geode-core/src/main/java/org/apache/geode/management/internal/json/AbstractJSONFormatter.java
index f91f062..cdc5a40 100644
---
a/geode-core/src/main/java/org/apache/geode/management/internal/json/AbstractJSONFormatter.java
+++
b/geode-core/src/main/java/org/apache/geode/management/internal/json/AbstractJSONFormatter.java
@@ -97,6 +97,7 @@ public abstract class AbstractJSONFormatter {
// to support jdk8 java.time if jackson-datatype-jsr310 is included in the
classpath
mapper.findAndRegisterModules();
+ mapper.disable(MapperFeature.USE_ANNOTATIONS);
// allow objects with no content
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// use toString on Enums
diff --git
a/geode-core/src/main/java/org/apache/geode/management/internal/json/QueryResultFormatter.java
b/geode-core/src/main/java/org/apache/geode/management/internal/json/QueryResultFormatter.java
index 3cc63ac..bbd5523 100644
---
a/geode-core/src/main/java/org/apache/geode/management/internal/json/QueryResultFormatter.java
+++
b/geode-core/src/main/java/org/apache/geode/management/internal/json/QueryResultFormatter.java
@@ -38,6 +38,7 @@ 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 com.fasterxml.jackson.databind.ser.ResolvableSerializer;
import com.fasterxml.jackson.databind.type.ArrayType;
public class QueryResultFormatter extends AbstractJSONFormatter {
@@ -216,6 +217,9 @@ public class QueryResultFormatter extends
AbstractJSONFormatter {
} else {
gen.writeStartArray();
gen.writeString(value.getClass().getCanonicalName());
+ if (defaultSerializer instanceof ResolvableSerializer) {
+ ((ResolvableSerializer) defaultSerializer).resolve(serializers);
+ }
defaultSerializer.serialize(value, gen, serializers);
gen.writeEndArray();
}
diff --git
a/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterTest.java
b/geode-core/src/test/java/org/apache/geode/management/internal/json/QueryResultFormatterTest.java
similarity index 92%
rename from
geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterTest.java
rename to
geode-core/src/test/java/org/apache/geode/management/internal/json/QueryResultFormatterTest.java
index 256e4d9..1defccb 100644
---
a/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterTest.java
+++
b/geode-core/src/test/java/org/apache/geode/management/internal/json/QueryResultFormatterTest.java
@@ -12,9 +12,10 @@
* or implied. See the License for the specific language governing permissions
and limitations under
* the License.
*/
-package org.apache.geode.management.internal.cli.json;
+package org.apache.geode.management.internal.json;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.InstanceOfAssertFactories.map;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -33,7 +34,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.apache.geode.cache.query.data.CollectionHolder;
-import org.apache.geode.management.internal.json.QueryResultFormatter;
+import org.apache.geode.management.model.Employee;
import org.apache.geode.management.model.Item;
import org.apache.geode.management.model.Order;
import org.apache.geode.management.model.SubOrder;
@@ -257,7 +258,7 @@ public class QueryResultFormatterTest {
QueryResultFormatter queryResultFormatter =
new QueryResultFormatter(100).add(RESULT, Currency.DIME);
checkResult(queryResultFormatter,
-
"{\"result\":[[\"org.apache.geode.management.internal.cli.json.QueryResultFormatterTest.Currency\",\"DIME\"]]}");
+
"{\"result\":[[\"org.apache.geode.management.internal.json.QueryResultFormatterTest.Currency\",\"DIME\"]]}");
}
@Test
@@ -270,7 +271,7 @@ public class QueryResultFormatterTest {
QueryResultFormatter queryResultFormatter = new
QueryResultFormatter(100).add(RESULT, list);
checkResult(queryResultFormatter,
-
"{\"result\":[[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.internal.cli.json.QueryResultFormatterTest.Currency\",\"DIME\"],\"1\":[\"org.apache.geode.management.internal.cli.json.QueryResultFormatterTest.Currency\",\"NICKLE\"],\"2\":[\"org.apache.geode.management.internal.cli.json.QueryResultFormatterTest.Currency\",\"QUARTER\"],\"3\":[\"org.apache.geode.management.internal.cli.json.QueryResultFormatterTest.Currency\",\"NICKLE\"]}]]}");
+
"{\"result\":[[\"java.util.ArrayList\",{\"0\":[\"org.apache.geode.management.internal.json.QueryResultFormatterTest.Currency\",\"DIME\"],\"1\":[\"org.apache.geode.management.internal.json.QueryResultFormatterTest.Currency\",\"NICKLE\"],\"2\":[\"org.apache.geode.management.internal.json.QueryResultFormatterTest.Currency\",\"QUARTER\"],\"3\":[\"org.apache.geode.management.internal.json.QueryResultFormatterTest.Currency\",\"NICKLE\"]}]]}");
}
@Test
@@ -279,7 +280,25 @@ public class QueryResultFormatterTest {
QueryResultFormatter queryResultFormatter =
new QueryResultFormatter(100).add(RESULT, enumContainer);
checkResult(queryResultFormatter,
-
"{\"result\":[[\"org.apache.geode.management.internal.cli.json.QueryResultFormatterTest.EnumContainer\",{}]]}");
+
"{\"result\":[[\"org.apache.geode.management.internal.json.QueryResultFormatterTest.EnumContainer\",{}]]}");
+ }
+
+ @Test
+ public void testObjectWithJsonAnnotation() throws Exception {
+ Employee employee = new Employee();
+ employee.setId(10);
+ employee.setName("John");
+ employee.setTitle("Manager");
+ QueryResultFormatter queryResultFormatter = new QueryResultFormatter(100);
+ queryResultFormatter.add("result", employee);
+ // these to make sure we are keeping the pre 1.8 behavior
+ assertThat(queryResultFormatter.toString())
+ // make sure null values are serialized as well
+ .contains("\"address\":null")
+ // make sure we don't honor @JsonIgnore annotation
+ .contains("id")
+ // make sure we don't honor @JsonProperty annotation
+ .doesNotContain("Job Title");
}
private enum Currency {
diff --git
a/geode-junit/src/main/java/org/apache/geode/management/model/Employee.java
b/geode-junit/src/main/java/org/apache/geode/management/model/Employee.java
new file mode 100644
index 0000000..e7cf063
--- /dev/null
+++ b/geode-junit/src/main/java/org/apache/geode/management/model/Employee.java
@@ -0,0 +1,94 @@
+/*
+ * 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.model;
+
+import java.time.LocalDate;
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * a domain object that has various date objects and json annotations.
+ * Used to test QueryResultsFormatter
+ */
+public class Employee {
+ private int id;
+ private String name;
+ private String title;
+ private String address;
+ private Date startDate;
+ private java.sql.Date endDate;
+ private LocalDate birthday;
+
+ @JsonIgnore
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @JsonProperty("Job Title")
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ public java.sql.Date getEndDate() {
+ return endDate;
+ }
+
+ public void setEndDate(java.sql.Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public LocalDate getBirthday() {
+ return birthday;
+ }
+
+ public void setBirthday(LocalDate birthday) {
+ this.birthday = birthday;
+ }
+}