Why can't I access a superclass' enum in Kotlin? - java

I am converting a Java Android project to Kotlin.
I am using API.AI's client, which has two AIConfiguration classes:
Superclass
package ai.api;
public class AIConfiguration implements Cloneable {
public static enum SupportedLanguages {
English("en"),
//...
}
//...
}
Subclass
package ai.api.android;
public class AIConfiguration extends ai.api.AIConfiguration {
public enum RecognitionEngine {
//...
}
In my Java code, I was creating an instance of the subclass, as recommended in the api guide:
final AIConfiguration config = new AIConfiguration("TOKEN",
AIConfiguration.SupportedLanguages.English,
AIConfiguration.RecognitionEngine.System);
Once converted to Kotlin, it looks like this:
val config = AIConfiguration("TOKEN",
AIConfiguration.SupportedLanguages.English,
AIConfiguration.RecognitionEngine.System)
...which causes an Unresolved reference: SupportedLanguages.
I can update the reference to ai.api.AIConfiguration.SupportedLanguages.English, which compiles successfully.
I could import the superclass with import ai.api.AIConfiguration as SuperAIConfiguration and use SuperAIConfiguration.SupportedLanguages, but I would rather reference the enum directly on the subclass.
I don't get it: why is this reference valid in Java but not in Kotlin?

The visibility rules in Kotlin are different from those in Java. Kotlin classes do not "inherit" static nested classes from supertypes, because the rules get too complicated when companion objects come into play. We are trying to keep the rules as simple as possible, and normally there's no issue accessing a nested class through a supertype name, but in your case the short names of the subclass and superclass clash. This is not typical, so you have the options you listed in the question: a fully-qualified name or a rename on import.

Related

Accessing static inner class defined in Java, through derived class

I've got some classes defined in java, similar to the code below.
I'm trying to access SomeValue through a derived java class, which is allowed in java, but not in kotlin.
Is there a way to access the field through the derived class?
// java file
// -------------------------------------------------
class MyBaseClass {
public static final class MyInnerClass
{
public static int SomeValue = 42;
}
}
final class MyDerivedClass extends MyBaseClass {
}
// kotlin file
// -------------------------------------------------
val baseAccess = MyBaseClass.MyInnerClass.SomeValue;
// this compiles
val derivedAccess = MyDerivedClass.MyInnerClass.SomeValue;
// ^ compile error: Unresolved reference: MyInnerClass
In Kotlin, nested types and companion objects are not automatically inherited.
This behavior is not specific to Java, you can reproduce the same behavior in Kotlin alone:
open class Base {
class Nested
}
class Derived : Base()
val base = Base.Nested::class // OK
val derived = Derived.Nested::class // Error: 'Nested' unresolved
As such, you explicitly have to qualify the nested class using the base class.
This behavior was deliberately made more strict in Kotlin, to avoid some of the confusion in Java related to accessing static members/classes via derived types. You also see that a lot of IDEs warn you in Java when you use a derived class name to refer to static symbols in the base class.
Regarding terminology, Kotlin has a clear definition of inner classes (namely those annotated with the inner keyword). Not all nested classes are inner classes. See also here.
Related:
Kotlin - accessing companion object members in derived types
Kotlin: How can I create a "static" inheritable function?

Kotlin Error : 'public' function exposes its 'public/*package*/' return type argument

I am new to Kotlin and trying out to write some project using the language.
I am using Java library and extending a class from the library in my project and I am seeing this error message.
'public' function exposes its 'public/*package*/' return type argument FooSettings
I understand the problem is but I am not sure how to fix it in Kotlin since I am still trying get familiar with Kotlin.
I can see that Kotlin is being smart and only trying to return of type that extends FooSettings. However the problem is FooSettings is package public only which means that I cannot access if in my Kotlin project.
I did some research about Kotlin generics and use of in or out but I wasn't able to fix the problem.
Is there any work around that I can do in my Kotlin project to fix the error I am seeing?
Code snippet
This is sample of Java library class:
Note, I have no way to changing the implementation of the library. I must use this Library and extend it in Kotlin.
It seems odd to me that the java library is written such a way and expect it to be overridden but that is question for another day.
import java.util.Collections;
import java.util.List;
public abstract class ClassA {
public List<FooBuilder<?>> getBuilder(Foo foo) {
return Collections.emptyList();
}
}
public class Foo {
}
public abstract class FooBuilder<U extends FooBuilder.FooSettings> {
// implementation of Class
abstract static class FooSettings {
// implementation of Class
}
}
Normally Java classes would override the method like such:
import java.util.List;
public class MyJavaClassA extends ClassA {
#Override public List<FooBuilder<?>> getBuilder(final Foo foo) {
// implementation
}
}
But I am trying to write in Kotlin such that it looks like: Reminder that this Kotlin is depending on the Java library and does not have access to package public classes.
class MyKotlinClassA : ClassA() {
override fun getBuilder(foo: Foo): MutableList<FooBuilder<*>> {
// implementation
}
}
This causes error
'public' function exposes its 'public/*package*/' return type argument FooSettings
I presume that by "package public" you meant "package private"? In your example, FooBuilder.FooSettings has no visibility modifier so uses the Java default of package private. Assuming that's what you meant...
You will be able to access the package private class, FooSettings, in your Kotlin code, but only if you put that Kotlin code in a package matching the one where FooSettings is declared.
You'll still get the same compilation error, but that's not because you can't access the type: it's because you're trying to use it in a context which is more visible than the type's declaration. i.e. you're trying to take a package private type and use it as part of a public method's signature, which isn't allowed. To get round that problem you need to mark your Kotlin class as internal.
It's might also be worth mentioning that internal for Kotlin means it's visible in that module, not in that package. This is all explained in more detail here.
In my case, I was getting this error because I was importing a kotlin class variable from another java file which raised because of the auto conversion from java to kotlin by Android Studio.
I was able to fix it by changing all the references of the variable in the java file to its setters and getters.
eg:
// kotlin file
internal open class BubbleBaseLayout : FrameLayout {
var windowManager: WindowManager? = null
lateinit var viewParams: WindowManager.LayoutParams
// defined here
var layoutCoordinator: BubblesLayoutCoordinator? = null
// ...
}
// Java file
// This variable
if (layoutCoordinator != null) { ... }
Needs to be changed to
// layoutCoordinator to getlayoutCoordinator everywhere
if(getlayoutCoordinator() != null){ ... }

instantiating a Scala class using reflection Java's `newInstance`

For some special use-case I have a small utility to load Java classes from jars using a dynamic class loader DynamicClassLoader. This works fine for Java classes contained in jars. Loading Scala classes from a jar also works without problems. However, instantiating the loaded Scala class leads to the following exception. It looks like the Scala class has private default constructor? Note the compiled Scala class name ending with $
java.lang.IllegalAccessException: Class XXX can not access a member of class ScalaClassYYY$ with modifiers "private"
The snippet below illustrates the idea of what I'm trying to achieve and gives a bit more context. The exception happens at the annotated line:
// deploy and register the new code
byte[] jarBytes = (byte[]) ((Object) message.getAttachment("jar"));
String registerClassName = message.getAttachment("register");
logger.debug("the register is '" + registerClassName + "'");
DynamicClassLoader loader = new DynamicClassLoader(jarBytes);
Class<?> registerClass = loader.lookUp(registerClassName);
// ===> this is where the java.lang.IllegalAccessException happens
IRegisterExecutor registerExecutor = (IRegisterExecutor) registerClass.newInstance();
registerExecutor.register();
Any ideas how to fix?
Obviously, you need to make the default constructor public (it won't work for Java classes without a public default constructor either). E.g.
class ScalaClassYYY() {
...
}
or if you want primary constructor to take some arguments,
class ScalaClassYYY(arg1: Int) {
def this() = this(0)
}
But from
Note the compiled Scala class name ending with $
it seems like you are actually trying to instantiate a Scala object:
object ScalaClassYYY { ... }
In this case, you shouldn't create a new instance and instead use the existing one:
(IRegisterExecutor) registerClass.getField("MODULE$").get(null);
EDIT:
I don't see in your answer how you add a default public constructor to a Scala class that does NOT require any parameters.
A class (not an object) that doesn't require any parameters has a default public constructor already (my first example).
Actually in Java all classes by default offer a public default constructor
No. Only those classes which have no constructors which take arguments.
remove the "(it won't work for Java classes without a public default constructor either)" because it is wrong
The documentation for Class.newInstance() says
IllegalAccessException - if the class or its nullary constructor is not accessible.
So I am pretty sure it's right. If it does work for Java classes without a public default constructor, this seems to be a major bug in the class loader you use. You can test it with a Java class which looks like this:
public class TestClass implements IRegisterExecutor {
public TestClass(int dummy) {}
// some implementation for IRegisterExecutor methods to get it to compile
}

can't cast to implemented interface

i'm very confused...
I have a class which directly implements an interface:
public class Device implements AutocompleteResult
{...}
Here is proof that I'm looking at the right variables:
Object match = ...;
log.debug(match.getClass()); // Outputs 'Device'
log.debug(match.getClass().getInterfaces()[0]); // Outputs 'AutocompleteResult'
Yet when I try to cast an instance of the class to the interface:
AutocompleteResult result = (AutocompleteResult) match;
I get a ClassCastException!
ClassCastException: Device cannot be cast to AutocompleteResult
Also, isAssignableFrom returns false and i'm not sure why:
log.debug(AutocompleteResult.class.isAssignableFrom(Device.class));
from the doc:
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.
Shouldn't I always be able to cast a object to an interface its class implements?
Thanks.
This can happen if two different classloaders load a class named AutocompleteResult.
These two classes are then treated as entirely different classes, even if they have the same package and name (and even implementation/fields/methods).
A common cause for this is if you use some kind of plugin system and both your base classes and the plugin classes provide the same class.
To check for this issue print the value returned by Class.getClassLoader() on both offending classes (i.e. the class of the interface implemented by Device and the result of AutocompleteResult.class).
AKA when Java apparently doesn't Java.
I hit this problem recently with Play Framework 2.6.3, what helped me was this:
https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader
I leave this info here for the people that might have the same problem.
To make it clearer, what helps is:
Injecting Application on an Eager Singleton and then using its classloader to load the classes I was having issues with.
To make it clearer
public class Module {
#Override
public void configure {
bind(TheClassLoaderLoader.class).asEagerSingleton()
public static class TheClassLoaderLoader {
#Inject
public TheClassLoaderLoader( Application application) {
ClassLoader classloader = application.classloader();
Class<?> interfaceClass = classloader.loadClass(InterfaceClass.class.getName());
classloader.loadClass(ImplementsInterfaceClass.class.getName()).asSubclass(interfaceClass);
The example here https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings
That uses Environment often throws a frustrating ClassNotFoundException
Cheers

type definition in a package object "hijacking" the inheritance of a java class in scala code

I have the following situation:
I have a Java class hierarchy like this:
package org.foo.some;
public class Model extends org.foo.some.GenericModel { // ... }
package org.bar;
public class MyModel extends org.foo.some.Model { // ... }
where org.foo.some.Model and org.foo.some.GenericModel are out of my reach (not my code). In Scala, also out of my reach, there is:
package org {
package foo {
package object some {
type Model = org.foo.some.ScalaModel
}
}
}
This leads to a funny behavior in Scala code, e.g.
val javaModel:MyModel = new org.bar.MyModel()
trait FooTrait[T <: org.foo.some.GenericModel] { // ... }
class FooClass extends FooTrait[MyModel] { //... }
does not compile and raises the following error:
type arguments [org.bar.MyModel] do not conform to trait FooTrait's type
parameter bounds [T <: org.foo.some.GenericModel]
Further, I can't invoke any method of org.foo.some.Model nor of org.foo.some.GenericModel on javaModel:
javaModel.doSomething()
raises
value create is not a member of org.bar.MyModel
I am under the impression that the package object is "hijacking" the visibility of the Java class hierarchy in Scala code. Indeed, ScalaModel does not extend org.foo.some.GenericModel.
Is there maybe a way to still access the hierarchy from within Scala code?
Edit: when re-compiling the code out of my reach and removing the type re-definition, everything works. So I think what I'm looking at is a way to "disable" an package-level type definition for a specific class.
Are you using a GUI (in particular Eclipse) to build your project?
This seems related to Scala trouble accessing Java methods (that has no answer but where the general consensus is that the problem is not with scala but with Eclipse).

Categories