Explorar el Código

refactor(exam-sprint): 收紧报告映射防御逻辑

金逸霄 hace 2 semanas
padre
commit
f4b7ff5e2a

+ 1 - 27
abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/DefaultExamSprintReportApplicationService.java

@@ -606,14 +606,6 @@ public class DefaultExamSprintReportApplicationService implements ExamSprintRepo
         }
     }
 
-    private JsonNode requireObjectField(JsonNode objectNode, String fieldName) {
-        JsonNode field = objectNode.get(fieldName);
-        if (field == null || !field.isObject()) {
-            throw validationException(ACHIEVEMENT_REPORT_NAME, "字段 " + fieldName + " 必须为对象");
-        }
-        return field;
-    }
-
     private void requireOptionalBooleanField(JsonNode objectNode, String fieldName) {
         JsonNode field = objectNode.get(fieldName);
         if (field != null && !field.isNull() && !field.isBoolean()) {
@@ -646,29 +638,11 @@ public class DefaultExamSprintReportApplicationService implements ExamSprintRepo
         }
     }
 
-    private void requireTextualArrayField(JsonNode objectNode, String fieldPath) {
-        JsonNode field = objectNode.get(leafFieldName(fieldPath));
-        if (field == null || !field.isArray()) {
-            throw validationException(ACHIEVEMENT_REPORT_NAME, "字段 " + fieldPath + " 必须为字符串数组");
-        }
-        int index = 0;
-        for (JsonNode element : field) {
-            if (!element.isTextual()) {
-                throw validationException(ACHIEVEMENT_REPORT_NAME, "字段 " + fieldPath + "[" + index + "] 必须为字符串");
-            }
-            index++;
-        }
-    }
-
     private <T> T readPayload(JsonNode payload, Class<T> payloadType, String reportName) {
         requireObjectPayload(payload, reportName);
 
         try {
-            T reportPayload = objectMapper.treeToValue(payload, payloadType);
-            if (reportPayload == null) {
-                throw validationException(reportName, "payload 不能为空");
-            }
-            return reportPayload;
+            return objectMapper.treeToValue(payload, payloadType);
         } catch (JsonProcessingException | IllegalArgumentException exception) {
             throw validationException(reportName, "payload 无法解析为报告请求结构,请检查字段类型和结构");
         }

+ 5 - 7
abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportContractMapper.java

@@ -5,19 +5,19 @@ import cn.yunzhixue.ability.center.examsprint.contracts.report.ExamSprintReportT
 import cn.yunzhixue.ability.center.examsprint.domain.report.ReportGenerationStatus;
 import cn.yunzhixue.ability.center.examsprint.domain.report.ReportType;
 
+import java.util.Objects;
+
 final class ExamSprintReportContractMapper {
 
     private ExamSprintReportContractMapper() {
     }
 
     static ExamSprintReportGenerationStatus toContractStatus(ReportGenerationStatus status) {
-        return status == null ? null : ExamSprintReportGenerationStatus.valueOf(status.name());
+        return ExamSprintReportGenerationStatus.valueOf(Objects.requireNonNull(status, "status").name());
     }
 
     static ExamSprintReportType toContractReportType(ReportType reportType) {
-        if (reportType == null) {
-            return null;
-        }
+        Objects.requireNonNull(reportType, "reportType");
         return switch (reportType) {
             case OUTLOOK -> ExamSprintReportType.OUTLOOK;
             case ACHIEVEMENT -> ExamSprintReportType.ACHIEVEMENT;
@@ -25,9 +25,7 @@ final class ExamSprintReportContractMapper {
     }
 
     static ReportType toDomainReportType(ExamSprintReportType reportType) {
-        if (reportType == null) {
-            return null;
-        }
+        Objects.requireNonNull(reportType, "reportType");
         return switch (reportType) {
             case OUTLOOK -> ReportType.OUTLOOK;
             case ACHIEVEMENT -> ReportType.ACHIEVEMENT;

+ 12 - 5
abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportContractMapperTest.java

@@ -6,6 +6,7 @@ import cn.yunzhixue.ability.center.examsprint.domain.report.ReportType;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 class ExamSprintReportContractMapperTest {
 
@@ -18,8 +19,10 @@ class ExamSprintReportContractMapperTest {
     }
 
     @Test
-    void mapsNullGenerationStatusToNull() {
-        assertThat(ExamSprintReportContractMapper.toContractStatus(null)).isNull();
+    void rejectsNullGenerationStatus() {
+        assertThatThrownBy(() -> ExamSprintReportContractMapper.toContractStatus(null))
+                .isInstanceOf(NullPointerException.class)
+                .hasMessageContaining("status");
     }
 
     @Test
@@ -55,8 +58,12 @@ class ExamSprintReportContractMapperTest {
     }
 
     @Test
-    void mapsNullReportTypeToNullInBothDirections() {
-        assertThat(ExamSprintReportContractMapper.toContractReportType(null)).isNull();
-        assertThat(ExamSprintReportContractMapper.toDomainReportType(null)).isNull();
+    void rejectsNullReportTypeInBothDirections() {
+        assertThatThrownBy(() -> ExamSprintReportContractMapper.toContractReportType(null))
+                .isInstanceOf(NullPointerException.class)
+                .hasMessageContaining("reportType");
+        assertThatThrownBy(() -> ExamSprintReportContractMapper.toDomainReportType(null))
+                .isInstanceOf(NullPointerException.class)
+                .hasMessageContaining("reportType");
     }
 }