ProGuard: ClassCastException
Asked Answered
B

2

5

I'm getting this annoying ClassCastException when I obfuscate my Java code (which works fine before I obfuscate using ProGuard).

   java.lang.ClassCastException: com.google.gson.internal.StringMap cannot be cast to net.minecraft.launcher.profile.Profile
        at java.lang.ClassCastException: com.google.gson.internal.StringMap cannot be cast to net.minecraft.launcher.profile.Profile
at net.minecraft.launcher.profile.ProfileManager.getSelectedProfile(SourceFile:117)
at net.minecraft.launcher.g.run(SourceFile:184)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

That ClastCastException error points to this bit of code, here (the bolded line being the exact line):

public Profile getSelectedProfile()
{
    if ((this.selectedProfile == null) || (!this.profiles.containsKey(this.selectedProfile))) {
        if (this.profiles.get("Default") != null)
        {
            this.selectedProfile = "Default";
        }
        else if (this.profiles.size() > 0)
        {
            this.selectedProfile = ((Profile)this.profiles.values().iterator().next()).getName();
        }
        else
        {
            this.selectedProfile = "Default";
            this.profiles.put("Default", new Profile(this.selectedProfile));
        }
    }
    *Profile profile = this.profiles.get(this.selectedProfile);*
    return profile;
}

Whole Class File (Un obfuscated) : http://pastebin.com/Jgh4x1SS RawProfileList Class File (Un obfuscated) : http://pastebin.com/vPxFpYfC ProGuard version : 5.2.1

Declaration of Profiles field:

private final Map<String, Profile> profiles = new HashMap<String, Profile>();
Bussey answered 8/5, 2015 at 10:32 Comment(9)
Please show us the declaration of selectedProfile and profiles fields. Also if it's possible, please provide a non-obfuscated and obfuscated .class file. And which version of ProGuard are you using?Proleg
Added to bottom of post. Whole Class File (Un obfuscated) : pastebin.com/Jgh4x1SS ProGuard version : 5.2.1 Declaration of Profiles field: private final Map<String, Profile> profiles = new HashMap<String, Profile>();Bussey
Who writes in the profiles map? I suspect there is something in the Minecraft framework that uses reflection to decide what to populate your map with, and since the names have changed, it behaves differently with the obfuscated code.Grainger
Show us the RawProfileList class.Colfin
@Grainger if you look in this class (pastebin.com/Jgh4x1SS) the loadProfiles uses gson's fromJson method to set rawProfile's profiles to the values. RawProfileList class = pastebin.com/Jgh4x1SSBussey
That's where I would start looking then. If you're getting a class cast exception when getting a value from a map, always look at the put, that's where the problems are likely to be.Grainger
Does your proguard.cfg contain these rules?Colfin
@EgorN Not all of it, only some. This is my proguard config file: pastebin.com/68gec9uGBussey
@EgorN It worked!!! don't know how, but it did. I'm curious to know how it worked.Bussey
C
6

Your classes look fine. ClassCastException means that Gson didn't know that a field should have been serialized as Profile.

Make sure your proguard.cfg contains all of these rules.

Colfin answered 9/5, 2015 at 9:13 Comment(0)
M
1

Adding to @EgorNeliuba's excellent answer, as these rules alone were insufficient in my situation:

  1. MyPrettyAmazingDataStruct is fully serialized and instantiated from a corresponding JSON in debug mode.
  2. MyApp is using MyCoreLib, hence 2 build.gradle files and 2 proguard.cfg files.

My ordeal started when my APK started crashing with:

java.lang.ClassCastException: e2.s cannot be cast to com.me.mycorelib.MyPrettyAmazingDataStruct

I checked mapping.txt and the only obfuscation to e2.s is:

com.google.gson.internal.LinkedTreeMap -> e2.s

Note: Getting Logcat to log messages from a Proguard-processed APK was an ordeal by itself because I did not know that the -assumenosideeffects class android.util.Log should be commented out in MyApp's proguard.cfg as well. It is not enough to do so in MyCoreLib's proguard.cfg only.

So, I naively added to both proguard.cfg files the following:

-keep public class com.me.mycorelib.MyPrettyAmazingDataStruct
-keepnames class  com.me.mycorelib.MyPrettyAmazingDataStruct
-keepclassmembers class com.me.mycorelib.MyPrettyAmazingDataStruct

That did not eliminate the exception.

Then I found @EgorNeliuba's answer which added these rules (to both files!) and now MyApp is no longer crashing.

Lastly, it was helpful for me to finally understand the differences between:

Option Class Name Class Code Member Name Member Code
-keep Preserved Preserved Preserved Preserved
-keepnames Preserved Optimized Preserved Optimized
-keepclassmembers Optimized Optimized Preserved Preserved

Please correct the above table if you spot any mistake.

Masinissa answered 21/7, 2023 at 6:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.