Align Project.NameKey serialization to gerrit core Since I96dbb4c38f2 Project.NameKey is serialized in stream events as: "project": "project-name" However high-availability plugin missed this feature and doesn't use custom JsonSerializer, so that the Project.NameKey is serialized in legacy form: "project": { "name" : "project-name" } Starting from gerrit release 3.1 this plugin migrated to custom ProjectNameKeyAdapter that was added in I242b51530a3. As a side effect, project name serialization was implicitly changed to new serialization form. This incompatibility can cause a problem in zero-downtime upgrade scenario, where the events created by gerrit 3.0 cannot be de-serialized by second node running gerrit 3.1. To rectify, install custom ProjectNameKeyAdapter, that is aware of skew of project name representation and could also understand legacy and new form of project name. Note, that the plugin own ProjectNameKeyAdapter class should be removed when this change is merged to stable-3.1 branch. The test class could be removed as well, because similar round trip serialization tests exist in gerrit core. Bug: Issue 13825 Change-Id: I73bd4df898d8b978f67e9ab27fe5bb5461a951fd
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/ProjectNameKeyAdapter.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/ProjectNameKeyAdapter.java new file mode 100644 index 0000000..8c00282 --- /dev/null +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/ProjectNameKeyAdapter.java
@@ -0,0 +1,44 @@ +// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.event; + +import com.google.gerrit.reviewdb.client.Project; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +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; + +public class ProjectNameKeyAdapter + implements JsonSerializer<Project.NameKey>, JsonDeserializer<Project.NameKey> { + @Override + public JsonElement serialize( + Project.NameKey project, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(project.get()); + } + + @Override + public Project.NameKey deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (json.isJsonObject()) { + return Project.nameKey(json.getAsJsonObject().get("name").getAsJsonPrimitive().getAsString()); + } + return Project.nameKey(json.getAsString()); + } +}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonProvider.java index e62cec2..36f0029 100644 --- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonProvider.java +++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonProvider.java
@@ -14,7 +14,9 @@ package com.ericsson.gerrit.plugins.highavailability.forwarder.rest; +import com.ericsson.gerrit.plugins.highavailability.event.ProjectNameKeyAdapter; import com.google.common.base.Supplier; +import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.events.Event; import com.google.gerrit.server.events.EventDeserializer; import com.google.gerrit.server.events.SupplierDeserializer; @@ -28,6 +30,7 @@ public Gson get() { return new GsonBuilder() .registerTypeAdapter(Event.class, new EventDeserializer()) + .registerTypeAdapter(Project.NameKey.class, new ProjectNameKeyAdapter()) .registerTypeAdapter(Supplier.class, new SupplierDeserializer()) .create(); }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/event/EventDeserializerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/event/EventDeserializerTest.java new file mode 100644 index 0000000..8e1b5eb --- /dev/null +++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/event/EventDeserializerTest.java
@@ -0,0 +1,42 @@ +// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.event; + +import static com.google.common.truth.Truth.assertThat; + +import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.GsonProvider; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gson.Gson; +import org.junit.Test; + +public class EventDeserializerTest { + private static final String LEGACY_PROJECT_KEY = "{\"name\": \"project\"}"; + + private static final String NEW_PROJECT_KEY = "\"project\""; + + private final Gson gson = new GsonProvider().get(); + + @Test + public void deserializePatchSetCreatedEventLegacyProjectKey() { + Project.NameKey n = gson.fromJson(LEGACY_PROJECT_KEY, Project.NameKey.class); + assertThat(n.get()).isEqualTo("project"); + } + + @Test + public void deserializePatchSetCreatedEventNewProjectKey() { + Project.NameKey n = gson.fromJson(NEW_PROJECT_KEY, Project.NameKey.class); + assertThat(n.get()).isEqualTo("project"); + } +}