Skip to content

Conversation

arvi18
Copy link

@arvi18 arvi18 commented Apr 21, 2025

Admin.listConsumerGroups() was able to use the early versions of
ListGroups RPC with the version used dependent upon the filters the user
specified. Admin.listGroups(ListGroupsOptions.forConsumerGroups())
inadvertently required ListGroups v5 because it always set a types
filter. This patch handles the UnsupportedVersionException and winds
back the complexity of the request unless the user has specified filters
which demand a higher version.

It also adds ListGroupsOptions.forShareGroups() and forStreamsGroups().
The usability of Admin.listGroups() is much improved as a result.

@visz11
Copy link
Collaborator

visz11 commented Jul 16, 2025

/refacto-test

1 similar comment
@visz11
Copy link
Collaborator

visz11 commented Jul 16, 2025

/refacto-test

@visz11
Copy link
Collaborator

visz11 commented Aug 7, 2025

/refacto-test

Copy link

refacto-test bot commented Aug 7, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Comment on lines 3559 to +3569
private void maybeAddGroup(ListGroupsResponseData.ListedGroup group) {
final String groupId = group.groupId();
final Optional<GroupType> type;
if (group.groupType() == null || group.groupType().isEmpty()) {
type = Optional.empty();
} else {
type = Optional.of(GroupType.parse(group.groupType()));
}
final String protocolType = group.protocolType();
final Optional<GroupState> groupState;
if (group.groupState() == null || group.groupState().isEmpty()) {
groupState = Optional.empty();
} else {
groupState = Optional.of(GroupState.parse(group.groupState()));
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
final String groupId = group.groupId();
final Optional<GroupType> type;
if (group.groupType() == null || group.groupType().isEmpty()) {
type = Optional.empty();
} else {
type = Optional.of(GroupType.parse(group.groupType()));
}
final Optional<GroupState> groupState;
Copy link

Choose a reason for hiding this comment

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

Client-Side Protocol Type Filtering Bypass

The protocol type filtering is performed client-side after receiving the response from the server. This means that even if a user is only authorized to see certain protocol types, they could modify the client code to bypass this filtering and see all group types returned by the server. The server should be responsible for enforcing access controls based on protocol types, not the client. This could lead to information disclosure where users can access group data they shouldn't have permission to view.

Suggested change
private void maybeAddGroup(ListGroupsResponseData.ListedGroup group) {
final String groupId = group.groupId();
final Optional<GroupType> type;
if (group.groupType() == null || group.groupType().isEmpty()) {
type = Optional.empty();
} else {
type = Optional.of(GroupType.parse(group.groupType()));
}
final String protocolType = group.protocolType();
final Optional<GroupState> groupState;
if (group.groupState() == null || group.groupState().isEmpty()) {
groupState = Optional.empty();
} else {
groupState = Optional.of(GroupState.parse(group.groupState()));
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
final String groupId = group.groupId();
final Optional<GroupType> type;
if (group.groupType() == null || group.groupType().isEmpty()) {
type = Optional.empty();
} else {
type = Optional.of(GroupType.parse(group.groupType()));
}
final Optional<GroupState> groupState;
// In createRequest method, add protocol types to the request
List<String> protocolTypes = new ArrayList<>(options.protocolTypes());
return new ListGroupsRequest.Builder(new ListGroupsRequestData()
.setTypesFilter(groupTypes)
.setStatesFilter(groupStates)
.setProtocolTypesFilter(protocolTypes));

Comment on lines 85 to 87
public ListGroupsOptions withProtocolTypes(Set<String> protocolTypes) {
this.protocolTypes = (protocolTypes == null || protocolTypes.isEmpty()) ? Set.of() : Set.copyOf(protocolTypes);
return this;
Copy link

Choose a reason for hiding this comment

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

Insecure Default in Protocol Type Filtering

The withProtocolTypes method treats null or empty sets as 'no filtering' rather than 'no access'. This follows the principle of being permissive by default, which is not a secure design pattern. If a developer forgets to specify protocol types, the system will allow access to all protocol types rather than denying access by default, potentially leading to unintended information disclosure.

Suggested change
public ListGroupsOptions withProtocolTypes(Set<String> protocolTypes) {
this.protocolTypes = (protocolTypes == null || protocolTypes.isEmpty()) ? Set.of() : Set.copyOf(protocolTypes);
return this;
public ListGroupsOptions withProtocolTypes(Set<String> protocolTypes) {
// Default to an empty set (no access) if null is provided
this.protocolTypes = (protocolTypes == null) ? Set.of() : Set.copyOf(protocolTypes);
return this;
}

Copy link

refacto-test bot commented Aug 7, 2025

Protocol Type Filtering Bypass in ListGroupsOptions

👍 Well Done
Comprehensive Test Coverage

The PR includes thorough test cases that verify the functionality of the new ListGroupsOptions features, including edge cases and backward compatibility.

Backward Compatibility Support

The implementation properly handles backward compatibility with older broker versions through the handleUnsupportedVersionException mechanism.

Proper Encapsulation of Group Types

The introduction of specialized factory methods (forConsumerGroups, forShareGroups, forStreamsGroups) follows good API design principles by encapsulating implementation details.

📌 Files Processed
  • clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java
  • clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java
  • clients/src/test/java/org/apache/kafka/clients/admin/KafkaAdminClientTest.java
  • clients/src/test/java/org/apache/kafka/clients/admin/ListGroupsOptionsTest.java
  • core/src/main/scala/kafka/admin/ConfigCommand.scala
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ShareGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/streams/StreamsGroupCommand.java
  • tools/src/test/java/org/apache/kafka/tools/consumer/group/ListConsumerGroupTest.java

@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from visz11 Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Aug 7, 2025
Copy link

refacto-test bot commented Aug 7, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

@coderabbit-test coderabbit-test deleted a comment from visz11 Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from visz11 Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from visz11 Aug 7, 2025
@coderabbit-test coderabbit-test deleted a comment from visz11 Aug 7, 2025
Copy link

refacto-test bot commented Aug 7, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-visz bot commented Sep 16, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-visz bot commented Sep 16, 2025

Code Review: ListGroups Protocol Type Filtering

👍 Well Done
Backward Compatibility Handling

Graceful handling of older broker versions improves system reliability.

Protocol Type Filtering

Added protocol type filtering enhances functional correctness of group listing.

📌 Files Processed
  • clients/src/test/java/org/apache/kafka/clients/admin/ListGroupsOptionsTest.java
  • clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java
  • clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java
  • clients/src/test/java/org/apache/kafka/clients/admin/KafkaAdminClientTest.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ShareGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/streams/StreamsGroupCommand.java
  • core/src/main/scala/kafka/admin/ConfigCommand.scala
  • tools/src/test/java/org/apache/kafka/tools/consumer/group/ListConsumerGroupTest.java
📝 Additional Comments
clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java (3)
Retry Logic Improvement

The retry logic only attempts one earlier version. For multi-version compatibility, consider implementing a more flexible version fallback mechanism that could try multiple earlier versions if needed.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • SRE-Graceful-Degradation
Logging For Fallbacks

Version fallback occurs silently without logging. Adding logging when falling back to earlier request versions would improve observability and help diagnose compatibility issues in production environments.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • SRE-Observability
Consistent Error Handling

When version fallback isn't possible, the code silently gives up. Consider providing more context about the version incompatibility to help diagnose the root cause of failures in mixed-version environments.

Standards:

  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • SRE-Error-Handling

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Protocol Type Filtering Lacks Null Safety

The protocol type filtering doesn't handle null protocol types safely. If group.protocolType() returns null, the contains() check will throw NullPointerException. This would cause the listing operation to fail unexpectedly.

Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • SRE-Error-Handling

@visz11
Copy link
Collaborator

visz11 commented Sep 16, 2025

/refacto-test-arvi

Copy link

refacto-visz bot commented Sep 16, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-visz bot commented Sep 16, 2025

Code Review: ListGroups API Enhancement

👍 Well Done
Improved API Design

New factory methods enhance usability and reliability for different group types.

Backward Compatibility

Graceful fallback to earlier request versions maintains reliability with older brokers.

📌 Files Processed
  • clients/src/test/java/org/apache/kafka/clients/admin/ListGroupsOptionsTest.java
  • clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java
  • clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java
  • clients/src/test/java/org/apache/kafka/clients/admin/KafkaAdminClientTest.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ShareGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/streams/StreamsGroupCommand.java
  • core/src/main/scala/kafka/admin/ConfigCommand.scala
  • tools/src/test/java/org/apache/kafka/tools/consumer/group/ListConsumerGroupTest.java
📝 Additional Comments
clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java (1)
Simplify Version Fallback

The version fallback logic could be simplified to a single condition. Current implementation has multiple exit points and state tracking that increases complexity. Simplifying would improve maintainability and reduce potential for logic errors.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Simplicity
  • DbC-Clarity
clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java (2)
Missing Error Handling

No validation for null parameter in public API method. If null is passed, it's handled correctly in the implementation, but explicit validation would provide clearer error messages. Current implementation silently converts null to empty set.

Standards:

  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Input-Validation
  • DbC-Preconditions
Inconsistent Error Handling

Inconsistent null handling across similar methods. withProtocolTypes() handles null by converting to empty set, while withTypes() delegates to another method. This inconsistency could lead to confusion and potential bugs when maintaining the code.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Consistency
  • DbC-Consistency

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Potential NullPointerException

No null check on protocolType before using it in contains() method. If broker returns null protocolType, this will cause NullPointerException, crashing the client application. This breaks reliability when interacting with non-standard broker responses.

Suggested change
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || (protocolType != null && options.protocolTypes().contains(protocolType))) {
Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Robustness
  • DbC-Defensive-Programming

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Protocol Type Filtering

Protocol type filtering happens after receiving response from broker, not in request. This creates unnecessary network traffic and processing overhead when filtering could be done server-side. May cause performance degradation under high load.

Suggested change
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
if (tryUsingEarlierRequestVersion) {
List<String> groupStates = options.groupStates()
.stream()
.map(GroupState::toString)
.collect(Collectors.toList());
return new ListGroupsRequest.Builder(new ListGroupsRequestData()
.setStatesFilter(groupStates)
);
} else {
List<String> groupTypes = options.types()
.stream()
.map(GroupType::toString)
.collect(Collectors.toList());
List<String> groupStates = options.groupStates()
.stream()
.map(GroupState::toString)
.collect(Collectors.toList());
List<String> protocolTypes = options.protocolTypes()
.stream()
.collect(Collectors.toList());
return new ListGroupsRequest.Builder(new ListGroupsRequestData()
.setTypesFilter(groupTypes)
.setStatesFilter(groupStates)
.setProtocolTypesFilter(protocolTypes)
);
}
Standards
  • ISO-IEC-25010-Reliability-Resource-Utilization
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • SRE-Efficiency

@visz11
Copy link
Collaborator

visz11 commented Sep 16, 2025

/refacto-test-arvi

Copy link

refacto-visz bot commented Sep 16, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-visz bot commented Sep 16, 2025

Code Review: ListGroups Implementation

👍 Well Done
Improved Protocol Type Filtering

Added protocol type filtering enhances reliability by preventing unnecessary processing of irrelevant groups.

Backward Compatibility Support

Graceful fallback to earlier request versions prevents failures with older brokers.

📌 Files Processed
  • clients/src/test/java/org/apache/kafka/clients/admin/ListGroupsOptionsTest.java
  • clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java
  • clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java
  • clients/src/test/java/org/apache/kafka/clients/admin/KafkaAdminClientTest.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ShareGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/streams/StreamsGroupCommand.java
  • core/src/main/scala/kafka/admin/ConfigCommand.scala
  • tools/src/test/java/org/apache/kafka/tools/consumer/group/ListConsumerGroupTest.java
📝 Additional Comments
clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java (1)
Missing Error Logging

No logging when version fallback fails or succeeds. This reduces observability of compatibility issues in production. Adding debug logging would help diagnose version compatibility problems without impacting normal operation.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • SRE-Observability
clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java (1)
Defensive Type Checking

The method accepts a boolean parameter without validation. While not immediately problematic, adding validation or using an enum instead would improve API reliability by preventing incorrect usage patterns and making intent clearer.

Standards:

  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Preconditions

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Protocol Type Filtering

The protocol type filtering doesn't handle null protocol types safely. If group.protocolType() returns null, the contains() check will throw NullPointerException, causing request failure. This breaks reliability when processing groups with null protocol types.

Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • SRE-Error-Handling

Comment on lines +3605 to +3617
// If we cannot try the earlier request version, give up
if (!canTryEarlierRequestVersion) {
return false;
}

// If have already tried the earlier request version, give up
if (tryUsingEarlierRequestVersion) {
return false;
}

// Have a try using the earlier request version
tryUsingEarlierRequestVersion = true;
return true;
Copy link

Choose a reason for hiding this comment

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

Incomplete Version Fallback

The version fallback mechanism only attempts one earlier version. If multiple version downgrades are needed, the code will fail after a single retry. This creates a reliability gap when interacting with brokers supporting much older versions.

Standards
  • ISO-IEC-25010-Reliability-Compatibility
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • SRE-Graceful-Degradation

@visz11
Copy link
Collaborator

visz11 commented Sep 16, 2025

/refacto-test-arvi

Copy link

refacto-visz bot commented Sep 16, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-visz bot commented Sep 16, 2025

Code Review: Admin API Enhancements

👍 Well Done
Backward Compatibility Handling

Graceful handling of older broker versions prevents runtime failures.

Protocol Type Filtering

Added protocol type filtering improves reliability by preventing unnecessary processing.

📌 Files Processed
  • clients/src/test/java/org/apache/kafka/clients/admin/ListGroupsOptionsTest.java
  • clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java
  • clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java
  • clients/src/test/java/org/apache/kafka/clients/admin/KafkaAdminClientTest.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ShareGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/streams/StreamsGroupCommand.java
  • core/src/main/scala/kafka/admin/ConfigCommand.scala
  • tools/src/test/java/org/apache/kafka/tools/consumer/group/ListConsumerGroupTest.java
📝 Additional Comments
clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java (2)
Simplify Version Handling

The version handling logic could be simplified to a single condition. Current implementation has two separate conditions that both return false, increasing complexity and potential for maintenance errors.

Standards:

  • ISO-IEC-25010-Maintainability-Modifiability
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Code-Clarity
Defensive Null Checking

The code checks for null or empty groupType but doesn't validate the parsed GroupType. If GroupType.parse() returns null for an unrecognized type, it could cause NullPointerException when creating the Optional.

Standards:

  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Defensive-Programming
clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java (1)
Consistent Error Handling

The public withTypes() method doesn't validate input parameters while the private implementation does. This inconsistency could lead to unexpected behavior if null is passed to the public method.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Precondition-Validation

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Potential NPE Risk

The protocolType variable may be null, causing NullPointerException when calling contains(). While the protocol type is unlikely to be null in practice, defensive null checking would prevent potential runtime failures.

Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Precondition-Validation
  • SRE-Error-Prevention

@visz11
Copy link
Collaborator

visz11 commented Sep 16, 2025

/refacto-test-arvi

Copy link

refacto-visz bot commented Sep 16, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-visz bot commented Sep 16, 2025

Code Review: ListGroups Implementation

👍 Well Done
Backward Compatibility Support

Added fallback mechanism for older broker versions enhances system reliability.

Protocol Type Filtering

New protocol type filtering improves functional correctness of group listing operations.

📌 Files Processed
  • clients/src/test/java/org/apache/kafka/clients/admin/ListGroupsOptionsTest.java
  • clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java
  • clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java
  • clients/src/test/java/org/apache/kafka/clients/admin/KafkaAdminClientTest.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ShareGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/streams/StreamsGroupCommand.java
  • core/src/main/scala/kafka/admin/ConfigCommand.scala
  • tools/src/test/java/org/apache/kafka/tools/consumer/group/ListConsumerGroupTest.java
📝 Additional Comments
clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java (2)
Simplify Version Fallback Logic

The version fallback logic could be simplified to a single condition. The current implementation checks two separate conditions that could be combined, making the code more maintainable and reducing the risk of future logic errors during modifications.

Standards:

  • ISO-IEC-25010-Maintainability-Modifiability
  • ISO-IEC-25010-Reliability-Maturity
Consistent Error Handling

The error handling for UnsupportedVersionException returns false in both conditions but for different reasons. Adding logging or differentiated error handling would improve observability and help diagnose version compatibility issues in production environments.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • SRE-Error-Handling
  • ISO-IEC-25010-Maintainability-Testability
clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java (1)
Defensive Type Checking

The withTypes method sets regularConsumerGroupTypes without validation. Adding validation that the types parameter contains only consumer group types when regularConsumerGroupTypes is true would prevent potential inconsistencies between the flag and actual types content.

Standards:

  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Invariant-Preservation

Comment on lines +3561 to +3562
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
final String groupId = group.groupId();
Copy link

Choose a reason for hiding this comment

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

Missing Protocol Type Validation

The code doesn't handle null protocol types before checking containment. If protocolType is null, the contains() check will throw NullPointerException, causing request processing to fail. This creates a reliability issue when processing responses with null protocol types.

Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Precondition-Validation

@visz11
Copy link
Collaborator

visz11 commented Sep 16, 2025

/refacto-test-arvi

Copy link

refacto-visz bot commented Sep 16, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-visz bot commented Sep 16, 2025

Code Review: ListGroups API Enhancements

👍 Well Done
Protocol Type Filtering

Added protocol type filtering improves group listing flexibility and precision.

Backward Compatibility

Maintained backward compatibility with older broker versions through version detection and fallback mechanisms.

📌 Files Processed
  • clients/src/test/java/org/apache/kafka/clients/admin/ListGroupsOptionsTest.java
  • clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java
  • clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java
  • clients/src/test/java/org/apache/kafka/clients/admin/KafkaAdminClientTest.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/consumer/group/ShareGroupCommand.java
  • tools/src/main/java/org/apache/kafka/tools/streams/StreamsGroupCommand.java
  • core/src/main/scala/kafka/admin/ConfigCommand.scala
  • tools/src/test/java/org/apache/kafka/tools/consumer/group/ListConsumerGroupTest.java
📝 Additional Comments
clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java (6)
Defensive Null Handling

The code correctly checks for null before calling isEmpty() on groupType and groupState, but similar defensive checks should be applied to protocolType. Inconsistent null handling patterns increase maintenance complexity and risk of future null-related failures.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Defensive-Programming
  • SRE-Error-Handling
Logging For Observability

When falling back to an earlier request version, no logging occurs to indicate this fallback behavior. Adding logging would improve system observability and help diagnose compatibility issues in production environments where version mismatches occur.

Standards:

  • ISO-IEC-25010-Reliability-Maturity
  • SRE-Observability
  • SRE-Monitoring
  • ISO-IEC-25010-Functional-Appropriateness
Inconsistent Group Filtering

When falling back to an earlier request version, the code only applies groupStates filter but drops the protocolTypes filter. This creates inconsistent filtering behavior between normal and fallback paths, potentially returning groups that should be filtered out by protocolTypes.

Standards:

  • Algorithm-Correctness-Consistency
  • Business-Rule-Filter-Logic
  • Logic-Verification-Fallback-Behavior
Conditional Complexity

Method contains nested conditionals that could be simplified. The two separate if statements with return false could be combined with logical OR, reducing cognitive complexity and improving readability while maintaining the same behavior.

Standards:

  • Clean-Code-Functions
  • Maintainability-Quality-Complexity
  • Clean-Code-Simplicity
Protocol Type Filtering

Protocol type filtering happens before expensive parsing operations but still performs unnecessary object creation for groups that will be filtered out. Moving all parsing operations inside the conditional block would improve performance by avoiding unnecessary object creation and parsing.

Standards:

  • ISO-IEC-25010-Performance-Efficiency-Resource-Utilization
  • Optimization-Pattern-Early-Filtering
  • Algorithmic-Complexity-Conditional-Optimization
Unsupported Version Handling

The exception handling mechanism silently retries with an earlier version without logging the exception details. This could mask security-relevant compatibility issues and make troubleshooting difficult. Consider adding logging of the original exception to improve security monitoring and debugging capabilities.

Standards:

  • CWE-778
  • OWASP-A04
  • NIST-SSDF-RV.1
clients/src/main/java/org/apache/kafka/clients/admin/ListGroupsOptions.java (2)
Redundant Type Check

The public withTypes method always sets regularConsumerGroupTypes to false, which may override previous settings. This creates inconsistent behavior when chaining method calls after forConsumerGroups() which sets regularConsumerGroupTypes to true.

Standards:

  • Algorithm-Correctness-State-Consistency
  • Logic-Verification-Method-Chaining
  • Business-Rule-API-Contract
Inconsistent Method Naming

Inconsistent method naming pattern with 'with' vs 'in' prefixes for similar setter methods. Method inGroupStates uses different prefix than withProtocolTypes and withTypes. Consistent naming improves API predictability and reduces cognitive load.

Standards:

  • Clean-Code-Naming
  • Maintainability-Quality-Consistency
  • Clean-Code-API-Design
tools/src/main/java/org/apache/kafka/tools/consumer/group/ConsumerGroupCommand.java (1)
Group Type Validation

The group type validation has been improved to explicitly check against a whitelist of valid types rather than just checking for UNKNOWN. This is a security improvement, but consider adding validation for empty input strings and null values to prevent potential exceptions or unexpected behavior.

Standards:

  • CWE-20
  • OWASP-A03
  • NIST-SSDF-PW.1

Comment on lines +3605 to +3613
// If we cannot try the earlier request version, give up
if (!canTryEarlierRequestVersion) {
return false;
}

// If have already tried the earlier request version, give up
if (tryUsingEarlierRequestVersion) {
return false;
}
Copy link

Choose a reason for hiding this comment

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

Incomplete Error Handling

The handleUnsupportedVersionException method returns false when it cannot handle the exception, but doesn't provide any error information about why the version is unsupported. This can lead to silent failures and difficult debugging when version compatibility issues occur.

Suggested change
// If we cannot try the earlier request version, give up
if (!canTryEarlierRequestVersion) {
return false;
}
// If have already tried the earlier request version, give up
if (tryUsingEarlierRequestVersion) {
return false;
}
// If we cannot try the earlier request version, give up
if (!canTryEarlierRequestVersion) {
log.debug("Cannot handle UnsupportedVersionException for listGroups request: only regular consumer group types can use earlier version");
return false;
}
// If have already tried the earlier request version, give up
if (tryUsingEarlierRequestVersion) {
log.debug("Already tried earlier request version for listGroups, cannot handle UnsupportedVersionException");
return false;
}
Standards
  • ISO-IEC-25010-Reliability-Fault-Tolerance
  • ISO-IEC-25010-Functional-Correctness-Appropriateness
  • DbC-Error-Reporting
  • SRE-Observability

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Protocol Type Filter

The protocol type filter check doesn't handle null protocol types correctly. If group.protocolType() returns null, the contains() check will throw NullPointerException when options.protocolTypes() contains non-null values.

Standards
  • Algorithm-Correctness-Null-Safety
  • Business-Rule-Input-Validation
  • Logic-Verification-Defensive-Programming

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Protocol Type Filtering

The protocol type filtering implementation checks if the protocol type is empty before applying the filter. This could allow groups with empty protocol types to bypass filtering restrictions, potentially exposing groups that should be restricted. An attacker could exploit this to gain visibility into groups they shouldn't have access to.

Standards
  • CWE-284
  • OWASP-A01
  • NIST-SSDF-PW.1

Comment on lines +98 to 101
ListGroupsOptions withTypes(Set<GroupType> types, boolean regularConsumerGroupTypes) {
this.types = (types == null || types.isEmpty()) ? Set.of() : Set.copyOf(types);
this.regularConsumerGroupTypes = regularConsumerGroupTypes;
return this;
Copy link

Choose a reason for hiding this comment

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

Boolean Flag Parameter

Boolean parameter creates unclear API and makes method calls harder to understand. The regularConsumerGroupTypes flag hides intention and creates maintenance burden. Consider using descriptive method names or builder pattern instead.

Standards
  • Clean-Code-Functions
  • Maintainability-Quality-API-Design
  • Clean-Code-Boolean-Parameters

Comment on lines +3560 to +3561
String protocolType = group.protocolType();
if (options.protocolTypes().isEmpty() || options.protocolTypes().contains(protocolType)) {
Copy link

Choose a reason for hiding this comment

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

Duplicate Protocol Filtering

Protocol type filtering is duplicated between client and server. The server already filters by protocol type in ListGroupsRequest, making client-side filtering redundant. This creates maintenance burden when protocol handling changes.

Standards
  • Clean-Code-DRY
  • Maintainability-Quality-Duplication
  • Design-Pattern-Consistency

Comment on lines +3535 to +3556
if (tryUsingEarlierRequestVersion) {
List<String> groupStates = options.groupStates()
.stream()
.map(GroupState::toString)
.collect(Collectors.toList());
return new ListGroupsRequest.Builder(new ListGroupsRequestData()
.setStatesFilter(groupStates)
);
} else {
List<String> groupTypes = options.types()
.stream()
.map(GroupType::toString)
.collect(Collectors.toList());
List<String> groupStates = options.groupStates()
.stream()
.map(GroupState::toString)
.collect(Collectors.toList());
return new ListGroupsRequest.Builder(new ListGroupsRequestData()
.setTypesFilter(groupTypes)
.setStatesFilter(groupStates)
);
}
Copy link

Choose a reason for hiding this comment

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

Repeated Request Logic

Duplicated code for creating groupStates list in both branches increases maintenance burden. The stream transformation of groupStates is repeated, violating DRY principle. Extract common code to reduce duplication and improve maintainability.

Standards
  • Clean-Code-DRY
  • Refactoring-Extract-Method
  • Maintainability-Quality-Duplication

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.

3 participants