From ef9cad9259b7cd286b4b9feefe0f6a595304210d Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Thu, 2 Apr 2026 11:30:48 +0800 Subject: [PATCH] fix: Handle null paths in OpenAPI to prevent NPE Signed-off-by: Haotian Zhang <928016560@qq.com> --- .../contract/PolarisContractReporter.java | 12 ++++++++-- .../contract/PolarisContractReporterTest.java | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java index 046f7202d..da480554f 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java @@ -114,7 +114,7 @@ public class PolarisContractReporter implements ApplicationListener interfaceDescriptorList = getInterfaceDescriptorFromSwagger(openAPI); request.setInterfaceDescriptors(interfaceDescriptorList); - if (StringUtils.isNotBlank(contextPath)) { + if (StringUtils.isNotBlank(contextPath) && openAPI.getPaths() != null) { Paths newPaths = new Paths(); for (Map.Entry entry : openAPI.getPaths().entrySet()) { newPaths.addPathItem(contextPath + entry.getKey(), entry.getValue()); @@ -154,6 +154,9 @@ public class PolarisContractReporter implements ApplicationListener getInterfaceDescriptorFromSwagger(OpenAPI openAPI) { List interfaceDescriptorList = new ArrayList<>(); Paths paths = openAPI.getPaths(); + if (paths == null) { + return interfaceDescriptorList; + } for (Map.Entry p : paths.entrySet()) { PathItem path = p.getValue(); Map operationMap = getOperationMapFromPath(path); @@ -162,7 +165,12 @@ public class PolarisContractReporter implements ApplicationListener o : operationMap.entrySet()) { InterfaceDescriptor interfaceDescriptor = new InterfaceDescriptor(); - interfaceDescriptor.setPath(contextPath + p.getKey()); + if (StringUtils.isNotBlank(contextPath)) { + interfaceDescriptor.setPath(contextPath + p.getKey()); + } + else { + interfaceDescriptor.setPath(p.getKey()); + } interfaceDescriptor.setMethod(o.getKey()); try { String jsonValue; diff --git a/spring-cloud-starter-tencent-polaris-contract/src/test/java/com/tencent/cloud/polaris/contract/PolarisContractReporterTest.java b/spring-cloud-starter-tencent-polaris-contract/src/test/java/com/tencent/cloud/polaris/contract/PolarisContractReporterTest.java index dccec37d3..d0d27ea09 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/test/java/com/tencent/cloud/polaris/contract/PolarisContractReporterTest.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/test/java/com/tencent/cloud/polaris/contract/PolarisContractReporterTest.java @@ -161,4 +161,26 @@ class PolarisContractReporterTest { .extracting(InterfaceDescriptor::getPath) .allMatch(path -> path.startsWith("/api/")); } + + /** + * Test that null paths in OpenAPI returns an empty descriptor list without NPE. + * When OpenAPI.getPaths() returns null, the method should gracefully return + * an empty list instead of throwing NullPointerException. + */ + @DisplayName("null paths in OpenAPI returns empty descriptor list") + @Test + void testNullPathsReturnsEmptyList() throws Exception { + // Arrange + PolarisContractReporter reporter = new PolarisContractReporter( + null, null, polarisContractProperties, providerAPI, + polarisDiscoveryProperties, springdocObjectMapperProvider, "/context"); + OpenAPI openAPI = new OpenAPI(); + // Do not call openAPI.setPaths(), so getPaths() returns null + + // Act + List descriptors = invokeGetInterfaceDescriptorFromSwagger(reporter, openAPI); + + // Assert + assertThat(descriptors).isNotNull().isEmpty(); + } }