Repository: apache/gravitino (Java)

Issue:
[Improvement] Add precondition to PartitionStatisticsListResponse.java to validating each partition statistic is not null preventing NPE
### What would you like to be improved?

In common/src/main/java/org/apache/gravitino/dto/responses/PartitionStatisticsListResponse.java check if each partition statistic is not null.

Here's a test to help:
```
  @Test
  void testPartitionStatisticsListResponseNullElement() {
    AuditDTO audit = AuditDTO.builder().withCreator("user1").withCreateTime(Instant.now()).build();
    StatisticDTO statistic =
        StatisticDTO.builder().withName("stat").withAudit(audit).withValue(Optional.empty()).build();
    PartitionStatisticsDTO valid =
        PartitionStatisticsDTO.of("p1", new StatisticDTO[] {statistic});
    PartitionStatisticsDTO[] stats = new PartitionStatisticsDTO[] {valid, null};
    PartitionStatisticsListResponse response = new PartitionStatisticsListResponse(stats);
    assertThrows(IllegalArgumentException.class, response::validate);
  }
```

### How should we improve?

Add precondition


Discussion:
Hi @justinmclean
Can I take this issue?
Sure, if you have any questions just ask.



Patch:
diff --git a/common/src/main/java/org/apache/gravitino/dto/responses/PartitionStatisticsListResponse.java b/common/src/main/java/org/apache/gravitino/dto/responses/PartitionStatisticsListResponse.java
index d22240bf0ce..5b3be14596f 100644
--- a/common/src/main/java/org/apache/gravitino/dto/responses/PartitionStatisticsListResponse.java
+++ b/common/src/main/java/org/apache/gravitino/dto/responses/PartitionStatisticsListResponse.java
@@ -63,6 +63,8 @@ public void validate() throws IllegalArgumentException {
     Preconditions.checkArgument(
         partitionStatistics != null, "\"partitionStatistics\" must not be null");
     for (PartitionStatisticsDTO partitionStat : partitionStatistics) {
+      Preconditions.checkArgument(
+          partitionStat != null, "Each partition statistic must not be null");
       partitionStat.validate();
     }
   }


Test patch:
diff --git a/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java b/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
index 781f5ef4492..0c66109fcaf 100644
--- a/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
+++ b/common/src/test/java/org/apache/gravitino/dto/responses/TestResponses.java
@@ -30,6 +30,7 @@
 import com.google.common.collect.Lists;
 import java.time.Instant;
 import java.util.Map;
+import java.util.Optional;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.authorization.Privileges;
@@ -48,6 +49,8 @@
 import org.apache.gravitino.dto.rel.ColumnDTO;
 import org.apache.gravitino.dto.rel.TableDTO;
 import org.apache.gravitino.dto.rel.partitioning.Partitioning;
+import org.apache.gravitino.dto.stats.PartitionStatisticsDTO;
+import org.apache.gravitino.dto.stats.StatisticDTO;
 import org.apache.gravitino.dto.tag.TagDTO;
 import org.apache.gravitino.dto.util.DTOConverters;
 import org.apache.gravitino.json.JsonUtils;
@@ -510,4 +513,19 @@ void testModelVersionResponse() throws JsonProcessingException {
     ModelVersionResponse response1 = new ModelVersionResponse();
     assertThrows(IllegalArgumentException.class, response1::validate);
   }
+
+  @Test
+  void testPartitionStatisticsListResponseNullElement() {
+    AuditDTO audit = AuditDTO.builder().withCreator("user1").withCreateTime(Instant.now()).build();
+    StatisticDTO statistic =
+        StatisticDTO.builder()
+            .withName("stat")
+            .withAudit(audit)
+            .withValue(Optional.empty())
+            .build();
+    PartitionStatisticsDTO valid = PartitionStatisticsDTO.of("p1", new StatisticDTO[] {statistic});
+    PartitionStatisticsDTO[] stats = new PartitionStatisticsDTO[] {valid, null};
+    PartitionStatisticsListResponse response = new PartitionStatisticsListResponse(stats);
+    assertThrows(IllegalArgumentException.class, response::validate);
+  }
 }