Introduce 'null object' timestamp and also parse it from JSON
In Gerrit, it is common practice to use empty Strings to unset a value in contexts where using null is not possible. We need something similar for timestamps as well. Inside of the Gerrit backend, we introduce TimeUtil.never() to indicate this value. For users of Gerrit's REST API, we introduce another mapping for convenience: an empty timestamp string in JSON will be mapped to the magic value. We deliberately don't add the reverse mapping as proper implementations in Gerrit should never set this value internally and hence it should never be returned to the user. Change-Id: I533b793227de4315893ee99750b20a442ff3c081
This commit is contained in:
@@ -44,7 +44,15 @@ class SqlTimestampDeserializer implements JsonDeserializer<Timestamp>, JsonSeria
|
||||
throw new JsonParseException("Expected string for timestamp type");
|
||||
}
|
||||
|
||||
return JavaSqlTimestampHelper.parseTimestamp(p.getAsString());
|
||||
String input = p.getAsString();
|
||||
if (input.trim().isEmpty()) {
|
||||
// Magic timestamp to indicate no timestamp. (-> null object)
|
||||
// Always create a new object as timestamps are mutable. Don't use TimeUtil.never() to not
|
||||
// introduce an undesired dependency.
|
||||
return new Timestamp(0);
|
||||
}
|
||||
|
||||
return JavaSqlTimestampHelper.parseTimestamp(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ java_library(
|
||||
srcs = glob(["**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//java/com/google/gerrit/common:annotations",
|
||||
"//lib:guava",
|
||||
"//lib/jgit/org.eclipse.jgit:jgit",
|
||||
],
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package com.google.gerrit.server.util.time;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.gerrit.common.UsedAt;
|
||||
import com.google.gerrit.common.UsedAt.Project;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.util.function.LongSupplier;
|
||||
@@ -43,6 +45,17 @@ public class TimeUtil {
|
||||
return new Timestamp(nowMs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the magic timestamp representing no specific time.
|
||||
*
|
||||
* <p>This "null object" is helpful in contexts where using {@code null} directly is not possible.
|
||||
*/
|
||||
@UsedAt(Project.PLUGIN_CHECKS)
|
||||
public static Timestamp never() {
|
||||
// Always create a new object as timestamps are mutable.
|
||||
return new Timestamp(0);
|
||||
}
|
||||
|
||||
public static Timestamp truncateToSecond(Timestamp t) {
|
||||
return new Timestamp((t.getTime() / 1000) * 1000);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ junit_tests(
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//java/com/google/gerrit/json",
|
||||
"//java/com/google/gerrit/server/util/time",
|
||||
"//java/com/google/gerrit/testing:gerrit-test-util",
|
||||
"//lib:gson",
|
||||
"//lib:guava",
|
||||
"//lib/truth",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2019 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.server.util.time.TimeUtil;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import java.sql.Timestamp;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SqlTimestampDeserializerTest {
|
||||
|
||||
private final SqlTimestampDeserializer deserializer = new SqlTimestampDeserializer();
|
||||
|
||||
@Test
|
||||
public void emptyStringIsDeserializedToMagicTimestamp() {
|
||||
Timestamp timestamp = deserializer.deserialize(new JsonPrimitive(""), Timestamp.class, null);
|
||||
assertThat(timestamp).isEqualTo(TimeUtil.never());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user