This is an automated email from the ASF dual-hosted git repository.
yuqi4733 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new fdcb7ae187 [#6641] fix(core): Possible error in the equals method for
collection (#6644)
fdcb7ae187 is described below
commit fdcb7ae187d8f464fbc8dae1e07dc5ad385411d5
Author: Xiaojian Sun <[email protected]>
AuthorDate: Tue Mar 11 16:56:13 2025 +0800
[#6641] fix(core): Possible error in the equals method for collection
(#6644)
<!--
1. Title: [#<issue>] <type>(<scope>): <subject>
Examples:
- "[#123] feat(operator): support xxx"
- "[#233] fix: check null before access result in xxx"
- "[MINOR] refactor: fix typo in variable name"
- "[MINOR] docs: fix typo in README"
- "[#255] test: fix flaky test NameOfTheTest"
Reference: https://www.conventionalcommits.org/en/v1.0.0/
2. If the PR is unfinished, please mark this PR as draft.
-->
### What changes were proposed in this pull request?
Possible error in the equals method for collection
### Why are the changes needed?
Fix: #6641
### Does this PR introduce _any_ user-facing change?
N/A
### How was this patch tested?
N/A
---
api/build.gradle.kts | 1 +
.../gravitino/authorization/SecurableObjects.java | 15 ++++++++-
.../apache/gravitino/utils/CollectionUtils.java | 37 +++++++++++++---------
core/build.gradle.kts | 1 +
.../org/apache/gravitino/meta/GroupEntity.java | 5 +--
.../apache/gravitino/meta/ModelVersionEntity.java | 3 +-
.../java/org/apache/gravitino/meta/RoleEntity.java | 3 +-
.../org/apache/gravitino/meta/TableEntity.java | 3 +-
.../java/org/apache/gravitino/meta/UserEntity.java | 5 +--
.../relational/service/RoleMetaService.java | 7 ----
.../relational/service/TestRoleMetaService.java | 21 +++++++-----
11 files changed, 63 insertions(+), 38 deletions(-)
diff --git a/api/build.gradle.kts b/api/build.gradle.kts
index a9f2450863..b13745d9ff 100644
--- a/api/build.gradle.kts
+++ b/api/build.gradle.kts
@@ -24,6 +24,7 @@ plugins {
dependencies {
implementation(libs.commons.lang3)
+ implementation(libs.commons.collections4)
implementation(libs.guava)
implementation(libs.slf4j.api)
diff --git
a/api/src/main/java/org/apache/gravitino/authorization/SecurableObjects.java
b/api/src/main/java/org/apache/gravitino/authorization/SecurableObjects.java
index b926964e15..5aa2fd8d2f 100644
--- a/api/src/main/java/org/apache/gravitino/authorization/SecurableObjects.java
+++ b/api/src/main/java/org/apache/gravitino/authorization/SecurableObjects.java
@@ -22,9 +22,11 @@ import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
import org.apache.gravitino.MetadataObjects.MetadataObjectImpl;
@@ -168,7 +170,18 @@ public class SecurableObjects {
}
SecurableObject otherSecurableObject = (SecurableObject) other;
- return super.equals(other) && Objects.equals(privileges,
otherSecurableObject.privileges());
+ return super.equals(other)
+ && isEqualCollection(privileges, otherSecurableObject.privileges());
+ }
+
+ private boolean isEqualCollection(Collection<?> c1, Collection<?> c2) {
+ if (c1 == c2) {
+ return true;
+ }
+ if (c1 == null || c2 == null) {
+ return false;
+ }
+ return CollectionUtils.isEqualCollection(c1, c2);
}
}
diff --git a/api/build.gradle.kts
b/common/src/main/java/org/apache/gravitino/utils/CollectionUtils.java
similarity index 54%
copy from api/build.gradle.kts
copy to common/src/main/java/org/apache/gravitino/utils/CollectionUtils.java
index a9f2450863..43ade6c119 100644
--- a/api/build.gradle.kts
+++ b/common/src/main/java/org/apache/gravitino/utils/CollectionUtils.java
@@ -16,22 +16,29 @@
* specific language governing permissions and limitations
* under the License.
*/
-plugins {
- `maven-publish`
- id("java")
- id("idea")
-}
-dependencies {
- implementation(libs.commons.lang3)
- implementation(libs.guava)
- implementation(libs.slf4j.api)
+package org.apache.gravitino.utils;
- testImplementation(libs.junit.jupiter.api)
- testImplementation(libs.junit.jupiter.params)
- testRuntimeOnly(libs.junit.jupiter.engine)
-}
+import java.util.Collection;
+
+/** Utility class for working with collection. */
+public class CollectionUtils {
+ private CollectionUtils() {}
-tasks.build {
- dependsOn("javadoc")
+ /**
+ * Returns true if the two collections are equal.
+ *
+ * @param c1 the first collection, may be null
+ * @param c2 the second collection, may be null
+ * @return true if the two collections are equal
+ */
+ public static boolean isEqualCollection(Collection<?> c1, Collection<?> c2) {
+ if (c1 == c2) {
+ return true;
+ }
+ if (c1 == null || c2 == null) {
+ return false;
+ }
+ return
org.apache.commons.collections4.CollectionUtils.isEqualCollection(c1, c2);
+ }
}
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index ef23950b07..c5f92a6ed7 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -33,6 +33,7 @@ dependencies {
implementation(libs.commons.dbcp2)
implementation(libs.commons.io)
implementation(libs.commons.lang3)
+ implementation(libs.commons.collections4)
implementation(libs.guava)
implementation(libs.h2db)
implementation(libs.mybatis)
diff --git a/core/src/main/java/org/apache/gravitino/meta/GroupEntity.java
b/core/src/main/java/org/apache/gravitino/meta/GroupEntity.java
index d9e4b633d5..b8cac5ba4c 100644
--- a/core/src/main/java/org/apache/gravitino/meta/GroupEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/GroupEntity.java
@@ -29,6 +29,7 @@ import org.apache.gravitino.Field;
import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.utils.CollectionUtils;
public class GroupEntity implements Group, Entity, Auditable, HasIdentifier {
@@ -161,8 +162,8 @@ public class GroupEntity implements Group, Entity,
Auditable, HasIdentifier {
&& Objects.equals(name, that.name)
&& Objects.equals(namespace, that.namespace)
&& Objects.equals(auditInfo, that.auditInfo)
- && Objects.equals(roleNames, that.roleNames)
- && Objects.equals(roleIds, that.roleIds);
+ && CollectionUtils.isEqualCollection(roleNames, that.roleNames)
+ && CollectionUtils.isEqualCollection(roleIds, that.roleIds);
}
@Override
diff --git
a/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java
b/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java
index d6c4bfdf86..733c1315b5 100644
--- a/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/ModelVersionEntity.java
@@ -31,6 +31,7 @@ import org.apache.gravitino.Field;
import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
+import org.apache.gravitino.utils.CollectionUtils;
@ToString
public class ModelVersionEntity implements Entity, Auditable, HasIdentifier {
@@ -146,7 +147,7 @@ public class ModelVersionEntity implements Entity,
Auditable, HasIdentifier {
return Objects.equals(version, that.version)
&& Objects.equals(modelIdent, that.modelIdent)
&& Objects.equals(comment, that.comment)
- && Objects.equals(aliases, that.aliases)
+ && CollectionUtils.isEqualCollection(aliases, that.aliases)
&& Objects.equals(uri, that.uri)
&& Objects.equals(properties, that.properties)
&& Objects.equals(auditInfo, that.auditInfo);
diff --git a/core/src/main/java/org/apache/gravitino/meta/RoleEntity.java
b/core/src/main/java/org/apache/gravitino/meta/RoleEntity.java
index a96f6e0f5a..c69df41eae 100644
--- a/core/src/main/java/org/apache/gravitino/meta/RoleEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/RoleEntity.java
@@ -31,6 +31,7 @@ import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.authorization.Role;
import org.apache.gravitino.authorization.SecurableObject;
+import org.apache.gravitino.utils.CollectionUtils;
public class RoleEntity implements Role, Entity, Auditable, HasIdentifier {
@@ -142,7 +143,7 @@ public class RoleEntity implements Role, Entity, Auditable,
HasIdentifier {
&& Objects.equals(namespace, that.namespace)
&& Objects.equals(auditInfo, that.auditInfo)
&& Objects.equals(properties, that.properties)
- && Objects.equals(securableObjects, that.securableObjects);
+ && CollectionUtils.isEqualCollection(securableObjects,
that.securableObjects);
}
@Override
diff --git a/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
b/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
index 197eed6d33..f661cd049a 100644
--- a/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
@@ -29,6 +29,7 @@ import org.apache.gravitino.Entity;
import org.apache.gravitino.Field;
import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.Namespace;
+import org.apache.gravitino.utils.CollectionUtils;
/** A class representing a table entity in Apache Gravitino. */
@ToString
@@ -135,7 +136,7 @@ public class TableEntity implements Entity, Auditable,
HasIdentifier {
&& Objects.equal(name, baseTable.name)
&& Objects.equal(namespace, baseTable.namespace)
&& Objects.equal(auditInfo, baseTable.auditInfo)
- && Objects.equal(columns, baseTable.columns);
+ && CollectionUtils.isEqualCollection(columns, baseTable.columns);
}
@Override
diff --git a/core/src/main/java/org/apache/gravitino/meta/UserEntity.java
b/core/src/main/java/org/apache/gravitino/meta/UserEntity.java
index c71d731a99..c9d7089f85 100644
--- a/core/src/main/java/org/apache/gravitino/meta/UserEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/UserEntity.java
@@ -30,6 +30,7 @@ import org.apache.gravitino.Field;
import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.authorization.User;
+import org.apache.gravitino.utils.CollectionUtils;
/** A class representing a user metadata entity in Apache Gravitino. */
@ToString
@@ -164,8 +165,8 @@ public class UserEntity implements User, Entity, Auditable,
HasIdentifier {
&& Objects.equals(name, that.name)
&& Objects.equals(namespace, that.namespace)
&& Objects.equals(auditInfo, that.auditInfo)
- && Objects.equals(roleNames, that.roleNames)
- && Objects.equals(roleIds, that.roleIds);
+ && CollectionUtils.isEqualCollection(roleNames, that.roleNames)
+ && CollectionUtils.isEqualCollection(roleIds, that.roleIds);
}
@Override
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
index 3f27902d0c..59ec4dea8c 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
@@ -24,7 +24,6 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -408,12 +407,6 @@ public class RoleMetaService {
}
}
});
-
- // To ensure that the order of the returned securable objects remains
consistent,
- // the securable objects are sorted by fullName here,
- // since the order of securable objects after grouping by is different
each time.
- securableObjects.sort(Comparator.comparing(MetadataObject::fullName));
-
return securableObjects;
}
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
index 4a5d586465..ea6b31e1df 100644
---
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestRoleMetaService.java
@@ -57,6 +57,7 @@ import org.apache.gravitino.storage.relational.po.GroupPO;
import org.apache.gravitino.storage.relational.po.UserPO;
import org.apache.gravitino.storage.relational.session.SqlSessionFactoryHelper;
import org.apache.gravitino.storage.relational.utils.SessionUtils;
+import org.apache.gravitino.utils.CollectionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -623,13 +624,14 @@ class TestRoleMetaService extends TestJDBCBackend {
Assertions.assertEquals(grantRole.name(), roleEntity.name());
Assertions.assertEquals("creator", grantRole.auditInfo().creator());
Assertions.assertEquals("grantRole", grantRole.auditInfo().lastModifier());
- Assertions.assertEquals(
- Lists.newArrayList(
- SecurableObjects.ofCatalog(
- "catalog", Lists.newArrayList(Privileges.UseCatalog.allow())),
- SecurableObjects.ofMetalake(
- metalakeName,
Lists.newArrayList(Privileges.CreateTable.allow()))),
- grantRole.securableObjects());
+ Assertions.assertTrue(
+ CollectionUtils.isEqualCollection(
+ Lists.newArrayList(
+ SecurableObjects.ofCatalog(
+ "catalog",
Lists.newArrayList(Privileges.UseCatalog.allow())),
+ SecurableObjects.ofMetalake(
+ metalakeName,
Lists.newArrayList(Privileges.CreateTable.allow()))),
+ grantRole.securableObjects()));
// revoke privileges from the role
Function<RoleEntity, RoleEntity> revokeUpdater =
@@ -643,7 +645,10 @@ class TestRoleMetaService extends TestJDBCBackend {
.build();
List<SecurableObject> securableObjects =
Lists.newArrayList(role.securableObjects());
- securableObjects.remove(0);
+ securableObjects.removeIf(
+ securableObject ->
+ securableObject.type() == SecurableObject.Type.CATALOG
+ &&
securableObject.privileges().contains(Privileges.UseCatalog.allow()));
return RoleEntity.builder()
.withId(role.id())