Skip to content

<refactor>[core]: add immutable support for @GlobalProperty List fields#3501

Open
MatheMatrix wants to merge 1 commit into5.5.12from
sync/ye.zou/refactor/cleanup-orphan-vos-static-collections
Open

<refactor>[core]: add immutable support for @GlobalProperty List fields#3501
MatheMatrix wants to merge 1 commit into5.5.12from
sync/ye.zou/refactor/cleanup-orphan-vos-static-collections

Conversation

@MatheMatrix
Copy link
Owner

Summary

  • @GlobalProperty 注解新增 immutable 属性,List 字段标记 immutable=true 后框架自动 wrap Collections.unmodifiableList()
  • 标记 9 个只读 List GlobalProperty 字段为 immutable(KVM/VirtualRouter/Sftp/Zbs/Console/Ceph 的 MN_NETWORKS/IPTABLES_RULES/PORTS 等)
  • FlatNetworkServiceValidator.methods 改为 static final + unmodifiableList
  • 新增门禁测试 TestGlobalPropertyImmutableListGate:扫描全部 @GlobalProperty List 字段,未标 immutable=true 且不在白名单的直接失败
  • 白名单:CHRONY_SERVERS(ZOpsManagerImpl 运行时重赋值)、SERVER_IPS(集群成员变更)

改动文件 (10)

文件 改动
GlobalProperty.java +boolean immutable() default false
Platform.java List 注入后检查 immutable → wrap unmodifiable
FlatNetworkServiceValidator.java static final + unmodifiableList
KVMGlobalProperty.java 3 个字段标记 immutable
VirtualRouterGlobalProperty.java 2 个字段标记 immutable
SftpBackupStorageGlobalProperty.java 1 个字段标记 immutable
ZbsGlobalProperty.java 1 个字段标记 immutable
ConsoleGlobalProperty.java 1 个字段标记 immutable
CephGlobalProperty.java 1 个字段标记 immutable
TestGlobalPropertyImmutableListGate.java 新增门禁测试

Test plan

  • mvn compile 全量编译通过 (JDK 8)
  • TestGlobalPropertyImmutableListGate 测试通过
  • CI 全量测试

🤖 Generated with Claude Code

sync from gitlab !9360

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

Walkthrough

为全局属性加入不可变性支持:扩展@GlobalProperty注解增加immutable属性;在运行时对标记为immutableList值使用不可修改包装;新增单元测试强制检查;并将若干现有全局属性标记为不可变。

Changes

Cohort / File(s) Summary
注解增强
core/src/main/java/org/zstack/core/GlobalProperty.java
@GlobalProperty注解添加新的布尔属性immutable(),默认false
运行时实现
core/src/main/java/org/zstack/core/Platform.java
在处理List类型的全局属性值时,若注解immutable=true,使用Collections.unmodifiableList()包装结果并赋值。
测试强制执行
core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java
新增JUnit测试,扫描带@GlobalPropertyDefinition的类,验证所有List类型的@GlobalProperty字段默认被标记为不可变(含允许的例外白名单)。
模块属性标记更新
console/src/main/java/org/zstack/console/ConsoleGlobalProperty.java, plugin/ceph/src/main/java/org/zstack/storage/ceph/CephGlobalProperty.java, plugin/sftpBackupStorage/src/main/java/org/zstack/storage/backup/sftp/SftpBackupStorageGlobalProperty.java, plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsGlobalProperty.java
将各模块的MN_NETWORKS全局属性注解添加immutable = true
KVM 与 虚拟路由属性更新
plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalProperty.java, plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterGlobalProperty.java
为若干端口/规则相关的全局属性添加immutable = true标记(含IPTABLES_RULESHOST_NETWORK_NEED_ALARM_INTERFACE_SERVICE、TCP/UDP 管理网口端口列表)。
工具类不可变化
plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatNetworkServiceValidator.java
将静态methods字段改为private static final,并用Collections.unmodifiableList(...)包装初始化结果以确保不可修改性。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰✨ 我悄悄把列表裹紧,边缘缝上不可变的线,
注解轻点一笔,静谧在代码间梭巡。
网络与端口安睡,规则不再飘摇,
小小改变,大大安心。

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题遵循规定格式 [scope]: ,长度71字符,在72字符限制内,准确总结了核心改动:为@globalproperty List字段添加immutable支持。
Description check ✅ Passed 描述与变更集紧密相关,详细说明了@globalproperty新增immutable属性、9个只读List字段的标记、FlatNetworkServiceValidator改动、新增门禁测试及白名单机制。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sync/ye.zou/refactor/cleanup-orphan-vos-static-collections
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java (1)

78-86: 考虑补充 JAR classpath 扫描逻辑。

当前实现仅处理 file 协议的 URL,不会扫描 JAR 文件中的类。如果未来有 @GlobalPropertyDefinition 类打包在依赖 JAR 中,这些类将被跳过。

对于当前项目内的门禁测试场景,这个限制是可以接受的,因为被测类通常位于 target/classes 目录下。如果需要更完整的覆盖,可以考虑后续扩展支持 jar 协议。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java`
around lines 78 - 86, The current resource loop only handles "file" protocol and
skips JARs; update the code in TestGlobalPropertyImmutableListGate where the
resources Enumeration is iterated (the while (resources.hasMoreElements()) { ...
} block) to also handle "jar" protocol URLs: when resource.getProtocol() is
"jar" (or resource.toString() contains "!/"), open a JarURLConnection or new
JarFile from the URL, iterate its JarEntries, filter entries by the package path
(convert pkg to path with '/' suffix), for each matching .class entry derive the
class name, load the Class and add it to the result just like scanDirectory
does; keep existing exception handling but ensure you close the
JarFile/connection resources.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java`:
- Around line 78-86: The current resource loop only handles "file" protocol and
skips JARs; update the code in TestGlobalPropertyImmutableListGate where the
resources Enumeration is iterated (the while (resources.hasMoreElements()) { ...
} block) to also handle "jar" protocol URLs: when resource.getProtocol() is
"jar" (or resource.toString() contains "!/"), open a JarURLConnection or new
JarFile from the URL, iterate its JarEntries, filter entries by the package path
(convert pkg to path with '/' suffix), for each matching .class entry derive the
class name, load the Class and add it to the result just like scanDirectory
does; keep existing exception handling but ensure you close the
JarFile/connection resources.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)

Review profile: CHILL

Plan: Pro

Run ID: 25e471c6-5305-4c8c-a2da-63f5812ea177

📥 Commits

Reviewing files that changed from the base of the PR and between 327b1cc and 9e9981c.

📒 Files selected for processing (10)
  • console/src/main/java/org/zstack/console/ConsoleGlobalProperty.java
  • core/src/main/java/org/zstack/core/GlobalProperty.java
  • core/src/main/java/org/zstack/core/Platform.java
  • core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java
  • plugin/ceph/src/main/java/org/zstack/storage/ceph/CephGlobalProperty.java
  • plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatNetworkServiceValidator.java
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalProperty.java
  • plugin/sftpBackupStorage/src/main/java/org/zstack/storage/backup/sftp/SftpBackupStorageGlobalProperty.java
  • plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterGlobalProperty.java
  • plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsGlobalProperty.java

Prevent accidental mutation of static List fields populated by the
GlobalProperty framework. Add immutable attribute to @globalproperty
annotation; when true, Platform wraps the injected List with
Collections.unmodifiableList() at initialization time.

Mark all 9 read-only List GlobalProperty fields as immutable=true.
Add TestGlobalPropertyImmutableListGate gate test that fails if any
new @globalproperty List field is added without immutable=true.

Test: TestGlobalPropertyImmutableListGate (pass)

Change-Id: Iaa981bce28035f710d15dd8bb1e11d5fa8508986
Co-Authored-By: Claude Opus 4.6 (1M context) <ye.zou@zstack.io>
@MatheMatrix MatheMatrix force-pushed the sync/ye.zou/refactor/cleanup-orphan-vos-static-collections branch from 9e9981c to 5932935 Compare March 16, 2026 08:11
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java (2)

112-114: 捕获 Throwable 范围过广

此处捕获 Throwable 会吞掉 Error 类型的异常(如 OutOfMemoryErrorStackOverflowError),这些严重错误应当向上传播。建议改为捕获 Exception 或更具体的异常类型。

♻️ 建议修改
-                } catch (Throwable e) {
+                } catch (Exception e) {
                     // skip classes that can't be loaded
                 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java`
around lines 112 - 114, The test currently catches Throwable in the
class-loading loop which also swallows Error subclasses; update the catch to
only catch Exception (or a narrower checked exception like
ClassNotFoundException) in the try/catch inside
TestGlobalPropertyImmutableListGate where classes are being loaded so that
serious Errors (e.g., OutOfMemoryError) will propagate; keep the existing
skip/ignore behavior for recoverable exceptions and ensure any logging or
comments remain appropriate.

70-90: 类路径扫描仅处理 file 协议

当前实现只扫描文件系统中的类(第 80 行),不处理 JAR 包中的类。对于单元测试场景,扫描编译输出目录是足够的,但如果将来需要扫描依赖 JAR 中的类,需要扩展此逻辑。

如果这是预期行为,建议在注释中明确说明只扫描项目编译输出目录。

📝 建议添加说明性注释
     private List<Class<?>> findGlobalPropertyDefinitionClasses() {
         List<Class<?>> result = new ArrayList<>();
         String[] basePackages = {"org.zstack"};
 
         for (String pkg : basePackages) {
             String path = pkg.replace('.', '/');
             try {
                 Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(path);
                 while (resources.hasMoreElements()) {
                     URL resource = resources.nextElement();
+                    // Only scan file-based classpath entries (compiled classes in target/classes).
+                    // JAR dependencies are intentionally skipped as we only validate project sources.
                     if ("file".equals(resource.getProtocol())) {
                         scanDirectory(new File(resource.toURI()), pkg, result);
                     }
                 }
             } catch (Exception e) {
                 // skip unresolvable classpath entries
             }
         }
 
         return result;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java`
around lines 70 - 90, The current findGlobalPropertyDefinitionClasses() only
handles "file" protocol and therefore skips classes inside JARs; either add a
clear comment above findGlobalPropertyDefinitionClasses() stating it
intentionally only scans project compile-output (filesystem) or implement JAR
support: detect resource.getProtocol() == "jar" (or open a JarURLConnection for
"file" paths that reference JARs), iterate JarFile entries filtering by the
package path, convert matching entries to class names and add them to result
(extract the shared scanning logic into a new scanJar(...) method similar to
scanDirectory(...) and reuse scanDirectory/scanJar from
findGlobalPropertyDefinitionClasses()).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java`:
- Around line 112-114: The test currently catches Throwable in the class-loading
loop which also swallows Error subclasses; update the catch to only catch
Exception (or a narrower checked exception like ClassNotFoundException) in the
try/catch inside TestGlobalPropertyImmutableListGate where classes are being
loaded so that serious Errors (e.g., OutOfMemoryError) will propagate; keep the
existing skip/ignore behavior for recoverable exceptions and ensure any logging
or comments remain appropriate.
- Around line 70-90: The current findGlobalPropertyDefinitionClasses() only
handles "file" protocol and therefore skips classes inside JARs; either add a
clear comment above findGlobalPropertyDefinitionClasses() stating it
intentionally only scans project compile-output (filesystem) or implement JAR
support: detect resource.getProtocol() == "jar" (or open a JarURLConnection for
"file" paths that reference JARs), iterate JarFile entries filtering by the
package path, convert matching entries to class names and add them to result
(extract the shared scanning logic into a new scanJar(...) method similar to
scanDirectory(...) and reuse scanDirectory/scanJar from
findGlobalPropertyDefinitionClasses()).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)

Review profile: CHILL

Plan: Pro

Run ID: 6cf18056-01f6-4b73-a816-9977f2676b6e

📥 Commits

Reviewing files that changed from the base of the PR and between 9e9981c and 5932935.

📒 Files selected for processing (10)
  • console/src/main/java/org/zstack/console/ConsoleGlobalProperty.java
  • core/src/main/java/org/zstack/core/GlobalProperty.java
  • core/src/main/java/org/zstack/core/Platform.java
  • core/src/test/java/org/zstack/core/property/TestGlobalPropertyImmutableListGate.java
  • plugin/ceph/src/main/java/org/zstack/storage/ceph/CephGlobalProperty.java
  • plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatNetworkServiceValidator.java
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalProperty.java
  • plugin/sftpBackupStorage/src/main/java/org/zstack/storage/backup/sftp/SftpBackupStorageGlobalProperty.java
  • plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterGlobalProperty.java
  • plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsGlobalProperty.java
✅ Files skipped from review due to trivial changes (1)
  • plugin/ceph/src/main/java/org/zstack/storage/ceph/CephGlobalProperty.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • core/src/main/java/org/zstack/core/Platform.java
  • plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterGlobalProperty.java
  • console/src/main/java/org/zstack/console/ConsoleGlobalProperty.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants