Copy SqlTimestampDeserializer from gwtjsonrpc
Keep package-private in the json package so it can be used by all Gson instances created by OutputFormat. Also copy in JavaSqlTimestampHelper, which is a dependency. Change-Id: Ib9d31d346dbf2fd28b8fc78e425c0bf81a2fe9a6
This commit is contained in:
108
java/com/google/gerrit/json/JavaSqlTimestampHelper.java
Normal file
108
java/com/google/gerrit/json/JavaSqlTimestampHelper.java
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2008 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed 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 com.google.gerrit.json;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/** Utility to parse Timestamp from a string. */
|
||||||
|
public class JavaSqlTimestampHelper {
|
||||||
|
/**
|
||||||
|
* Parse a string into a timestamp.
|
||||||
|
*
|
||||||
|
* <p>Note that {@link Timestamp}s have no timezone, so the result is relative to the UTC epoch.
|
||||||
|
*
|
||||||
|
* <p>Supports the format {@code yyyy-MM-dd[ HH:mm:ss[.SSS][ Z]]} where {@code Z} is a 4-digit
|
||||||
|
* offset with sign, e.g. {@code -0500}.
|
||||||
|
*
|
||||||
|
* @param s input string.
|
||||||
|
* @return resulting timestamp.
|
||||||
|
*/
|
||||||
|
public static Timestamp parseTimestamp(String s) {
|
||||||
|
String[] components = s.split(" ");
|
||||||
|
if (components.length < 1 || components.length > 3) {
|
||||||
|
throw new IllegalArgumentException("Expected date and optional time: " + s);
|
||||||
|
}
|
||||||
|
String date = components[0];
|
||||||
|
String time = components.length >= 2 ? components[1] : null;
|
||||||
|
int off = components.length == 3 ? parseTimeZone(components[2]) : 0;
|
||||||
|
String[] dSplit = date.split("-");
|
||||||
|
if (dSplit.length != 3) {
|
||||||
|
throw new IllegalArgumentException("Invalid date format: " + date);
|
||||||
|
}
|
||||||
|
int yy, mm, dd;
|
||||||
|
try {
|
||||||
|
yy = Integer.parseInt(dSplit[0]) - 1900;
|
||||||
|
mm = Integer.parseInt(dSplit[1]) - 1;
|
||||||
|
dd = Integer.parseInt(dSplit[2]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid date format: " + date, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hh, mi, ss, ns;
|
||||||
|
if (time != null) {
|
||||||
|
int p = time.indexOf('.');
|
||||||
|
String t;
|
||||||
|
double f;
|
||||||
|
try {
|
||||||
|
if (p >= 0) {
|
||||||
|
t = time.substring(0, p);
|
||||||
|
f = Double.parseDouble("0." + time.substring(p + 1));
|
||||||
|
} else {
|
||||||
|
t = time;
|
||||||
|
f = 0;
|
||||||
|
}
|
||||||
|
String[] tSplit = t.split(":");
|
||||||
|
if (tSplit.length != 3) {
|
||||||
|
throw new IllegalArgumentException("Invalid time format: " + time);
|
||||||
|
}
|
||||||
|
hh = Integer.parseInt(tSplit[0]);
|
||||||
|
mi = Integer.parseInt(tSplit[1]);
|
||||||
|
ss = Integer.parseInt(tSplit[2]);
|
||||||
|
ns = (int) Math.round(f * 1e9);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid time format: " + time, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hh = 0;
|
||||||
|
mi = 0;
|
||||||
|
ss = 0;
|
||||||
|
ns = 0;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
Timestamp result = new Timestamp(Date.UTC(yy, mm, dd, hh, mi, ss) - off);
|
||||||
|
result.setNanos(ns);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int parseTimeZone(String s) {
|
||||||
|
if (s.length() != 5 || (s.charAt(0) != '-' && s.charAt(0) != '+')) {
|
||||||
|
throw new IllegalArgumentException("Invalid time zone: " + s);
|
||||||
|
}
|
||||||
|
for (int i = 1; i < s.length(); i++) {
|
||||||
|
if (s.charAt(i) < '0' || s.charAt(i) > '9') {
|
||||||
|
throw new IllegalArgumentException("Invalid time zone: " + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int off =
|
||||||
|
(s.charAt(0) == '-' ? -1 : 1)
|
||||||
|
* 60
|
||||||
|
* 1000
|
||||||
|
* ((60 * Integer.parseInt(s.substring(1, 3))) + Integer.parseInt(s.substring(3, 5)));
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JavaSqlTimestampHelper() {}
|
||||||
|
}
|
||||||
@@ -17,7 +17,6 @@ package com.google.gerrit.json;
|
|||||||
import com.google.gson.FieldNamingPolicy;
|
import com.google.gson.FieldNamingPolicy;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gwtjsonrpc.server.SqlTimestampDeserializer;
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
/** Standard output format used by an API call. */
|
/** Standard output format used by an API call. */
|
||||||
|
|||||||
66
java/com/google/gerrit/json/SqlTimestampDeserializer.java
Normal file
66
java/com/google/gerrit/json/SqlTimestampDeserializer.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2008 Google Inc.
|
||||||
|
//
|
||||||
|
// Licensed 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 com.google.gerrit.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonNull;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
class SqlTimestampDeserializer
|
||||||
|
implements JsonDeserializer<java.sql.Timestamp>, JsonSerializer<java.sql.Timestamp> {
|
||||||
|
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Timestamp deserialize(
|
||||||
|
final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
|
||||||
|
throws JsonParseException {
|
||||||
|
if (json.isJsonNull()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!json.isJsonPrimitive()) {
|
||||||
|
throw new JsonParseException("Expected string for timestamp type");
|
||||||
|
}
|
||||||
|
final JsonPrimitive p = (JsonPrimitive) json;
|
||||||
|
if (!p.isString()) {
|
||||||
|
throw new JsonParseException("Expected string for timestamp type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return JavaSqlTimestampHelper.parseTimestamp(p.getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(
|
||||||
|
final java.sql.Timestamp src, final Type typeOfSrc, final JsonSerializationContext context) {
|
||||||
|
if (src == null) {
|
||||||
|
return new JsonNull();
|
||||||
|
}
|
||||||
|
return new JsonPrimitive(newFormat().format(src) + "000000");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SimpleDateFormat newFormat() {
|
||||||
|
final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||||
|
f.setTimeZone(UTC);
|
||||||
|
f.setLenient(true);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
javatests/com/google/gerrit/json/BUILD
Normal file
11
javatests/com/google/gerrit/json/BUILD
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
load("//tools/bzl:junit.bzl", "junit_tests")
|
||||||
|
|
||||||
|
junit_tests(
|
||||||
|
name = "json_tests",
|
||||||
|
srcs = glob(["*.java"]),
|
||||||
|
deps = [
|
||||||
|
"//java/com/google/gerrit/json",
|
||||||
|
"//lib:guava",
|
||||||
|
"//lib/truth",
|
||||||
|
],
|
||||||
|
)
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (C) 2014 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed 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 com.google.gerrit.json;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.truth.Truth.assert_;
|
||||||
|
import static com.google.gerrit.json.JavaSqlTimestampHelper.parseTimestamp;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class JavaSqlTimestampHelperTest {
|
||||||
|
private SimpleDateFormat format;
|
||||||
|
private TimeZone systemTimeZone;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
synchronized (TimeZone.class) {
|
||||||
|
systemTimeZone = TimeZone.getDefault();
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone("GMT-5:00"));
|
||||||
|
format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void resetTimeZone() {
|
||||||
|
TimeZone.setDefault(systemTimeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseFullTimestamp() {
|
||||||
|
assertThat(reformat("2006-01-02 20:04:05.789000000"))
|
||||||
|
.isEqualTo("2006-01-02 15:04:05.789 -0500");
|
||||||
|
assertThat(reformat("2006-01-02 20:04:05")).isEqualTo("2006-01-02 15:04:05.000 -0500");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseDateOnly() {
|
||||||
|
assertThat(reformat("2006-01-02")).isEqualTo("2006-01-01 19:00:00.000 -0500");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseTimeZone() {
|
||||||
|
assertThat(reformat("2006-01-02 15:04:05.789 -0100"))
|
||||||
|
.isEqualTo("2006-01-02 11:04:05.789 -0500");
|
||||||
|
assertThat(reformat("2006-01-02 15:04:05.789 -0000"))
|
||||||
|
.isEqualTo("2006-01-02 10:04:05.789 -0500");
|
||||||
|
assertThat(reformat("2006-01-02 15:04:05.789 +0100"))
|
||||||
|
.isEqualTo("2006-01-02 09:04:05.789 -0500");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseInvalidTimestamps() {
|
||||||
|
assertInvalid("2006-01-02-15:04:05.789000000");
|
||||||
|
assertInvalid("2006-01-02T15:04:05.789000000");
|
||||||
|
assertInvalid("15:04:05");
|
||||||
|
assertInvalid("15:04:05.999000000");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertInvalid(String input) {
|
||||||
|
try {
|
||||||
|
parseTimestamp(input);
|
||||||
|
assert_().fail("Expected IllegalArgumentException for: " + input);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// Expected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String reformat(String input) {
|
||||||
|
return format.format(parseTimestamp(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user