Filter out JsonNull values in artifacts meta-data fields

Consider fields having a null value as inexistent, so that
they are automatically filtered out in the list of plugins
displayed by the plugin manager.

Bug: Issue 290658426
Change-Id: I45d8a613a0ced6610d226069a8f1a5212345414e
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java b/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java
index 3ea2af0..9dd1b6d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/gson/SmartJson.java
@@ -52,7 +52,8 @@
   public Optional<SmartJson> getOptional(String fieldName) {
     if (jsonElem != null
         && !jsonElem.isJsonNull()
-        && jsonElem.getAsJsonObject().get(fieldName) != null) {
+        && jsonElem.getAsJsonObject().get(fieldName) != null
+        && !jsonElem.getAsJsonObject().get(fieldName).isJsonNull()) {
       return Optional.of(SmartJson.of(jsonElem.getAsJsonObject().get(fieldName)));
     }
     return Optional.empty();
diff --git a/src/test/java/com/googlesource/gerrit/plugins/manager/gson/SmartJsonTest.java b/src/test/java/com/googlesource/gerrit/plugins/manager/gson/SmartJsonTest.java
new file mode 100644
index 0000000..d979981
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/manager/gson/SmartJsonTest.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 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.googlesource.gerrit.plugins.manager.gson;
+
+import static com.google.common.truth.OptionalSubject.optionals;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.google.common.truth.OptionalSubject;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SmartJsonTest {
+
+  private Gson gson;
+
+  @Before
+  public void setup() {
+    gson = new Gson();
+  }
+
+  @Test
+  public void shouldReturnEmptyForInexistentField() {
+    Optional<String> fooField = parseAsSmartJson("{}").getOptionalString("foofield");
+    assertThatOptional(fooField).isEmpty();
+  }
+
+  @Test
+  public void shouldReturnPresentValueForField() {
+    String fieldValue = "foovalue";
+    Optional<String> fooField =
+        parseAsSmartJson(String.format("{ \"foofield\": \"%s\"}", fieldValue))
+            .getOptionalString("foofield");
+    assertThatOptional(fooField).hasValue(fieldValue);
+  }
+
+  @Test
+  public void shouldReturnEmptyForFieldWithNullValue() {
+    Optional<String> fooField =
+        parseAsSmartJson("{ \"foofield\": null }").getOptionalString("foofield");
+    assertThatOptional(fooField).isEmpty();
+  }
+
+  private OptionalSubject assertThatOptional(Optional<String> field) {
+    return assertWithMessage("Optional<field>").about(optionals()).that(field);
+  }
+
+  private SmartJson parseAsSmartJson(String jsonAsString) {
+    return SmartJson.of(gson.fromJson(jsonAsString, JsonElement.class));
+  }
+}