[Java] Java code that cannot be used from Kotlin (for in-house study sessions)

2 minute read

  • Overview -We will announce the problem I was addicted to at work -Actually I’m not sure, so please comment if you understand
  • Assumption -Use Java library from Kotlin with Android Kotlin/JVM

Actually addicted code

Desk.java


package library_package;

abstract class BaseDesk {
    public enum Color {BLUE, ORANGE}
}

public class Desk extends BaseDesk {
    private Color color;

    public Desk(Color color) {
        this.color = color;
    }
}

Using such a Java implementation from Java works, of course.

java


new Desk(Desk.Color.BLUE);

Compile Error when used from Kotlin.

kotlin


Desk(Desk.Color.BLUE) // Unresolved reference: Color

kotlin


import library_package.BaseDesk // Cannot access'BaseDesk': it is package-private in'library_package'

Desk(BaseDesk.Color.BLUE) // Cannot access'Color': it is public in'BaseDesk'

How to avoid

A static method called getColorEnum() was provided to solve this problem.

Desk.java


package library_package;

abstract class BaseDesk {
    public enum Color {BLUE, ORANGE}

    public static Color getColorEnum(String name) {
        return Color.valueOf(name);
    }
}

kotlin


@Suppress("INACCESSIBLE_TYPE") // suppress warning is required
Desk(Desk.getColorEnum("BLUE")) // I was able to put a Color instance in the Desk constructor

Why did I get an error or not?

Looking at what kind of case causes an error…

Foo.java


class BaseFoo {
    public static int i = 0;

    public static int inc() {
        return ++i;
    }

    public static class FooFoo {
        public static int j = 0;
    }
}

public class Foo extends BaseFoo {}

java


int foo_i = Foo.i;
int foo_inc = Foo.inc();
int foo_foo_j = Foo.FooFoo.j;

kotlin


val foo_i = Foo.i
val foo_inc = Foo.inc()
val foo_foo_j: Int = Foo.FooFoo.j // Unresolved reference: FooFoo

Kotlin doesn’t seem to have access to the static inner class of the super class. I did some research on the underlying language specification, but I did not understand it.


Why could it be used as the return value of a method?

Java seems to be able to define an invisible class as a return value.

public class Bar {
    public static InternalBar getBar() {
        return new InternalBar();
    }

    private static class InternalBar extends Bar {}
}

Bar bar = Bar.getBar(); // OK

You can’t do this with Kotlin.

open class Baz {
    companion object {
        fun getInternalBaz(): InternalBaz {/ /'public' function exposes its'private' return type InternalBaz
            return InternalBaz()
        }

        fun getBaz(): Baz {// OK
            return InternalBaz()
        }
    }
    private class InternalBaz: Baz()
}

What is #INACCESSIBLE_TYPE warning?

There is a problem that the behavior of Kotlin Compiler, which causes an error when it cannot be referenced, does not compile properly because it does not match the Java specifications as described above, and now it is Warning instead of Compile Error. It seems that it will be changed again so that a compilation error will occur only when it is not possible.

See https://youtrack.jetbrains.com/issue/KT-11398.


What if getColorEnum() is not provided on the Library side?

You can create the Utility Method in Java by yourself.

DeskColorResolver.java


import library_package.Desk;

public class DeskColorResolver {
    public static Desk.Color getColor(String name) {
        return Desk.Color.valueOf(name);
    }
}

kotlin


val desk = Desk(DeskColorResolver.getColorEnum("BLUE"))

Can be written. Is this really the right answer…?


thanks!