Skip to content

Commit e5f50e4

Browse files
authored
feat: Migrate setUserAttribute (#689)
* feat: align onSetUserAttribute with UserAttributeListener (nullable params, naming) - SingularKit: key/value/user naming, null checks for Java interop - AppsFlyerKit, Braze AppboyKit: consistent UserAttributeListener overrides Made-with: Cursor * feat: move onSetUserAttribute to BaseAttributeListener - KitIntegration: declare onSetUserAttribute on BaseAttributeListener; remove from UserAttributeListener - KitManagerImpl: dispatch scalar and CSV list paths via BaseAttributeListener; avoid double calls for dual-interface kits - AttributeListener-only kits: delegate onSetUserAttribute to setUserAttribute - AttributeListenerTestKit: implement onSetUserAttribute Made-with: Cursor * Remove setUserAttribute from AttributeListener; route via onSetUserAttribute - Drop setUserAttribute from KitIntegration.AttributeListener; kits keep setUserAttribute as a regular method (no override). - KitManagerImpl: use BaseAttributeListener.onSetUserAttribute for scalar and joined list paths; prefer UserAttributeListener when both interfaces apply. - AttributeListenerTestKit: rename callback to setUserAttributeCallback; update DataplanBlockingUserTests. Made-with: Cursor * Inline user attribute handling in onSetUserAttribute; remove kit setUserAttribute - Move scalar attribute logic from removed setUserAttribute helpers into onSetUserAttribute (or private helpers shared with setAllUserAttributes). - Braze: applyScalarUserAttribute for onSet + initial sync; update unit tests to call onSetUserAttribute with a mocked FilteredMParticleUser. - AttributeListenerTestKit: inline callback/onAttributeReceived in onSetUserAttribute. Made-with: Cursor * KitManagerImpl: restore AttributeListener before UserAttributeListener for list attrs Re-run both branches when a kit implements both interfaces; UserAttributeListener join path calls UserAttributeListener.onSetUserAttribute again. Made-with: Cursor * Braze kit: extract scalar user attribute branches into helpers Split applyScalarUserAttribute into applyScalarUserAttributeOnUser plus focused helpers for age, email/push subscribe, gender, subscription groups, and unmapped custom keys (braze-38 through braze-41). Made-with: Cursor * KitManagerImplTest: verify onSetUserAttribute for list-as-CSV path AttributeListener no longer has setUserAttribute; assert BaseAttributeListener onSetUserAttribute with joined value and FilteredMParticleUser. Made-with: Cursor * KitManagerImplTest: expect null FilteredMParticleUser in list CSV verify FilteredMParticleUser.getInstance returns null in JVM unit tests; Mockito any(Class) does not match null. Use isNull() for the third onSetUserAttribute arg. Made-with: Cursor * Align onSetUserAttribute Kotlin overrides with nullable key and value - Use String? and Any? for parameters matching Java Object/null call paths - Add early returns when key or value is null where needed - CleverTap: rename parameters to key/value; use mappedKey/mappedValue for mutations Made-with: Cursor * Use nullable FilteredMParticleUser in onSetUserAttribute overrides Third parameter is user: FilteredMParticleUser? to match KitManagerImpl and FilteredMParticleUser.getInstance. GA/GA4 use parameter name user. Made-with: Cursor
1 parent 9d07e1c commit e5f50e4

27 files changed

Lines changed: 642 additions & 451 deletions

File tree

android-kit-base/src/androidTest/kotlin/com/mparticle/kits/DataplanBlockingUserTests.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class DataplanBlockingUserTests : BaseKitOptionsTest() {
7777
assertTrue(allowedAttributes.containsKey(key))
7878
assertFalse(blockedAttributes.containsKey(key))
7979
}
80-
attributeListenerKitKit.setUserAttribute = { key, _ ->
80+
attributeListenerKitKit.setUserAttributeCallback = { key, _ ->
8181
assertTrue(allowedAttributes.containsKey(key))
8282
assertFalse(blockedAttributes.containsKey(key))
8383
}

android-kit-base/src/androidTest/kotlin/com/mparticle/kits/testkits/AttributeListenerTestKit.kt

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ open class AttributeListenerTestKit :
1010
ListenerTestKit(),
1111
AttributeListener,
1212
LogoutListener {
13-
var setUserAttribute: ((attributeKey: String?, attributeValue: String?) -> Unit)? = null
13+
var setUserAttributeCallback: ((attributeKey: String?, attributeValue: String?) -> Unit)? = null
1414
var setUserAttributeList: ((attributeKey: String?, attributeValueList: List<String?>?) -> Unit)? =
1515
null
1616
var supportsAttributeLists: (() -> Boolean)? = null
@@ -41,14 +41,6 @@ open class AttributeListenerTestKit :
4141
userAttributeLists.forEach { onAttributeReceived?.invoke(it.key, it.value) }
4242
}
4343

44-
override fun setUserAttribute(
45-
attributeKey: String,
46-
attributeValue: String?,
47-
) {
48-
setUserAttribute?.invoke(attributeKey, attributeValue)
49-
onAttributeReceived?.invoke(attributeKey, attributeValue)
50-
}
51-
5244
override fun setUserIdentity(
5345
identityType: MParticle.IdentityType,
5446
identity: String?,
@@ -70,5 +62,17 @@ open class AttributeListenerTestKit :
7062
onAttributeReceived?.invoke(key, null)
7163
}
7264

65+
override fun onSetUserAttribute(
66+
key: String?,
67+
value: Any?,
68+
user: FilteredMParticleUser?,
69+
) {
70+
if (key == null || value == null || value !is String) {
71+
return
72+
}
73+
setUserAttributeCallback?.invoke(key, value)
74+
onAttributeReceived?.invoke(key, value)
75+
}
76+
7377
override fun logout(): List<ReportingMessage> = logout?.invoke() ?: listOf()
7478
}

android-kit-base/src/main/java/com/mparticle/kits/KitIntegration.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,19 @@ public interface BaseAttributeListener {
387387
* @param user filtered user context for this kit
388388
*/
389389
void onRemoveUserAttribute(String key, FilteredMParticleUser user);
390+
391+
/**
392+
* Called when a scalar user attribute is set for the current user.
393+
*
394+
* @param key attribute key
395+
* @param value attribute value (may be non-String for some {@link UserAttributeListener} call paths)
396+
* @param user filtered user context for this kit
397+
*/
398+
void onSetUserAttribute(String key, Object value, FilteredMParticleUser user);
390399
}
391400

392401
public interface AttributeListener extends BaseAttributeListener {
393402

394-
void setUserAttribute(String attributeKey, String attributeValue);
395-
396403
void setUserAttributeList(String attributeKey, List<String> attributeValueList);
397404

398405
void setAllUserAttributes(Map<String, String> userAttributes, Map<String, List<String>> userAttributeLists);
@@ -556,8 +563,6 @@ public interface UserAttributeListener extends BaseAttributeListener {
556563

557564
void onIncrementUserAttribute(String key, Number incrementedBy, String value, FilteredMParticleUser user);
558565

559-
void onSetUserAttribute(String key, Object value, FilteredMParticleUser user);
560-
561566
void onSetUserTag(String key, FilteredMParticleUser user);
562567

563568
void onSetUserAttributeList(String attributeKey, List<String> attributeValueList, FilteredMParticleUser user);

android-kit-base/src/main/java/com/mparticle/kits/KitManagerImpl.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -685,34 +685,30 @@ private void setUserAttribute(KitIntegration provider, String attributeKey, List
685685
&& !provider.isDisabled()
686686
&& KitConfiguration.shouldForwardAttribute(provider.getConfiguration().getUserAttributeFilters(), attributeKey)) {
687687
boolean supportsAttributeLists = ((KitIntegration.BaseAttributeListener) provider).supportsAttributeLists();
688+
FilteredMParticleUser user = FilteredMParticleUser.getInstance(mpid, provider);
688689
if (provider instanceof KitIntegration.AttributeListener) {
689690
if (supportsAttributeLists) {
690691
((KitIntegration.AttributeListener) provider).setUserAttributeList(attributeKey, valueList);
691692
} else {
692-
((KitIntegration.AttributeListener) provider).setUserAttribute(attributeKey, KitUtils.join(valueList));
693+
((KitIntegration.BaseAttributeListener) provider).onSetUserAttribute(attributeKey, KitUtils.join(valueList), user);
693694
}
694695
}
695696
if (provider instanceof KitIntegration.UserAttributeListener) {
696697
if (supportsAttributeLists) {
697-
((KitIntegration.UserAttributeListener) provider).onSetUserAttributeList(attributeKey, valueList, FilteredMParticleUser.getInstance(mpid, provider));
698+
((KitIntegration.UserAttributeListener) provider).onSetUserAttributeList(attributeKey, valueList, user);
698699
} else {
699-
((KitIntegration.UserAttributeListener) provider).onSetUserAttribute(attributeKey, KitUtils.join(valueList), FilteredMParticleUser.getInstance(mpid, provider));
700+
((KitIntegration.UserAttributeListener) provider).onSetUserAttribute(attributeKey, KitUtils.join(valueList), user);
700701
}
701702
}
702703
}
703704
}
704705

705706
private void setUserAttribute(KitIntegration provider, String attributeKey, String attributeValue, long mpid) {
706-
if ((provider instanceof KitIntegration.AttributeListener || provider instanceof KitIntegration.UserAttributeListener)
707+
if ((provider instanceof KitIntegration.BaseAttributeListener listener)
707708
&& !provider.isDisabled()
708709
&& KitConfiguration.shouldForwardAttribute(provider.getConfiguration().getUserAttributeFilters(),
709710
attributeKey)) {
710-
if (provider instanceof KitIntegration.AttributeListener) {
711-
((KitIntegration.AttributeListener) provider).setUserAttribute(attributeKey, attributeValue);
712-
}
713-
if (provider instanceof KitIntegration.UserAttributeListener) {
714-
((KitIntegration.UserAttributeListener) provider).onSetUserAttribute(attributeKey, attributeValue, FilteredMParticleUser.getInstance(mpid, provider));
715-
}
711+
listener.onSetUserAttribute(attributeKey, attributeValue, FilteredMParticleUser.getInstance(mpid, provider));
716712
}
717713
}
718714

@@ -745,8 +741,8 @@ public void incrementUserAttribute(String key, Number incrementedBy, String newV
745741
if (provider instanceof KitIntegration.UserAttributeListener) {
746742
((KitIntegration.UserAttributeListener) provider).onIncrementUserAttribute(key, incrementedBy, newValue, FilteredMParticleUser.getInstance(mpid, provider));
747743
}
748-
if (provider instanceof KitIntegration.AttributeListener) {
749-
((KitIntegration.AttributeListener) provider).setUserAttribute(key, newValue);
744+
if (provider instanceof KitIntegration.BaseAttributeListener listener) {
745+
listener.onSetUserAttribute(key, newValue, FilteredMParticleUser.getInstance(mpid, provider));
750746
}
751747
} catch (Exception e) {
752748
Logger.warning("Failed to call onIncrementUserAttribute for kit: " + provider.getName() + ": " + e.getMessage());

android-kit-base/src/test/kotlin/com/mparticle/kits/KitManagerImplTest.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.mparticle.internal.Logger
2323
import com.mparticle.internal.MPUtility
2424
import com.mparticle.internal.SideloadedKit
2525
import com.mparticle.kits.KitIntegration.AttributeListener
26+
import com.mparticle.kits.KitIntegration.BaseAttributeListener
2627
import com.mparticle.mock.MockContext
2728
import com.mparticle.mock.MockKitConfiguration
2829
import com.mparticle.mock.MockKitManagerImpl
@@ -49,6 +50,8 @@ import org.junit.Test
4950
import org.junit.runner.RunWith
5051
import org.mockito.ArgumentCaptor
5152
import org.mockito.ArgumentMatchers.any
53+
import org.mockito.ArgumentMatchers.eq
54+
import org.mockito.ArgumentMatchers.isNull
5255
import org.mockito.Mockito
5356
import org.mockito.Mockito.mock
5457
import org.mockito.Mockito.never
@@ -557,8 +560,8 @@ class KitManagerImplTest {
557560
manager.setUserAttributeList("test key", attributeList, 1)
558561
verify(integration as AttributeListener, Mockito.times(1))
559562
.setUserAttributeList("test key", attributeList)
560-
verify(integration2 as AttributeListener, Mockito.times(1))
561-
.setUserAttribute("test key", "1,2,3")
563+
verify(integration2 as BaseAttributeListener, Mockito.times(1))
564+
.onSetUserAttribute(eq("test key"), eq("1,2,3"), isNull())
562565
}
563566

564567
@Test

kits/adobe/adobe-5/src/main/kotlin/com/mparticle/kits/AdobeKitBase.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ abstract class AdobeKitBase :
4848
syncIds()
4949
}
5050

51-
override fun setUserAttribute(
52-
s: String,
53-
s1: String,
54-
) {
55-
syncIds()
56-
}
57-
5851
override fun setUserAttributeList(
5952
s: String,
6053
list: List<String>,
@@ -78,6 +71,17 @@ abstract class AdobeKitBase :
7871
syncIds()
7972
}
8073

74+
override fun onSetUserAttribute(
75+
key: String?,
76+
value: Any?,
77+
user: FilteredMParticleUser?,
78+
) {
79+
if (key == null || value == null || value !is String) {
80+
return
81+
}
82+
syncIds()
83+
}
84+
8185
override fun setUserIdentity(
8286
identityType: IdentityType,
8387
s: String,

kits/adobemedia/adobemedia-5/src/main/kotlin/com/mparticle/kits/AdobeKit.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,6 @@ open class AdobeKit :
8585
syncIds()
8686
}
8787

88-
override fun setUserAttribute(
89-
s: String,
90-
s1: String,
91-
) {
92-
syncIds()
93-
}
94-
9588
override fun setUserAttributeList(
9689
s: String,
9790
list: List<String>,
@@ -115,6 +108,17 @@ open class AdobeKit :
115108
syncIds()
116109
}
117110

111+
override fun onSetUserAttribute(
112+
key: String?,
113+
value: Any?,
114+
user: FilteredMParticleUser?,
115+
) {
116+
if (key == null || value == null || value !is String) {
117+
return
118+
}
119+
syncIds()
120+
}
121+
118122
override fun setUserIdentity(
119123
identityType: MParticle.IdentityType,
120124
s: String,

kits/appsflyer/appsflyer-6/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,6 @@ class AppsFlyerKit :
248248
return messageList
249249
}
250250

251-
override fun setUserAttribute(
252-
attributeKey: String,
253-
attributeValue: String,
254-
) {}
255-
256251
override fun setUserAttributeList(
257252
s: String,
258253
list: List<String>,

kits/apptimize/apptimize-3/src/main/kotlin/com/mparticle/kits/ApptimizeKit.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,6 @@ class ApptimizeKit :
121121

122122
override fun getName(): String = KIT_NAME
123123

124-
override fun setUserAttribute(
125-
key: String,
126-
value: String,
127-
) {
128-
Apptimize.setUserAttribute(key, value)
129-
}
130-
131124
/**
132125
* Not supported by the Apptimize kit.
133126
*/
@@ -148,7 +141,7 @@ class ApptimizeKit :
148141
attributeLists: Map<String, List<String>>,
149142
) {
150143
for ((key, value) in attributes) {
151-
setUserAttribute(key, value)
144+
Apptimize.setUserAttribute(key, value)
152145
}
153146
}
154147

@@ -159,6 +152,17 @@ class ApptimizeKit :
159152
Apptimize.clearUserAttribute(key)
160153
}
161154

155+
override fun onSetUserAttribute(
156+
key: String?,
157+
value: Any?,
158+
user: FilteredMParticleUser?,
159+
) {
160+
if (key == null || value == null || value !is String) {
161+
return
162+
}
163+
Apptimize.setUserAttribute(key, value)
164+
}
165+
162166
/**
163167
* @param identityType only Alias and CustomerId are suppoted by the Apptimize kit.
164168
*/

kits/branch/branch-5/src/main/kotlin/com/mparticle/kits/BranchMetricsKit.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,6 @@ class BranchMetricsKit :
174174
)
175175
}
176176

177-
override fun setUserAttribute(
178-
s: String,
179-
s1: String,
180-
) {}
181-
182177
override fun setUserAttributeList(
183178
s: String,
184179
list: List<String>,
@@ -198,6 +193,14 @@ class BranchMetricsKit :
198193
// No-op: this kit does not implement this feature.
199194
}
200195

196+
override fun onSetUserAttribute(
197+
key: String?,
198+
value: Any?,
199+
user: FilteredMParticleUser?,
200+
) {
201+
// No-op: this kit does not implement this feature.
202+
}
203+
201204
override fun setUserIdentity(
202205
identityType: IdentityType,
203206
s: String,

0 commit comments

Comments
 (0)