Skip to content

feat(openapi): introduce non-invasive OpenApiModelConverters for generated model types#5470

Merged
hezhangjian merged 1 commit into
apolloconfig:masterfrom
tacklequestions:pr/a03-openapi-converters
Oct 3, 2025
Merged

feat(openapi): introduce non-invasive OpenApiModelConverters for generated model types#5470
hezhangjian merged 1 commit into
apolloconfig:masterfrom
tacklequestions:pr/a03-openapi-converters

Conversation

@tacklequestions

@tacklequestions tacklequestions commented Sep 25, 2025

Copy link
Copy Markdown
Member

What's the purpose of this PR

Introduce a non-invasive OpenApiModelConverters utility to convert between portal DTO/BO/entities and generated com.ctrip.framework.apollo.openapi.model.* types, enabling subsequent domain refactors to use generated models without
modifying existing OpenApiBeanUtils.

Which issue(s) this PR fixes:

Fixes #5462

Brief changelog

  • Add new class: apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (no existing files modified).
  • Provide converters for:
    • App/AppNamespace: App <-> OpenAppDTO, AppNamespace <-> OpenAppNamespaceDTO, list helpers.
    • Item: ItemDTO <-> OpenItemDTO, batch helpers.
    • Namespace: NamespaceBO/DTO -> OpenNamespaceDTO, NamespaceLockDTO -> OpenNamespaceLockDTO, OpenNamespaceTextModel -> NamespaceTextModel, OpenNamespaceSyncModel -> NamespaceSyncModel, NamespaceIdentifier <->
      OpenNamespaceIdentifier.
    • Cluster: ClusterDTO <-> OpenClusterDTO.
    • Instance: InstanceDTO -> OpenInstanceDTO (and batch).
    • Release: ReleaseDTO -> OpenReleaseDTO (config map), ReleaseBO -> OpenReleaseBO (items mapped), batch helper.
    • Gray release rule: GrayReleaseRuleDTO <-> OpenGrayReleaseRuleDTO (including rule items).
    • Organization: Organization -> OpenOrganizationDto (and batch).
    • Env/Cluster info: EnvClusterInfo -> OpenEnvClusterInfo (and batch).
    • Item diffs/change sets: ItemChangeSets/ItemDiffs -> OpenItemChangeSets/OpenItemDiffs.
  • Zero runtime behavior change; serves as shared foundation for next PRs to avoid cross-PR conflicts.

Summary by CodeRabbit

  • New Features
    • Expanded OpenAPI compatibility with comprehensive model conversions between portal data and OpenAPI formats.
    • Supports single and bulk transformations for core entities (e.g., items, apps, releases, namespaces, clusters, organizations, instances, environment/cluster info).
    • Improves consistency of API request/response payloads, including namespace identifiers, text, locks, sync models, and item change/diff structures.
    • Enhanced handling of empty/null inputs for more robust integrations.

@coderabbitai

coderabbitai Bot commented Sep 25, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Introduces a new final utility class, OpenApiModelConverters, providing static bidirectional converters between portal domain objects and OpenAPI-generated DTOs. It covers single-object and collection mappings for items, apps, namespaces, releases, rules, clusters, organizations, instances, env-cluster info, and item change/diff structures, using Gson and BeanUtils.

Changes

Cohort / File(s) Summary
OpenAPI model converters utility
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java
Adds a non-instantiable utility with numerous public static methods to convert between internal portal models and OpenAPI-generated models (Open* DTOs), including list and nested structures; uses Gson for config JSON parsing and BeanUtils/Preconditions/CollectionUtils for mapping and validation.

Sequence Diagram(s)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested labels

size:M

Suggested reviewers

  • hezhangjian

Poem

I hop through fields of DTOs so bright,
Mapping beans by day and night.
With Gson crumbs and Utils light,
I bridge two worlds in tidy flight.
Tap-tap keys—converters right!
A fluffy merge, ears upright. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning The PR only adds a converter utility without altering any API endpoints, URLs, HTTP methods, parameter annotations, response wrappers, pagination validation, or permission error handling required by issue #5462. Revise the PR to implement or incorporate the RESTful API design, DTO usage in controllers, unified response wrappers, standardized pagination validation, and permission exception handling as specified by issue #5462, or unlink this converter work from the refactoring issue.
Out of Scope Changes Check ⚠️ Warning The introduction of OpenApiModelConverters is unrelated to the API design refactoring objectives of issue #5462, which focus on controller-level changes; the new converter class does not align with any specified goals and constitutes an out-of-scope addition. Consider separating the converter utilities into a dedicated PR or issue focused on model mapping and link this work appropriately, ensuring the API refactoring PR only includes changes related to endpoint design and response handling.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit's high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the addition of non-invasive OpenApiModelConverters for generated model types, matching the primary change of introducing a new converter utility class without modifying existing files.
Docstring Coverage ✅ Passed Docstring coverage is 97.22% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca298c0 and 8043e61.

📒 Files selected for processing (1)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (14)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/ClusterDTO.java (1)
  • ClusterDTO (23-80)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/GrayReleaseRuleDTO.java (1)
  • GrayReleaseRuleDTO (24-81)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/GrayReleaseRuleItemDTO.java (1)
  • GrayReleaseRuleItemDTO (28-85)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/ItemDTO.java (1)
  • ItemDTO (20-103)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/NamespaceDTO.java (1)
  • NamespaceDTO (22-66)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java (1)
  • BeanUtils (37-255)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/KVEntity.java (1)
  • KVEntity (19-44)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ItemBO.java (1)
  • ItemBO (21-76)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/NamespaceBO.java (1)
  • NamespaceBO (23-103)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseBO.java (1)
  • ReleaseBO (24-46)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceSyncModel.java (1)
  • NamespaceSyncModel (26-70)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceTextModel.java (1)
  • NamespaceTextModel (24-104)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/EnvClusterInfo.java (1)
  • EnvClusterInfo (24-48)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/NamespaceIdentifier.java (1)
  • NamespaceIdentifier (23-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build (8)
🔇 Additional comments (10)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (10)

73-84: LGTM!

The utility class structure follows best practices: final class with private constructor prevents instantiation, and the static Gson instance is thread-safe. The TypeToken correctly preserves generic type information for configuration parsing.


86-114: LGTM!

The Item conversion methods correctly use Preconditions for null validation, BeanUtils.transform for object mapping, and handle empty collections appropriately. The stream-based batch conversions are clean and efficient.


116-142: LGTM!

The App/AppNamespace conversion methods follow the same solid pattern: null validation with Preconditions, object mapping with BeanUtils.transform, and proper empty collection handling.


154-180: LGTM!

The Release BO conversion correctly handles the type mismatch between portal and OpenAPI KVEntity classes by manually mapping each item. The empty collection checks are appropriate, and the batch conversion is clean.


182-225: LGTM!

The Namespace conversion methods correctly handle nested structures. The fromNamespaceBO method properly transforms the base info and nested item list, while fromNamespaceLockDTO appropriately handles the nullable lock case by setting isLocked to false.


226-290: LGTM!

The namespace model conversions properly handle nested structures and type conversions. The toNamespaceSyncModel correctly processes optional nested lists, and fromNamespaceIdentifier appropriately converts the Env enum to a string representation.


292-323: LGTM!

The gray release rule conversions now correctly guard against null collections. Lines 308, 311-316 properly handle nullable ruleItems, clientIpList, and clientLabelList by checking for null/empty before processing, addressing the issues raised in previous reviews.


325-337: LGTM!

The Cluster conversions are straightforward bidirectional mappings with proper null validation.


339-369: LGTM!

The Organization and Instance conversions follow the established pattern with proper null validation, empty collection handling, and efficient stream-based batch processing.


371-425: LGTM!

The EnvClusterInfo and item diff conversions properly handle nested structures. The fromItemChangeSets and fromItemDiffs methods appropriately check each nested collection/object for null before conversion, ensuring safe transformation of complex hierarchical data.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels Sep 25, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apollo-portal/pom.xml (1)

30-168: Do not fetch the OpenAPI spec from a mutable remote URL at build time

Pointing <apollo.openapi.spec.url> to https://raw.githubusercontent.com/... makes every Maven build depend on external network access and an uncontrolled file that can change (or disappear) at any moment. That’s a supply-chain and reproducibility problem, and it will break offline or air‑gapped builds.

Vendor the OpenAPI document inside this repository (or publish it to an internal, versioned artifact) and reference the local path/property instead. That way the generated sources stay deterministic and the build remains self-contained.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa881a and 341746c.

📒 Files selected for processing (4)
  • apollo-portal/pom.xml (4 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (1 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (5 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
  • SpringSecurityUserInfoHolder (33-121)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/UserInfo.java (1)
  • UserInfo (19-79)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (8)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java (1)
  • BeanUtils (37-255)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ItemBO.java (1)
  • ItemBO (21-76)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/NamespaceBO.java (1)
  • NamespaceBO (23-103)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseBO.java (1)
  • ReleaseBO (24-46)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceSyncModel.java (1)
  • NamespaceSyncModel (26-70)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceTextModel.java (1)
  • NamespaceTextModel (24-104)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/EnvClusterInfo.java (1)
  • EnvClusterInfo (24-48)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/NamespaceIdentifier.java (1)
  • NamespaceIdentifier (23-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build (8)
🔇 Additional comments (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (1)

112-114: Confirm ConsumerService presence for auth/ldap contexts.

With the new constructor dependency, the springSecurityUserInfoHolder bean will now fail to instantiate if no ConsumerService bean is registered when the auth or ldap profile is active. Please double-check that those application contexts (including relevant tests) always expose ConsumerService; otherwise we’ll hit a startup NoSuchBeanDefinitionException.

Also applies to: 216-218

import org.springframework.util.CollectionUtils;

import java.lang.reflect.Type;
import java.util.*;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using the * symbol when importing packages

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already fixed that issue, thanks for reviewing!

return namespaceBOs.stream().map(OpenApiModelConverters::fromNamespaceBO).collect(Collectors.toCollection(LinkedList::new));
}

public static OpenNamespaceLockDTO fromNamespaceLockDTO(String namespaceName, NamespaceLockDTO namespaceLock) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The namespaces LockDTO and Opennamespaces LockDTO structures are inconsistent, which may result in compatibility issues

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for reviewing but this is a method originally defined in OpenApiBeanUtils and has been verified. All such methods are now annotated with "originally defined in OpenApiBeanUtils"

@tacklequestions
tacklequestions force-pushed the pr/a03-openapi-converters branch from 341746c to bacf40a Compare October 1, 2025 06:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (2)

249-256: Critical: Fix NPE when gray release rule items are null.

openGrayReleaseRuleDTO.getRuleItems() returns null when clients omit rule items (valid for "clear all rules" scenarios). Line 249 directly wraps this in new HashSet<>(), causing a NullPointerException that will fail all such requests with HTTP 500.

Apply this fix to handle null/empty rule items:

-    Set<OpenGrayReleaseRuleItemDTO> openGrayReleaseRuleItemDTOSet = new HashSet<>(openGrayReleaseRuleDTO.getRuleItems());
-    openGrayReleaseRuleItemDTOSet.forEach(openGrayReleaseRuleItemDTO -> {
+    Set<OpenGrayReleaseRuleItemDTO> openGrayReleaseRuleItemDTOSet = openGrayReleaseRuleDTO.getRuleItems();
+    if (!CollectionUtils.isEmpty(openGrayReleaseRuleItemDTOSet)) {
+      openGrayReleaseRuleItemDTOSet.forEach(openGrayReleaseRuleItemDTO -> {
-      String clientAppId = openGrayReleaseRuleItemDTO.getClientAppId();
-      Set<String> clientIpList = new HashSet<>(openGrayReleaseRuleItemDTO.getClientIpList());
-      Set<String> clientLabelList = new HashSet<>(openGrayReleaseRuleItemDTO.getClientLabelList());
-      GrayReleaseRuleItemDTO ruleItem = new GrayReleaseRuleItemDTO(clientAppId, clientIpList, clientLabelList);
-      grayReleaseRuleDTO.addRuleItem(ruleItem);
-    });
+        String clientAppId = openGrayReleaseRuleItemDTO.getClientAppId();
+        Set<String> clientIpList = new HashSet<>(openGrayReleaseRuleItemDTO.getClientIpList());
+        Set<String> clientLabelList = new HashSet<>(openGrayReleaseRuleItemDTO.getClientLabelList());
+        GrayReleaseRuleItemDTO ruleItem = new GrayReleaseRuleItemDTO(clientAppId, clientIpList, clientLabelList);
+        grayReleaseRuleDTO.addRuleItem(ruleItem);
+      });
+    }

38-38: Replace wildcard import with explicit imports.

Wildcard imports reduce code clarity and can cause unexpected compilation issues when new types are added to imported packages.

Based on coding guidelines

Replace line 38 with explicit imports:

-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
🧹 Nitpick comments (2)
apollo-portal/pom.xml (1)

163-163: Reconsider skipping OpenAPI spec validation.

Setting skipValidateSpec to true bypasses validation of the OpenAPI specification, which could allow malformed specs to generate broken code that only fails at runtime.

Unless there's a specific compatibility issue with the validator, remove this line to enable validation:

-<skipValidateSpec>true</skipValidateSpec>

If validation must be skipped due to known spec issues, please document the reason in a comment.

apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (1)

45-50: Consider making utility class constructor private with clear message.

The private constructor prevents instantiation but could benefit from an explicit assertion to fail fast if instantiated via reflection.

-private OpenApiModelConverters() {}
+private OpenApiModelConverters() {
+  throw new AssertionError("Utility class should not be instantiated");
+}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 341746c and bacf40a.

📒 Files selected for processing (8)
  • apollo-portal/pom.xml (4 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/filter/ConsumerAuthenticationFilter.java (4 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/service/ConsumerService.java (2 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/ConsumerAuthUtil.java (4 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (1 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (5 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1 hunks)
  • pom.xml (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
  • SpringSecurityUserInfoHolder (37-125)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/UserInfo.java (1)
  • UserInfo (19-79)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (8)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java (1)
  • BeanUtils (37-255)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ItemBO.java (1)
  • ItemBO (21-76)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/NamespaceBO.java (1)
  • NamespaceBO (23-103)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseBO.java (1)
  • ReleaseBO (24-46)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceSyncModel.java (1)
  • NamespaceSyncModel (26-70)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceTextModel.java (1)
  • NamespaceTextModel (24-104)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/EnvClusterInfo.java (1)
  • EnvClusterInfo (24-48)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/NamespaceIdentifier.java (1)
  • NamespaceIdentifier (23-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build (8)
🔇 Additional comments (3)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (3)

160-170: Document namespace lock structure mapping decision.

As noted in past reviews, NamespaceLockDTO and OpenNamespaceLockDTO have inconsistent structures. The conversion at line 160-169 manually constructs the OpenAPI model rather than using BeanUtils.transform, suggesting intentional structural differences.

Please clarify:

  1. Are these structural differences documented in the OpenAPI spec design?
  2. Should this mapping logic be unit tested to prevent regression?

Consider adding a comment explaining why manual mapping is necessary:

// Manual mapping required: OpenNamespaceLockDTO uses isLocked boolean + namespaceName,
// while NamespaceLockDTO uses presence/absence pattern with dataChangeCreatedBy
public static OpenNamespaceLockDTO fromNamespaceLockDTO(String namespaceName, NamespaceLockDTO namespaceLock) {

47-48: Thread-safe Gson instance is appropriate for utility class.

The static GSON instance is immutable and thread-safe by default, making it suitable for concurrent use across all conversion methods.


53-76: Item conversion methods handle null inputs correctly.

The Preconditions.checkArgument guards on single-item conversions and CollectionUtils.isEmpty checks on batch operations provide appropriate null safety. The use of streams for batch conversions is clean and efficient.

Comment thread apollo-portal/pom.xml
Comment thread pom.xml
<common-lang3.version>3.18.0</common-lang3.version>
<gson.version>2.10.1</gson.version>
<guava.version>32.0.0-jre</guava.version>
<jackson-databind-nullable.version>0.2.7</jackson-databind-nullable.version>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify dependency versions are current and secure.

The added OpenAPI-related dependencies should be checked for:

  • Whether these are the latest stable versions
  • Any known security vulnerabilities

Please run the following script to check the latest versions and security advisories:

Also applies to: 83-84, 208-222


🏁 Script executed:

#!/bin/bash
# Check latest versions from Maven Central and security advisories

echo "=== Checking jackson-databind-nullable ==="
curl -s "https://search.maven.org/solrsearch/select?q=g:org.openapitools+AND+a:jackson-databind-nullable&rows=1&wt=json" | jq -r '.response.docs[0].latestVersion'

echo "=== Checking swagger-annotations ==="
curl -s "https://search.maven.org/solrsearch/select?q=g:io.swagger.core.v3+AND+a:swagger-annotations&rows=1&wt=json" | jq -r '.response.docs[0].latestVersion'

echo "=== Checking swagger-models ==="
curl -s "https://search.maven.org/solrsearch/select?q=g:io.swagger.core.v3+AND+a:swagger-models&rows=1&wt=json" | jq -r '.response.docs[0].latestVersion'

echo "=== Checking for security advisories ==="
gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: MAVEN, package: "org.openapitools:jackson-databind-nullable") {
    nodes {
      advisory { summary severity publishedAt }
      vulnerableVersionRange
      firstPatchedVersion { identifier }
    }
  }
}'

gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: MAVEN, package: "io.swagger.core.v3:swagger-annotations") {
    nodes {
      advisory { summary severity publishedAt }
      vulnerableVersionRange
      firstPatchedVersion { identifier }
    }
  }
}'

gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: MAVEN, package: "io.swagger.core.v3:swagger-models") {
    nodes {
      advisory { summary severity publishedAt }
      vulnerableVersionRange
      firstPatchedVersion { identifier }
    }
  }
}'

Length of output: 371


Invalid dependency versions detected — update to actual latest.

  • <jackson-databind-nullable.version> is 0.2.7 but Maven Central’s latest is 0.2.6.
  • <swagger-annotations.version> and <swagger-models.version> are 2.2.37 but Maven Central’s latest are 2.2.31.
    Adjust to published versions or configure the repository that hosts these newer releases.
🤖 Prompt for AI Agents
In pom.xml around line 74, the declared dependency property
<jackson-databind-nullable.version> is set to 0.2.7 and swagger properties
<swagger-annotations.version> and <swagger-models.version> are set to 2.2.37
even though Maven Central shows latest published versions as 0.2.6 for
jackson-databind-nullable and 2.2.31 for the swagger artifacts; update those
version properties to the published versions (or add/configure the correct
repository that hosts the newer releases) so the POM references valid,
resolvable versions and rebuild to verify resolution.

@tacklequestions
tacklequestions force-pushed the pr/a03-openapi-converters branch 3 times, most recently from 182432e to ca298c0 Compare October 2, 2025 04:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (1)

146-152: Add error handling for JSON parsing.

Line 149 parses release.getConfigurations() without catching JsonSyntaxException. Malformed JSON from database corruption or manual edits will cause unexpected 500 errors.

Wrap the parsing with error handling:

 public static OpenReleaseDTO fromReleaseDTO(ReleaseDTO release) {
   Preconditions.checkArgument(release != null);
   OpenReleaseDTO openReleaseDTO = BeanUtils.transform(OpenReleaseDTO.class, release);
-  Map<String, String> configs = GSON.fromJson(release.getConfigurations(), TYPE);
-  openReleaseDTO.setConfigurations(configs);
+  try {
+    Map<String, String> configs = GSON.fromJson(release.getConfigurations(), TYPE);
+    openReleaseDTO.setConfigurations(configs);
+  } catch (com.google.gson.JsonSyntaxException e) {
+    throw new IllegalArgumentException("Invalid JSON in release configurations for release id: " + release.getId(), e);
+  }
   return openReleaseDTO;
 }
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)

102-108: Avoid breaking OpenAPI calls when the owner user is missing.

Lines 103-108 throw an IllegalStateException whenever userService.findByUserId(consumer.getOwnerName()) returns null. This turns a previously tolerable data gap (owner user not yet provisioned or already deleted) into a 500 for every OpenAPI call, contradicting the zero-behavior-change expectation. The legacy getUser() path simply returned a minimal UserInfo stub when the lookup missed, allowing downstream logic to keep working.

Preserve that behavior here: if the lookup fails, build the fallback UserInfo (with the owner's id) instead of throwing. That keeps OpenAPI usable while still logging the anomaly.

         UserInfo consumerUserInfo = userService.findByUserId(consumer.getOwnerName());
-        if (consumerUserInfo == null) {
-            logger.error("Consumer not found or incomplete, consumer={}", consumer.getOwnerName());
-            throw  new IllegalStateException("Consumer information is missing for owner of consumer " +
-                    consumer.getOwnerName());
-        }
-        return consumerUserInfo;
+        if (consumerUserInfo != null) {
+            return consumerUserInfo;
+        }
+
+        logger.warn("Consumer owner {} not found in portal user service, returning fallback UserInfo", consumer.getOwnerName());
+        UserInfo fallback = new UserInfo();
+        fallback.setUserId(consumer.getOwnerName());
+        return fallback;

Based on past review comments.

🧹 Nitpick comments (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)

79-81: Remove duplicate requestURI retrieval.

Line 80 retrieves requestURI but it's not used afterward. Line 81 recalculates the path from request.getRequestURI() again. Remove the unused variable.

-        HttpServletRequest request = attributes.getRequest();
-        String requestURI = request.getRequestURI();
-        String path = request.getRequestURI().substring(request.getContextPath().length());
+        HttpServletRequest request = attributes.getRequest();
+        String path = request.getRequestURI().substring(request.getContextPath().length());
+        String requestURI = request.getRequestURI();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f73767f and ca298c0.

📒 Files selected for processing (3)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (1 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (5 hunks)
  • apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/UserInfo.java (1)
  • UserInfo (19-79)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (14)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/ClusterDTO.java (1)
  • ClusterDTO (23-80)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/GrayReleaseRuleDTO.java (1)
  • GrayReleaseRuleDTO (24-81)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/GrayReleaseRuleItemDTO.java (1)
  • GrayReleaseRuleItemDTO (28-85)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/ItemDTO.java (1)
  • ItemDTO (20-103)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/dto/NamespaceDTO.java (1)
  • NamespaceDTO (22-66)
apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java (1)
  • BeanUtils (37-255)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/KVEntity.java (1)
  • KVEntity (19-44)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ItemBO.java (1)
  • ItemBO (21-76)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/NamespaceBO.java (1)
  • NamespaceBO (23-103)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/bo/ReleaseBO.java (1)
  • ReleaseBO (24-46)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceSyncModel.java (1)
  • NamespaceSyncModel (26-70)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/model/NamespaceTextModel.java (1)
  • NamespaceTextModel (24-104)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/EnvClusterInfo.java (1)
  • EnvClusterInfo (24-48)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/entity/vo/NamespaceIdentifier.java (1)
  • NamespaceIdentifier (23-76)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (1)
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (1)
  • SpringSecurityUserInfoHolder (37-124)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build (8)
🔇 Additional comments (15)
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiModelConverters.java (10)

86-114: LGTM!

The Item conversion methods are well-implemented with proper null checks, empty collection handling, and consistent use of BeanUtils for object mapping. The batch conversion methods correctly leverage stream operations.


116-142: LGTM!

The App and AppNamespace conversion methods are correctly implemented with proper null checks and consistent BeanUtils usage.


155-179: LGTM!

The fromReleaseBO and fromReleaseBOs methods correctly transform internal ReleaseBO objects to OpenAPI models, with proper null-safe collection handling for the KVEntity items.


182-290: LGTM!

The Namespace conversion methods are well-structured with comprehensive null safety. The manual field mapping in toNamespaceIdentifier and fromNamespaceIdentifier correctly handles the Env enum conversion, and the nested transformations (items, sync models) are properly delegated to their respective converters.


292-323: LGTM!

The gray release rule conversions correctly handle null rule items and nested IP/label lists with defensive checks at lines 308, 311-316. The past review concerns about NPE risks have been properly addressed.


325-337: LGTM!

The Cluster conversion methods are straightforward bidirectional transformations with proper null guards.


339-353: LGTM!

The Organization conversion methods follow the established pattern with proper null and empty collection handling.


355-369: LGTM!

The Instance conversion methods are correctly implemented following the established conversion patterns with appropriate defensive checks.


371-385: LGTM!

The Env/Cluster info conversion methods correctly transform the domain objects with proper null and empty collection handling.


387-425: LGTM!

The Item diffs and change sets conversion methods properly handle nested transformations with appropriate null checks for all optional fields (createItems, updateItems, deleteItems, namespace, diffs). The delegation to specialized converters maintains consistency across the utility class.

apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/springsecurity/SpringSecurityUserInfoHolder.java (3)

44-48: LGTM! Lazy wiring prevents circular dependency.

The @Lazy annotation on the ConsumerService parameter correctly breaks potential circular dependencies while preserving the ability to resolve consumer-based user info for OpenAPI requests.


50-68: LGTM! Two-stage resolution preserves backward compatibility.

The refactored getUser() correctly attempts consumer-based resolution for OpenAPI requests before falling back to Spring Security context, maintaining existing behavior for non-OpenAPI flows.


114-123: LGTM! Extracted method improves readability.

The getCurrentUsername() method correctly extracts the username from the Spring Security context, handling UserDetails, Principal, and fallback cases as before.

apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java (2)

22-22: LGTM! Import updates align with new dependencies.

The added ConsumerService import (line 22) and consolidated imports (lines 36, 46) correctly support the updated bean factory methods without introducing unnecessary dependencies.

Also applies to: 36-36, 46-46


101-102: LGTM! Bean wiring matches updated constructor.

Both springSecurityUserInfoHolder bean factories (lines 101-102 in SpringSecurityAuthAutoConfiguration and lines 205-206 in SpringSecurityLDAPAuthAutoConfiguration) correctly inject the @Lazy ConsumerService, matching the updated SpringSecurityUserInfoHolder constructor signature.

Also applies to: 205-206

…model types

Co-authored-by: arrow2020 <316166287@qq.com>
@tacklequestions
tacklequestions force-pushed the pr/a03-openapi-converters branch from ca298c0 to 8043e61 Compare October 3, 2025 04:51
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Oct 3, 2025
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Oct 3, 2025
@hezhangjian
hezhangjian merged commit 8c646fe into apolloconfig:master Oct 3, 2025
8 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 3, 2025
@nobodyiam nobodyiam added this to the 2.5.0 milestone Feb 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] 统一 Apollo-portal API 设计规范

4 participants