[Kotlin] Get rid of Kotlin generated check — “null cannot be cast to non-null type”

kokchai
2 min readMay 7, 2020

Use case 1:

The code below is to cast (as) a nullable variable:

data class Boss(val name: String)

data class Staff(val name: String)

fun getPerson(type: String, name: String): Any? {
return when (type) {
"boss" -> Boss(name)
"staff" -> Staff(name)
else -> null
}
}
fun main() {
val boss = getPerson("boss", "Peter") as Boss
print(boss)
}

Highlighted points:

  1. getPerson() might return null
  2. Boss and Staff are supposed to be obfuscated and no clues in getPerson()

Let’s look at the decompiled code below:

/* This is Boss */
public static final class C0374a {
/* renamed from: a */
public final String f8550a;
public C0374a(String str) {
this.f8550a = str;
}
...
}/* This is Staff */
public static final class C0379c {
/* renamed from: a */
public final String f8556a;
public C0379c(String str) {
this.f8556a = str;
}
...
}/* This is getPerson(String, String) */
public final Object mo12141a(String str, String str2) {
int hashCode = str.hashCode();
if (hashCode != 3029869) {
if (hashCode == 109757152 && str.equals("staff")) {
return new C0379c(str2);
}
} else if (str.equals("boss")) {
return new C0374a(str2);
}
return null;
}
/* This is main() */
public void mo12147a(boolean z) {
Object a = mo12141a("Boss", "Peter");
if (a != null) {
System.out.print((C0374a) a);
return;
}
throw new C3147k("null cannot be cast to non-null type Boss");
}

Highlighted points:

  1. In the obfuscated code, Boss is still visible

How to prevent null checkings in generated code ?

Solution A:

fun main() {
val temp = getPerson("boss", "Peter")
if (temp != null) {
val boss = temp as Boss
print(boss)
}
}

Solution B:

fun main() {
val boss = getPerson("boss", "Peter") as? Boss
print(boss?.name ?: "no boss")
}

Use case 2:

Slighly different from use case1:

open class A {
open fun print() {

}
}

class A1 : A() {
override fun print() {
print("A1")
}
}

class A2 : A() {
override fun print() {
print("B1")
}
}
/**
* This function won't return null
*/
fun getA(isA1: Boolean): Any {
return if (isA1) {
A1()
} else {
A2()
}
}

Look at the code below:

Non-obfuscated:
(getA(true) as A1).print()
Obfuscated:
Object c = mo12151c(true);
if (c != null) {
((C0374a) c).mo12159a();
}
// A1 is explored !!
throw new C3207k("null cannot be cast to non-null type A1");

Using same way to pretend:

val a1 = getA(true)
if (a1 != null) (a1 as A1).print()

Used in:

--

--