Skip to content
This repository was archived by the owner on Jan 27, 2021. It is now read-only.

Commit 6ca548f

Browse files
authored
GEODE-8447: QueryResultFormatter should show dates in localized strings (apache#5469)
* support java.util.Date, java.sql.Date and java.time.* date objects in the formatter
1 parent 43a783b commit 6ca548f

File tree

7 files changed

+175
-5
lines changed

7 files changed

+175
-5
lines changed

boms/geode-all-bom/src/test/resources/expected-pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@
6767
<version>2.9.8</version>
6868
<scope>compile</scope>
6969
</dependency>
70+
<dependency>
71+
<groupId>com.fasterxml.jackson.datatype</groupId>
72+
<artifactId>jackson-datatype-jsr310</artifactId>
73+
<version>2.11.2</version>
74+
<scope>compile</scope>
75+
</dependency>
7076
<dependency>
7177
<groupId>com.fasterxml.jackson.module</groupId>
7278
<artifactId>jackson-module-scala_2.10</artifactId>

buildSrc/src/main/groovy/org/apache/geode/gradle/plugins/DependencyConstraints.groovy

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class DependencyConstraints implements Plugin<Project> {
8888
api(group: 'com.arakelian', name: 'java-jq', version: '0.10.1')
8989
api(group: 'com.carrotsearch.randomizedtesting', name: 'randomizedtesting-runner', version: '2.7.7')
9090
api(group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-joda', version: '2.9.8')
91+
api(group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.11.2')
9192
api(group: 'com.fasterxml.jackson.module', name: 'jackson-module-scala_2.10', version: '2.10.0')
9293
api(group: 'com.github.davidmoten', name: 'geo', version: '0.7.7')
9394
api(group: 'com.github.stefanbirkner', name: 'system-rules', version: '1.19.0')

geode-core/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ dependencies {
366366

367367
integrationTestRuntimeOnly('org.apache.derby:derby')
368368
integrationTestRuntimeOnly('xerces:xercesImpl')
369+
integrationTestRuntimeOnly('com.fasterxml.jackson.datatype:jackson-datatype-jsr310')
369370

370371
distributedTestImplementation(project(':geode-gfsh'))
371372
distributedTestImplementation(project(':geode-junit')) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3+
* agreements. See the NOTICE file distributed with this work for additional information regarding
4+
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
5+
* "License"); you may not use this file except in compliance with the License. You may obtain a
6+
* copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software distributed under the License
11+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12+
* or implied. See the License for the specific language governing permissions and limitations under
13+
* the License.
14+
*/
15+
16+
package org.apache.geode.management.internal.beans;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import java.text.SimpleDateFormat;
21+
import java.time.LocalDate;
22+
import java.util.Date;
23+
24+
import org.junit.BeforeClass;
25+
import org.junit.ClassRule;
26+
import org.junit.Rule;
27+
import org.junit.Test;
28+
29+
import org.apache.geode.cache.Region;
30+
import org.apache.geode.cache.RegionShortcut;
31+
import org.apache.geode.management.DistributedSystemMXBean;
32+
import org.apache.geode.management.internal.json.QueryResultFormatter;
33+
import org.apache.geode.test.junit.assertions.TabularResultModelAssert;
34+
import org.apache.geode.test.junit.rules.GfshCommandRule;
35+
import org.apache.geode.test.junit.rules.MBeanServerConnectionRule;
36+
import org.apache.geode.test.junit.rules.ServerStarterRule;
37+
38+
public class DistributedSystemMBeanIntegrationTest {
39+
40+
public static final String SELECT = "select * from /testRegion r where r.id=1";
41+
42+
@ClassRule
43+
public static ServerStarterRule server = new ServerStarterRule()
44+
.withNoCacheServer()
45+
.withJMXManager()
46+
.withRegion(RegionShortcut.REPLICATE, "testRegion")
47+
.withAutoStart();
48+
49+
@Rule
50+
public MBeanServerConnectionRule connectionRule =
51+
new MBeanServerConnectionRule(server::getJmxPort);
52+
53+
@Rule
54+
public GfshCommandRule gfsh = new GfshCommandRule();
55+
56+
private static Date date;
57+
private static java.sql.Date sqlDate;
58+
private static LocalDate localDate;
59+
60+
@BeforeClass
61+
public static void setupClass() throws Exception {
62+
Region<Object, Object> testRegion = server.getCache().getRegion("testRegion");
63+
localDate = LocalDate.of(2020, 1, 1);
64+
sqlDate = java.sql.Date.valueOf(localDate);
65+
date = new Date(sqlDate.getTime());
66+
Data data = new Data(1, date, sqlDate, localDate);
67+
testRegion.put(1, data);
68+
}
69+
70+
// this is to make sure dates are formatted correctly
71+
@Test
72+
public void queryUsingMBean() throws Exception {
73+
connectionRule.connect(server.getJmxPort());
74+
SimpleDateFormat formater =
75+
new SimpleDateFormat(QueryResultFormatter.DATE_FORMAT_PATTERN);
76+
String dateString = formater.format(date);
77+
DistributedSystemMXBean bean = connectionRule.getProxyMXBean(DistributedSystemMXBean.class);
78+
String result = bean.queryData(SELECT, "server", 100);
79+
System.out.println(result);
80+
assertThat(result)
81+
.contains("\"java.util.Date\",\"" + dateString + "\"")
82+
.contains("\"java.sql.Date\",\"" + dateString + "\"")
83+
.contains("\"java.time.LocalDate\",\"2020-01-01\"");
84+
}
85+
86+
// this is simply to document the current behavior of gfsh
87+
// gfsh doesn't attempt tp format the date objects as of now
88+
@Test
89+
public void queryUsingGfsh() throws Exception {
90+
gfsh.connectAndVerify(server.getJmxPort(), GfshCommandRule.PortType.jmxManager);
91+
TabularResultModelAssert tabularAssert =
92+
gfsh.executeAndAssertThat("query --query='" + SELECT + "'")
93+
.statusIsSuccess()
94+
.hasTableSection();
95+
tabularAssert.hasColumn("id").containsExactly("1");
96+
tabularAssert.hasColumn("date").containsExactly(date.getTime() + "");
97+
tabularAssert.hasColumn("sqlDate").containsExactly(sqlDate.getTime() + "");
98+
tabularAssert.hasColumn("localDate")
99+
.asList().asString().contains("\"year\":2020,\"month\":\"JANUARY\"");
100+
}
101+
102+
public static class Data {
103+
private int id;
104+
private Date date;
105+
private java.sql.Date sqlDate;
106+
private LocalDate localDate;
107+
108+
public Data() {}
109+
110+
public Data(int id, Date date, java.sql.Date sqlDate, LocalDate localDate) {
111+
this.id = id;
112+
this.date = date;
113+
this.sqlDate = sqlDate;
114+
this.localDate = localDate;
115+
}
116+
117+
public int getId() {
118+
return id;
119+
}
120+
121+
public void setId(int id) {
122+
this.id = id;
123+
}
124+
125+
public Date getDate() {
126+
return date;
127+
}
128+
129+
public void setDate(Date date) {
130+
this.date = date;
131+
}
132+
133+
public java.sql.Date getSqlDate() {
134+
return sqlDate;
135+
}
136+
137+
public void setSqlDate(java.sql.Date sqlDate) {
138+
this.sqlDate = sqlDate;
139+
}
140+
141+
public LocalDate getLocalDate() {
142+
return localDate;
143+
}
144+
145+
public void setLocalDate(LocalDate localDate) {
146+
this.localDate = localDate;
147+
}
148+
}
149+
}

geode-core/src/main/java/org/apache/geode/management/internal/json/AbstractJSONFormatter.java

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ public AbstractJSONFormatter(int maxCollectionElements, int serializationDepth,
9494

9595
// register the custom module
9696
mapper.registerModule(mapperModule);
97+
// to support jdk8 java.time if jackson-datatype-jsr310 is included in the classpath
98+
mapper.findAndRegisterModules();
9799

98100
// allow objects with no content
99101
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

geode-core/src/main/java/org/apache/geode/management/internal/json/QueryResultFormatter.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.UncheckedIOException;
2222
import java.io.Writer;
2323
import java.text.DateFormat;
24+
import java.text.SimpleDateFormat;
2425
import java.util.ArrayList;
2526
import java.util.LinkedHashMap;
2627
import java.util.List;
@@ -41,6 +42,8 @@
4142

4243
public class QueryResultFormatter extends AbstractJSONFormatter {
4344

45+
public static final String DATE_FORMAT_PATTERN =
46+
"EEE " + new SimpleDateFormat().toLocalizedPattern() + " zzz";
4447
/**
4548
* map contains the named objects to be serialized
4649
*/
@@ -74,8 +77,10 @@ void postCreateMapper() {
7477
TypeSerializationEnforcerModule typeModule =
7578
new TypeSerializationEnforcerModule(nonOverridableSerializers);
7679

77-
// Consistency: use the default date format java.sql.Date as well as java.util.Date.
80+
// Consistency: use the same date format java.sql.Date as well as java.util.Date.
7881
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
82+
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_PATTERN);
83+
mapper.setDateFormat(sdf);
7984
typeModule.addSerializer(java.sql.Date.class, new SqlDateSerializer(mapper.getDateFormat()));
8085

8186
// Register module

geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/json/QueryResultFormatterTest.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import static org.mockito.Mockito.verify;
2121

2222
import java.math.BigDecimal;
23+
import java.text.SimpleDateFormat;
2324
import java.util.ArrayList;
2425
import java.util.Collection;
26+
import java.util.Date;
2527
import java.util.HashMap;
2628
import java.util.List;
2729
import java.util.Map;
@@ -117,15 +119,19 @@ public void testPrimitives() throws Exception {
117119
QueryResultFormatter stringResult = new QueryResultFormatter(100).add(RESULT, "String");
118120
checkResult(stringResult, "{\"result\":[[\"java.lang.String\",\"String\"]]}");
119121

122+
Date date = new Date(0);
123+
String expectedString =
124+
new SimpleDateFormat(QueryResultFormatter.DATE_FORMAT_PATTERN).format(date);
120125
QueryResultFormatter javaDateResult =
121-
new QueryResultFormatter(100).add(RESULT, new java.util.Date(0));
126+
new QueryResultFormatter(100).add(RESULT, date);
122127
checkResult(javaDateResult,
123-
"{\"result\":[[\"java.util.Date\",\"1970-01-01T00:00:00.000+0000\"]]}");
128+
"{\"result\":[[\"java.util.Date\",\"" + expectedString + "\"]]}");
124129

130+
java.sql.Date sqlDate = new java.sql.Date(0);
125131
QueryResultFormatter sqlDateResult =
126-
new QueryResultFormatter(100).add(RESULT, new java.sql.Date(0));
132+
new QueryResultFormatter(100).add(RESULT, sqlDate);
127133
checkResult(sqlDateResult,
128-
"{\"result\":[[\"java.sql.Date\",\"1970-01-01T00:00:00.000+0000\"]]}");
134+
"{\"result\":[[\"java.sql.Date\",\"" + expectedString + "\"]]}");
129135
}
130136

131137
@Test

0 commit comments

Comments
 (0)