You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by jm...@apache.org on 2022/06/03 15:13:52 UTC

[geode] branch develop updated: GEODE-10301: support LocalDate and JodaTime (#7737)

This is an automated email from the ASF dual-hosted git repository.

jmelchior 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 e370d2fb6c GEODE-10301: support LocalDate and JodaTime (#7737)
e370d2fb6c is described below

commit e370d2fb6c9f5e4281146fe78a4840452f70ca9e
Author: Joris Melchior <jo...@gmail.com>
AuthorDate: Fri Jun 3 11:13:44 2022 -0400

    GEODE-10301: support LocalDate and JodaTime (#7737)
    
    * GEODE-10301: support LocalDate and JodaTime
    
    Co-authored-by: Jinmei Liao <jl...@pivotal.io>
    
    - include libraries so that end-users won't have to add them to the java
      path
    - ensure proper serialization in gfsh and pulse
---
 .../src/test/resources/expected-pom.xml            |  2 +-
 .../gradle/plugins/DependencyConstraints.groovy    |  2 +-
 ...tandaloneClientManagementAPIAcceptanceTest.java | 16 ++++++----
 .../integrationTest/resources/assembly_content.txt |  3 ++
 .../integrationTest/resources/expected_jars.txt    |  2 ++
 .../resources/gfsh_dependency_classpath.txt        |  3 ++
 geode-common/build.gradle                          |  2 ++
 .../geode/util/internal/GeodeJsonMapper.java       | 10 +++++++
 geode-common/src/test/resources/expected-pom.xml   | 10 +++++++
 .../DistributedSystemMBeanIntegrationTest.java     | 35 +++++++++++++++++-----
 .../internal/json/QueryResultFormatterTest.java    | 10 +++++--
 .../commands/QueryCommandIntegrationTestBase.java  | 13 +++++---
 .../sanctioned-geode-dunit-serializables.txt       |  2 +-
 .../cli/commands/GetCommandIntegrationTest.java    | 19 +++++++++++-
 .../internal/cli/domain/DataCommandResult.java     |  5 ++--
 .../cli/functions/DataCommandFunction.java         |  3 +-
 geode-junit/build.gradle                           |  1 +
 .../apache/geode/management/model/Employee.java    | 10 +++++++
 geode-junit/src/test/resources/expected-pom.xml    |  5 ++++
 .../resources/dependency_classpath.txt             |  3 ++
 20 files changed, 129 insertions(+), 27 deletions(-)

diff --git a/boms/geode-all-bom/src/test/resources/expected-pom.xml b/boms/geode-all-bom/src/test/resources/expected-pom.xml
index 93c148ebe9..f16020b7b6 100644
--- a/boms/geode-all-bom/src/test/resources/expected-pom.xml
+++ b/boms/geode-all-bom/src/test/resources/expected-pom.xml
@@ -245,7 +245,7 @@
       <dependency>
         <groupId>joda-time</groupId>
         <artifactId>joda-time</artifactId>
-        <version>2.10.9</version>
+        <version>2.10.14</version>
       </dependency>
       <dependency>
         <groupId>junit</groupId>
diff --git a/build-tools/geode-dependency-management/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy b/build-tools/geode-dependency-management/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
index cb6f371945..f8fb6e3aae 100644
--- a/build-tools/geode-dependency-management/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
+++ b/build-tools/geode-dependency-management/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy
@@ -128,7 +128,7 @@ class DependencyConstraints {
         api(group: 'javax.resource', name: 'javax.resource-api', version: '1.7.1')
         api(group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0')
         api(group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1')
-        api(group: 'joda-time', name: 'joda-time', version: '2.10.9')
+        api(group: 'joda-time', name: 'joda-time', version: '2.10.14')
         api(group: 'junit', name: 'junit', version: get('junit.version'))
         api(group: 'mx4j', name: 'mx4j-tools', version: '3.0.1')
         api(group: 'mysql', name: 'mysql-connector-java', version: '5.1.46')
diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/rest/StandaloneClientManagementAPIAcceptanceTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/rest/StandaloneClientManagementAPIAcceptanceTest.java
index 295974e0fe..79ee80105d 100644
--- a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/rest/StandaloneClientManagementAPIAcceptanceTest.java
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/rest/StandaloneClientManagementAPIAcceptanceTest.java
@@ -31,6 +31,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
@@ -123,18 +124,18 @@ public class StandaloneClientManagementAPIAcceptanceTest {
         .withName("startCluster")
         .execute(gfshRule);
 
+    int expectedReturnCode = 0;
     assertThat(startCluster.getProcess().exitValue())
-        .as("Cluster did not start correctly")
-        .isEqualTo(0);
+        .as("Cluster did not start correctly").isEqualTo(expectedReturnCode);
 
     Process process = launchClientProcess(outputJar, httpPort);
 
-    boolean exited = process.waitFor(getTimeout().toMillis(), MILLISECONDS);
-    assertThat(exited)
-        .as("Process did not exit within 10 seconds")
+    long processTimeout = getTimeout().getSeconds();
+    boolean exited = process.waitFor(processTimeout, TimeUnit.SECONDS);
+    assertThat(exited).as(String.format("Process did not exit within %d seconds", processTimeout))
         .isTrue();
     assertThat(process.exitValue())
-        .as("Process did not exit with 0 return code")
+        .as(String.format("Process did not exit with %d return code", expectedReturnCode))
         .isEqualTo(0);
 
     GfshExecution listRegionsResult = GfshScript
@@ -162,6 +163,9 @@ public class StandaloneClientManagementAPIAcceptanceTest {
         "jackson-annotations",
         "jackson-core",
         "jackson-databind",
+        "jackson-datatype-jsr310",
+        "jackson-datatype-joda",
+        "joda-time",
         "httpclient",
         "httpcore",
         "spring-beans",
diff --git a/geode-assembly/src/integrationTest/resources/assembly_content.txt b/geode-assembly/src/integrationTest/resources/assembly_content.txt
index 738e4cb73e..2b41f9c8cb 100644
--- a/geode-assembly/src/integrationTest/resources/assembly_content.txt
+++ b/geode-assembly/src/integrationTest/resources/assembly_content.txt
@@ -1070,3 +1070,6 @@ tools/Modules/Apache_Geode_Modules-0.0.0-Tomcat.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-tcServer.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-tcServer30.zip
 tools/Pulse/geode-pulse-0.0.0.war
+lib/jackson-datatype-joda-2.13.2.jar
+lib/jackson-datatype-jsr310-2.13.2.jar
+lib/joda-time-2.10.14.jar
diff --git a/geode-assembly/src/integrationTest/resources/expected_jars.txt b/geode-assembly/src/integrationTest/resources/expected_jars.txt
index 11d6f45f18..cdd374a6d7 100644
--- a/geode-assembly/src/integrationTest/resources/expected_jars.txt
+++ b/geode-assembly/src/integrationTest/resources/expected_jars.txt
@@ -26,6 +26,7 @@ jackson-annotations
 jackson-core
 jackson-databind
 jackson-dataformat-yaml
+jackson-datatype-joda
 jackson-datatype-jsr
 jakarta.activation-api
 jakarta.validation-api
@@ -51,6 +52,7 @@ jgroups
 jline
 jna
 jna-platform
+joda-time
 jopt-simple
 json-path
 json-smart
diff --git a/geode-assembly/src/integrationTest/resources/gfsh_dependency_classpath.txt b/geode-assembly/src/integrationTest/resources/gfsh_dependency_classpath.txt
index 3c6af519ed..8105a12f20 100644
--- a/geode-assembly/src/integrationTest/resources/gfsh_dependency_classpath.txt
+++ b/geode-assembly/src/integrationTest/resources/gfsh_dependency_classpath.txt
@@ -87,3 +87,6 @@ jetty-http-9.4.46.v20220331.jar
 jetty-io-9.4.46.v20220331.jar
 jetty-util-ajax-9.4.46.v20220331.jar
 jetty-util-9.4.46.v20220331.jar
+jackson-datatype-joda-2.13.2.jar
+jackson-datatype-jsr310-2.13.2.jar
+joda-time-2.10.14.jar
\ No newline at end of file
diff --git a/geode-common/build.gradle b/geode-common/build.gradle
index 1ec66dbcd7..f659493fe7 100755
--- a/geode-common/build.gradle
+++ b/geode-common/build.gradle
@@ -32,6 +32,8 @@ dependencies {
 
 
   implementation('com.fasterxml.jackson.core:jackson-databind')
+  implementation('com.fasterxml.jackson.datatype:jackson-datatype-jsr310')
+  implementation('com.fasterxml.jackson.datatype:jackson-datatype-joda')
 
   // test
   testImplementation('com.github.stefanbirkner:system-rules') {
diff --git a/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java b/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java
index ce5593d2d2..ebfef92acb 100644
--- a/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java
+++ b/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java
@@ -22,6 +22,8 @@ import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 
 /**
  * helper class for creating various json mappers used by Geode Project
@@ -34,6 +36,8 @@ public class GeodeJsonMapper {
    */
   public static ObjectMapper getMapper() {
     ObjectMapper mapper = JsonMapper.builder()
+        .addModule(new JavaTimeModule())
+        .addModule(new JodaModule())
         .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES)
         .enable(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL)
         .build();
@@ -41,6 +45,12 @@ public class GeodeJsonMapper {
     return mapper;
   }
 
+  public static ObjectMapper getMapperWithAlwaysInclusion() {
+    ObjectMapper mapper = getMapper();
+    mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
+    return mapper;
+  }
+
   public static ObjectMapper getMapperIgnoringUnknownProperties() {
     ObjectMapper mapper = getMapper();
     mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
diff --git a/geode-common/src/test/resources/expected-pom.xml b/geode-common/src/test/resources/expected-pom.xml
index 2f323add8d..1c512ff34f 100644
--- a/geode-common/src/test/resources/expected-pom.xml
+++ b/geode-common/src/test/resources/expected-pom.xml
@@ -51,5 +51,15 @@
       <artifactId>jackson-databind</artifactId>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.datatype</groupId>
+      <artifactId>jackson-datatype-jsr310</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.datatype</groupId>
+      <artifactId>jackson-datatype-joda</artifactId>
+      <scope>runtime</scope>
+    </dependency>
   </dependencies>
 </project>
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 920df23449..49471dcf0d 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,8 @@ import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.util.Date;
 
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
@@ -63,10 +65,12 @@ public class DistributedSystemMBeanIntegrationTest {
   private static Date date;
   private static java.sql.Date sqlDate;
   private static LocalDate localDate;
+  private static DateTime jodaDateTime;
 
   @BeforeClass
   public static void setupClass() throws Exception {
     Region<Object, Object> testRegion = server.getCache().getRegion("testRegion");
+    jodaDateTime = new DateTime(2020, 1, 1, 1, 1, DateTimeZone.UTC);
     localDate = LocalDate.of(2020, 1, 1);
     sqlDate = java.sql.Date.valueOf(localDate);
     date = new Date(sqlDate.getTime());
@@ -77,6 +81,7 @@ public class DistributedSystemMBeanIntegrationTest {
     employee.setStartDate(date);
     employee.setEndDate(sqlDate);
     employee.setBirthday(localDate);
+    employee.setAnniversary(jodaDateTime);
     testRegion.put(1, employee);
   }
 
@@ -100,7 +105,8 @@ public class DistributedSystemMBeanIntegrationTest {
         .doesNotContain("Job Title")
         .contains("\"java.util.Date\",\"" + dateString + "\"")
         .contains("\"java.sql.Date\",\"" + dateString + "\"")
-        .contains("\"java.time.LocalDate\",\"2020-01-01\"");
+        .contains("\"java.time.LocalDate\",\"2020-01-01\"")
+        .contains("\"org.joda.time.DateTime\",\"2020-01-01T01:01:00.000Z\"");
   }
 
   @Test
@@ -125,14 +131,28 @@ public class DistributedSystemMBeanIntegrationTest {
   }
 
   // this is simply to document the current behavior of gfsh
-  // gfsh refused to format the date objects as of jackson 2.12's fix#2683
+  // code changes made to enable jsr310
   @Test
-  public void queryAllUsingGfshRefusesToFormatLocalDate() throws Exception {
+  public void queryAllUsingGfshAbleToFormatLocalDate() throws Exception {
     gfsh.connectAndVerify(server.getJmxPort(), GfshCommandRule.PortType.jmxManager);
-    gfsh.executeAndAssertThat("query --query='" + SELECT_ALL + "'")
-        .statusIsError()
-        .containsOutput(
-            "Java 8 date/time type `java.time.LocalDate` not supported by default: add Module \"com.fasterxml.jackson.datatype:jackson-datatype-jsr310\"");
+    TabularResultModelAssert tabularResultModelAssert =
+        gfsh.executeAndAssertThat("query --query='" + SELECT_ALL + "'")
+            .statusIsSuccess()
+            .hasTableSection();
+    tabularResultModelAssert.hasColumn("birthday").containsExactly("[2020,1,1]");
+  }
+
+  // this is simply to document the current behavior of gfsh
+  // code changes made to enable Joda time
+  @Test
+  public void queryAllUsingGfshAbleToParseJodaDateTime() throws Exception {
+    gfsh.connectAndVerify(server.getJmxPort(), GfshCommandRule.PortType.jmxManager);
+    TabularResultModelAssert tabularResultModelAssert =
+        gfsh.executeAndAssertThat("query --query='" + SELECT_ALL + "'")
+            .statusIsSuccess()
+            .hasTableSection();
+    tabularResultModelAssert.hasColumn("anniversary")
+        .containsExactly(jodaDateTime.getMillis() + "");
   }
 
   @Test
@@ -142,6 +162,7 @@ public class DistributedSystemMBeanIntegrationTest {
         .statusIsSuccess()
         .hasTableSection().hasColumns().asList()
         .containsExactlyInAnyOrder("id", "title");
+
   }
 
   @Test
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/json/QueryResultFormatterTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/json/QueryResultFormatterTest.java
index 853647cd3d..f54807bf3b 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/json/QueryResultFormatterTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/json/QueryResultFormatterTest.java
@@ -15,7 +15,6 @@
 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;
@@ -31,7 +30,8 @@ import java.util.Map;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.junit.Test;
+import org.joda.time.DateTime;
+import org.junit.jupiter.api.Test;
 
 import org.apache.geode.cache.query.data.CollectionHolder;
 import org.apache.geode.internal.logging.DateFormatter;
@@ -138,6 +138,12 @@ public class QueryResultFormatterTest {
         new QueryResultFormatter(100).add(RESULT, sqlDate);
     checkResult(sqlDateResult,
         "{\"result\":[[\"java.sql.Date\",\"" + expectedString + "\"]]}");
+
+    DateTime jodaTime = new DateTime(time);
+    QueryResultFormatter jodaTimeResult =
+        new QueryResultFormatter(100).add(RESULT, jodaTime);
+    String jsonString = jodaTimeResult.toString();
+    assertThat(jsonString).contains("{\"result\":[[\"org.joda.time.DateTime\",\"");
   }
 
   @Test
diff --git a/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java b/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java
index 22ef19dd70..3d4814d8b0 100644
--- a/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java
+++ b/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java
@@ -26,6 +26,7 @@ import java.util.List;
 
 import com.google.common.io.Files;
 import org.apache.commons.io.FileUtils;
+import org.joda.time.DateTime;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
@@ -200,7 +201,8 @@ public class QueryCommandIntegrationTestBase {
   @Test
   public void outputDisplaysResultsFromComplexRegion() throws Exception {
     String result = gfsh
-        .execute("query --query='select c.name, c.address from " + SEPARATOR + "complexRegion c'");
+        .execute("query --query='select c.name, c.address, c.birthday from " + SEPARATOR
+            + "complexRegion c'");
 
     String[] resultLines = splitOnLineBreaks(result);
 
@@ -209,7 +211,7 @@ public class QueryCommandIntegrationTestBase {
     assertThat(resultLines[2]).containsPattern("Rows\\s+:\\s+100");
     assertThat(resultLines[3]).containsPattern("name\\s+\\|\\s+address");
     Arrays.asList(resultLines).subList(5, resultLines.length)
-        .forEach(line -> assertThat(line).matches("name\\d+.*\"city\":\"Hometown\".*"));
+        .forEach(line -> assertThat(line).matches("name\\d+.*\"city\":\"Hometown\".*\\d*"));
   }
 
   @Test
@@ -275,14 +277,17 @@ public class QueryCommandIntegrationTestBase {
   public static class Customer implements Serializable {
     public String name;
     public Address address;
+    public DateTime birthday;
+
 
     public Customer(String name, String street, String city) {
       this.name = name;
-      address = new Address(street, city);
+      this.address = new Address(street, city);
+      this.birthday = new DateTime();
     }
 
     public String toString() {
-      return name + address;
+      return name + address + birthday;
     }
   }
 
diff --git a/geode-dunit/src/main/resources/org/apache/geode/test/dunit/internal/sanctioned-geode-dunit-serializables.txt b/geode-dunit/src/main/resources/org/apache/geode/test/dunit/internal/sanctioned-geode-dunit-serializables.txt
index 2b3646e550..81f334b6bf 100644
--- a/geode-dunit/src/main/resources/org/apache/geode/test/dunit/internal/sanctioned-geode-dunit-serializables.txt
+++ b/geode-dunit/src/main/resources/org/apache/geode/test/dunit/internal/sanctioned-geode-dunit-serializables.txt
@@ -113,7 +113,7 @@ org/apache/geode/management/ManagementTestBase$3,false,this$0:org/apache/geode/m
 org/apache/geode/management/internal/cli/commands/ExportLogsDistributedTestBase$LogLine,false,level:java/lang/String,message:java/lang/String,shouldBeIgnoredDueToTimestamp:boolean
 org/apache/geode/management/internal/cli/commands/Product,false,contractSize:java/lang/String,productCodes:java/util/TreeMap,productID:java/lang/Long,status:java/lang/String
 org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase$Address,false,city:java/lang/String,street:java/lang/String
-org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase$Customer,false,address:org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase$Address,name:java/lang/String
+org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase$Customer,false,address:org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase$Address,birthday:org/joda/time/DateTime,name:java/lang/String
 org/apache/geode/management/internal/cli/commands/ShowDeadlockDistributedTestBase$LockFunction,false
 org/apache/geode/management/internal/cli/commands/ShowLogCommandDistributedTestBase,false
 org/apache/geode/management/internal/configuration/ClusterConfig,false,groups:java/util/List
diff --git a/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/GetCommandIntegrationTest.java b/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/GetCommandIntegrationTest.java
index fe3b3ce51c..474357a4fc 100644
--- a/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/GetCommandIntegrationTest.java
+++ b/geode-gfsh/src/integrationTest/java/org/apache/geode/management/internal/cli/commands/GetCommandIntegrationTest.java
@@ -24,6 +24,7 @@ import java.util.Formatter;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.joda.time.DateTime;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
@@ -100,7 +101,11 @@ public class GetCommandIntegrationTest {
 
   @Test
   public void get() throws Exception {
-    gfsh.executeAndAssertThat("get --region=Users --key=jonbloom").statusIsSuccess();
+    gfsh.executeAndAssertThat("get --region=Users --key=jonbloom")
+        .statusIsSuccess()
+        .hasDataSection(DataCommandResult.DATA_INFO_SECTION)
+        .hasContent()
+        .hasEntrySatisfying("Value", v -> v.contains("\"startTime\":1653595626520"));
   }
 
   @Test
@@ -205,16 +210,28 @@ public class GetCommandIntegrationTest {
 
   private static class User implements Serializable {
     private final String username;
+    private final DateTime startTime;
 
     public User(final String username) {
       assert username != null : "The username cannot be null!";
       this.username = username;
+      this.startTime = new DateTime();
+    }
+
+    public User(final String username, DateTime startTime) {
+      assert username != null : "The username cannot be null!";
+      this.username = username;
+      this.startTime = startTime;
     }
 
     public String getUsername() {
       return username;
     }
 
+    public DateTime getStartTime() {
+      return startTime;
+    }
+
     public String getHashcode() {
       StringBuilder sb = new StringBuilder(username.getBytes().length * 2);
 
diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandResult.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandResult.java
index dc4f2fe02b..36e6f81e6e 100644
--- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandResult.java
+++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/domain/DataCommandResult.java
@@ -39,6 +39,7 @@ import org.apache.geode.management.internal.cli.result.model.TabularResultModel;
 import org.apache.geode.management.internal.i18n.CliStrings;
 import org.apache.geode.pdx.JSONFormatter;
 import org.apache.geode.pdx.PdxInstance;
+import org.apache.geode.util.internal.GeodeJsonMapper;
 
 
 /**
@@ -691,7 +692,7 @@ public class DataCommandResult implements Serializable {
       } else if (value instanceof UUID) {
         columnData.put("Result", valueToJson(value));
       } else {
-        ObjectMapper mapper = new ObjectMapper();
+        ObjectMapper mapper = GeodeJsonMapper.getMapperWithAlwaysInclusion();
         JsonNode node = mapper.valueToTree(value);
 
         node.fieldNames().forEachRemaining(field -> {
@@ -729,7 +730,7 @@ public class DataCommandResult implements Serializable {
         return JSONFormatter.toJSON((PdxInstance) value);
       }
 
-      ObjectMapper mapper = new ObjectMapper();
+      ObjectMapper mapper = GeodeJsonMapper.getMapperWithAlwaysInclusion();
       try {
         return mapper.writeValueAsString(value);
       } catch (JsonProcessingException jex) {
diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/DataCommandFunction.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/DataCommandFunction.java
index 18d0ca22a4..ed7f188cdd 100644
--- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/DataCommandFunction.java
+++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/DataCommandFunction.java
@@ -600,7 +600,6 @@ public class DataCommandFunction implements InternalFunction<DataCommandRequest>
 
   private Object[] getClassAndJson(Object obj) {
     Object[] array = new Object[2];
-
     if (obj == null) {
       array[0] = null;
       array[1] = null;
@@ -614,7 +613,7 @@ public class DataCommandFunction implements InternalFunction<DataCommandRequest>
       return array;
     }
 
-    ObjectMapper mapper = new ObjectMapper();
+    ObjectMapper mapper = GeodeJsonMapper.getMapperWithAlwaysInclusion();
     try {
       array[1] = mapper.writeValueAsString(obj);
     } catch (JsonProcessingException e) {
diff --git a/geode-junit/build.gradle b/geode-junit/build.gradle
index 010e30a4f8..73fbdb64d3 100755
--- a/geode-junit/build.gradle
+++ b/geode-junit/build.gradle
@@ -47,6 +47,7 @@ dependencies {
   api('io.github.classgraph:classgraph')
   api('com.fasterxml.jackson.core:jackson-annotations')
   api('com.fasterxml.jackson.core:jackson-databind')
+  api('joda-time:joda-time')
   api('com.github.stefanbirkner:system-rules') {
     exclude module: 'junit-dep'
   }
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
index e7cf063afd..18094aa946 100644
--- 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
@@ -20,6 +20,7 @@ import java.util.Date;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import org.joda.time.DateTime;
 
 /**
  * a domain object that has various date objects and json annotations.
@@ -33,6 +34,7 @@ public class Employee {
   private Date startDate;
   private java.sql.Date endDate;
   private LocalDate birthday;
+  private DateTime anniversary;
 
   @JsonIgnore
   public int getId() {
@@ -91,4 +93,12 @@ public class Employee {
   public void setBirthday(LocalDate birthday) {
     this.birthday = birthday;
   }
+
+  public DateTime getAnniversary() {
+    return anniversary;
+  }
+
+  public void setAnniversary(DateTime anniversary) {
+    this.anniversary = anniversary;
+  }
 }
diff --git a/geode-junit/src/test/resources/expected-pom.xml b/geode-junit/src/test/resources/expected-pom.xml
index e3db01d0e5..ff48598963 100644
--- a/geode-junit/src/test/resources/expected-pom.xml
+++ b/geode-junit/src/test/resources/expected-pom.xml
@@ -92,6 +92,11 @@
       <artifactId>jackson-databind</artifactId>
       <scope>compile</scope>
     </dependency>
+    <dependency>
+      <groupId>joda-time</groupId>
+      <artifactId>joda-time</artifactId>
+      <scope>compile</scope>
+    </dependency>
     <dependency>
       <groupId>com.github.stefanbirkner</groupId>
       <artifactId>system-rules</artifactId>
diff --git a/geode-server-all/src/integrationTest/resources/dependency_classpath.txt b/geode-server-all/src/integrationTest/resources/dependency_classpath.txt
index 5c2f4c5264..6af61dfa67 100644
--- a/geode-server-all/src/integrationTest/resources/dependency_classpath.txt
+++ b/geode-server-all/src/integrationTest/resources/dependency_classpath.txt
@@ -87,3 +87,6 @@ antlr-2.7.7.jar
 jetty-xml-9.4.46.v20220331.jar
 geode-rebalancer-0.0.0.jar
 jetty-server-9.4.46.v20220331.jar
+jackson-datatype-jsr310-2.13.2.jar
+jackson-datatype-joda-2.13.2.jar
+joda-time-2.10.14.jar
\ No newline at end of file