Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

People.set throwing UnsupportedOperationException #803

Closed
badoualy opened this issue Oct 15, 2022 · 6 comments
Closed

People.set throwing UnsupportedOperationException #803

badoualy opened this issue Oct 15, 2022 · 6 comments

Comments

@badoualy
Copy link

badoualy commented Oct 15, 2022

An exception is thrown when calling set on people
SDK version: 6.5.2

Non-fatal Exception: java.lang.UnsupportedOperationException
       at java.util.Collections$UnmodifiableMap.put(Collections.java:1504)
       at org.json.JSONObject.put(JSONObject.java:1056)
       at com.mixpanel.android.mpmetrics.MixpanelAPI$PeopleImpl.set(MixpanelAPI.java:1888)
       at com.mixpanel.android.mpmetrics.MixpanelAPI$PeopleImpl.setMap(MixpanelAPI.java:1875)

In the mean time I tried to bypass by using unset on all properties, then setOnceMap

@chichi289
Copy link

chichi289 commented Oct 21, 2022

@badoualy

I also faces same error when setting data on people like below

mixPanel.people.set(JSONObject().apply {
            put("name".addDollar(),user.vName)
            put("email".addDollar(), user.vEmailId)
            put(KEY_MOBILE_NUMBER, user.vMobileNumber)
            put(KEY_INSTALLED_FROM, user.vReferalPlatform)
        })

I get error as below

Caused by: java.lang.UnsupportedOperationException
        at java.util.Collections$UnmodifiableMap.put(Collections.java:1504)

It is crashing only in release build in debug build working fine.

I have already used pro guard for the Mix Panel SDK.

Please let me know if you find any solution for the same.

Thank you

UPDATE

I downgraded SDK version to 6.5.1 and it's working fine but events are not being logged in mixpanel dashboard

@badoualy
Copy link
Author

badoualy commented Oct 21, 2022

Indeed I forgot to mention it seems to be working fine on debug builds.

@chichi289 FYI I used the following bypass, that seems to work:

    override suspend fun setPeople(properties: Map<String, Any?>) {
        with(mixpanel.people) {
            properties.keys.forEach { unset(it) }
            setOnceMap(properties.filterValues { it != null })
        }
    }

setOnceMap is not building a JsonObject like set is doing, so the bug won't occur

@chichi289
Copy link

chichi289 commented Oct 21, 2022

@badoualy Thanks for the suggestions

I imported mix panel library as a module in project and checked the code which causes exception.

@Override
        public void set(JSONObject properties) {
            if (hasOptedOutTracking()) return;
            try {
                final JSONObject sendProperties = new JSONObject(mDeviceInfo);
                for (final Iterator<?> iter = properties.keys(); iter.hasNext(); ) {
                    final String key = (String) iter.next();
                    sendProperties.put(key, properties.get(key));
                }

                final JSONObject message = stdPeopleMessage("$set", sendProperties);
                recordPeopleMessage(message);
            } catch (final JSONException e) {
                MPLog.e(LOGTAG, "Exception setting people properties", e);
            }
        }
   final JSONObject sendProperties = new JSONObject(mDeviceInfo);

Here mDeviceInfo is passed in JSONObject constructure which causes crash as it is constructed as unmodified map as below

mDeviceInfo = Collections.unmodifiableMap(deviceInfo);

So my guess is somewhere it is being modified.

If we remove mDeviceInfo from JSONObject constructor then code is compiled and worked fine in release app.

@badoualy setOnceMap is working as it is not using mDeviceInfo internally

@zihejia Please look into this and provide solutions for the same

Thank you

@badoualy
Copy link
Author

badoualy commented Oct 21, 2022

Ah indeed, it might be linked to a bad dependency. When checking the code, I had another version of JSONObject that's actually not using the map directly, but adding each entry into its interval map (which wouldn't cause the issue)

    public JSONObject(@NonNull Map copyFrom) {
        this();
        Map<?, ?> contentsTyped = (Map<?, ?>) copyFrom;
        for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {
            /*
             * Deviate from the original by checking that keys are non-null and
             * of the proper type. (We still defer validating the values).
             */
            String key = (String) entry.getKey();
            if (key == null) {
                throw new NullPointerException("key == null");
            }
            nameValuePairs.put(key, wrap(entry.getValue()));
        }
    }

But I also have this version in my classpath:

    public JSONObject(Map var1) {
        this.map = (Map)(var1 == null ? new HashMap() : var1);
    }

Not sure which one mixpanel is supposed to use. Maybe it's another dependency in our project that's overriding the dependency that mixpanel SDK is using?

Edit: ok so in my case, it looks like the socket-io lib that I'm using is using the following dependency:

    <dependency>
      <groupId>org.json</groupId>
      <artifactId>json</artifactId>
      <version>20090211</version>
    </dependency>

which is the version using the map passed to the constructor as is without making a copy.
So using an exclude module on the socket-io should fix the issue.

So the issue isn't actually with mixpanel SDK, but maybe a disclaimer about this could be nice in the setup doc

@chichi289
Copy link

@badoualy Yes I have also used socket io library so after removing json from socket io it is working fine

implementation ('io.socket:socket.io-client:2.1.0'){
      exclude group: 'org.json', module: 'json'
  }

Thanks for the help @badoualy

@zihejia
Copy link
Collaborator

zihejia commented Jun 15, 2023

Thanks guys for bringing this up and finding a solution. I've added this issue to the FAQ section of our documentation.

@zihejia zihejia closed this as completed Jun 15, 2023
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

No branches or pull requests

3 participants