Skip to content

feat: inline user attribute removal in onRemoveUserAttribute#687

Merged
denischilik merged 9 commits into
workstation/6.0-Releasefrom
feat/user-attribute-listener-on-remove-user-attribute
Mar 31, 2026
Merged

feat: inline user attribute removal in onRemoveUserAttribute#687
denischilik merged 9 commits into
workstation/6.0-Releasefrom
feat/user-attribute-listener-on-remove-user-attribute

Conversation

@denischilik

Copy link
Copy Markdown
Contributor

Background

Attribute removal for kits is consolidated on BaseAttributeListener.onRemoveUserAttribute so the SDK does not rely on a separate AttributeListener.removeUserAttribute contract. Kits now implement removal in one place, which aligns with the broader move toward UserAttributeListener-style APIs.

What Has Changed

  • Removed removeUserAttribute from AttributeListener; kits keep removal logic only in onRemoveUserAttribute.
  • Updated Adobe, Adobe Media, Apptimize, Branch, Braze (38–41), Comscore, Kochava, Localytics, Singular, AppsFlyer, and Urban Airship kits accordingly.
  • Renamed the AttributeListenerTestKit test hook to removeUserAttributeListener and adjusted dataplan blocking tests.
  • Sonar: no-op comments on empty kit overrides where required.

Screenshots/Video

N/A (SDK behavior change, no UI).

Checklist

  • I have performed a self-review of my own code.
  • I have made corresponding changes to the documentation.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have tested this locally.

Additional Notes

Target branch: workstation/6.0-Release. Kits were validated with publishMavenPublicationToMavenLocal and testRelease using -Pmparticle.kit.mparticleFromMavenLocalOnly=true.

Branch renamed to feat/user-attribute-listener-on-remove-user-attribute (CI requires feat/ not feature/).

Introduce KitIntegration.BaseAttributeListener as the common superinterface
for AttributeListener and UserAttributeListener. Document it as a temporary
contract to enable incremental migration and smaller PRs.

Made-with: Cursor
Resolve via BaseAttributeListener before AttributeListener/UserAttributeListener
branches in onUserAttributesReceived and setUserAttribute(list).

Made-with: Cursor
UserAttributeListener.onRemoveUserAttribute now forwards to the existing
AttributeListener.removeUserAttribute implementation for braze-38 through braze-41.

Made-with: Cursor
Declare onRemoveUserAttribute on KitIntegration.BaseAttributeListener so
AttributeListener and UserAttributeListener implementors must implement it.
KitManagerImpl now dispatches removal once via BaseAttributeListener.

AttributeListener-only kits delegate onRemoveUserAttribute to removeUserAttribute;
AttributeListenerTestKit updated accordingly.

Made-with: Cursor
Drop void removeUserAttribute(String) from KitIntegration.AttributeListener.
Kits keep the same logic as private-style helpers (fun removeUserAttribute
without override) and still satisfy BaseAttributeListener via
onRemoveUserAttribute. AdobeKitBase implements onRemoveUserAttribute by
delegating to removeUserAttribute.

Made-with: Cursor
Move kit-specific handling from removed helper methods into
BaseAttributeListener.onRemoveUserAttribute implementations.
Rename AttributeListenerTestKit callback to removeUserAttributeListener.
Fix Braze custom-key branch for Kotlin smart-cast in Braze callback.

Made-with: Cursor
Document intentional empty overrides in Adobe, AppsFlyer, Branch, Braze,
and Kochava kits to satisfy SonarQube analysis.

Made-with: Cursor
@denischilik denischilik requested a review from a team as a code owner March 31, 2026 13:22
@cursor

cursor Bot commented Mar 31, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches shared kit forwarding logic for user attributes and updates many kit implementations, so regressions could affect attribute removal propagation across integrations despite the change being mostly mechanical.

Overview
Consolidates kit user-attribute removal into a single callback by introducing BaseAttributeListener and removing the separate AttributeListener.removeUserAttribute path, so KitManagerImpl.removeUserAttribute always dispatches via onRemoveUserAttribute with a FilteredMParticleUser.

Updates multiple kits and test kits to implement the new removal callback signature (and adjusts dataplan-blocking tests accordingly), plus minor no-op/comment cleanups in several kit overrides.

Written by Cursor Bugbot for commit 7ad01d4. This will update automatically on new commits. Configure here.

@denischilik denischilik changed the title refactor(kits): inline user attribute removal in onRemoveUserAttribute feat: inline user attribute removal in onRemoveUserAttribute Mar 31, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

if (provider instanceof KitIntegration.UserAttributeListener) {
((KitIntegration.UserAttributeListener) provider).onRemoveUserAttribute(key, FilteredMParticleUser.getInstance(mpid, provider));
}
listener.onRemoveUserAttribute(key, FilteredMParticleUser.getInstance(mpid, provider));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nullable user passed to non-null Kotlin parameter

Medium Severity

FilteredMParticleUser.getInstance(mpid, provider) can return null (e.g. if MParticle.getInstance() is null or user lookup fails), but several AttributeListener-only kits (Adobe, Apptimize, Branch, Comscore, Kochava, Localytics, Urban Airship) now declare onRemoveUserAttribute with a non-null user: FilteredMParticleUser parameter. Kotlin's intrinsic null check on non-null parameters will throw a runtime exception if null is passed from the Java caller. Previously these kits received removeUserAttribute(String) with no user parameter, so this crash path is newly introduced.

Additional Locations (2)
Fix in Cursor Fix in Web

Replace if/else chain with when for standard vs custom user attribute removal; behavior unchanged across braze 38-41 kits.

Made-with: Cursor
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
68.8% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@denischilik denischilik merged commit 9d07e1c into workstation/6.0-Release Mar 31, 2026
21 of 22 checks passed
@denischilik denischilik deleted the feat/user-attribute-listener-on-remove-user-attribute branch March 31, 2026 14:33
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