EventGsonProvider: Register generic event serializer adapter

This custom serializer is only needed if instance is created in one
plugin, but the serialization takes place in another plugin. If the
class is reachable from the same classpath loader where the event
instance was instantiated, then it will work without this change.

This will simplify multi-site plugin setup, that is using inter-plugin
communication:

o multi-site plugin, that is using events-broker
o events-broker libModule, that provides BrokerApi abstraction
o events-kafka plugin, that is using Apache Kafka event streaming
  backend and is used by events-broker's DynamicItem
o events-gcloud-pubsub plugin, that is using GCloud's PubSub event streaming
  backend and is used by events-broker's DynamicItem
o events-aws-kinesis plugin, that is using AWS's Kinesis event streaming
  backend and is used by events-broker's DynamicItem

This change would allow us to drop EventGsonProvider fork in multi-site
plugin.

Change-Id: I7dc6e6a859152ee3e30a90075ddd34814720eba1
(cherry picked from commit 89f7a75dbaebdb7bba92ae1f11c7505ec80dcfc2)
diff --git a/java/com/google/gerrit/server/events/EventGsonProvider.java b/java/com/google/gerrit/server/events/EventGsonProvider.java
index 72cf7be..27be2f3 100644
--- a/java/com/google/gerrit/server/events/EventGsonProvider.java
+++ b/java/com/google/gerrit/server/events/EventGsonProvider.java
@@ -25,6 +25,7 @@
   @Override
   public Gson get() {
     return new GsonBuilder()
+        .registerTypeAdapter(Event.class, new EventSerializer())
         .registerTypeAdapter(Event.class, new EventDeserializer())
         .registerTypeAdapter(Supplier.class, new SupplierSerializer())
         .registerTypeAdapter(Supplier.class, new SupplierDeserializer())
diff --git a/java/com/google/gerrit/server/events/EventSerializer.java b/java/com/google/gerrit/server/events/EventSerializer.java
new file mode 100644
index 0000000..7322ef3
--- /dev/null
+++ b/java/com/google/gerrit/server/events/EventSerializer.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2021 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.server.events;
+
+import com.google.gerrit.common.UsedAt;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import java.lang.reflect.Type;
+
+@UsedAt(UsedAt.Project.PLUGIN_MULTI_SITE)
+class EventSerializer implements JsonSerializer<Event> {
+  @Override
+  public JsonElement serialize(Event src, Type typeOfSrc, JsonSerializationContext context) {
+    String type = src.getType();
+
+    Class<?> cls = EventTypes.getClass(type);
+    if (cls == null) {
+      throw new JsonParseException("Unknown event type: " + type);
+    }
+
+    return context.serialize(src, cls);
+  }
+}
diff --git a/javatests/com/google/gerrit/server/events/EventJsonTest.java b/javatests/com/google/gerrit/server/events/EventJsonTest.java
index 9ca60ca..8e4f436 100644
--- a/javatests/com/google/gerrit/server/events/EventJsonTest.java
+++ b/javatests/com/google/gerrit/server/events/EventJsonTest.java
@@ -78,6 +78,19 @@
   }
 
   @Test
+  public void customEventSimulateClassloaderIssue() {
+    EventTypes.register(CustomEvent.TYPE, CustomEvent.class);
+    CustomEvent event = new CustomEvent();
+    event.customField = "customValue";
+    // Need to serialise using the Event interface instead of json.getClass()
+    // for simulating the serialisation of an object owned by another class loader
+    String json = gson.toJson(event, Event.class);
+    CustomEvent resullt = gson.fromJson(json, CustomEvent.class);
+    assertThat(resullt.type).isEqualTo(CustomEvent.TYPE);
+    assertThat(resullt.customField).isEqualTo(event.customField);
+  }
+
+  @Test
   public void refUpdatedEvent() {
     RefUpdatedEvent event = new RefUpdatedEvent();