Accessing Kotlin Sealed Class from Java - java

Up until now I have been using this Kotlin sealed class:
sealed class ScanAction {
class Continue: ScanAction()
class Stop: ScanAction()
... /* There's more but that's not super important */
}
Which has been working great in both my Kotlin and Java code. Today I tried changing this class to use objects instead (as is recommended to reduce extra class instantiation):
sealed class ScanAction {
object Continue: ScanAction()
object Stop: ScanAction()
}
I am able to reference this easy peasy in my other Kotlin files, but I am now struggling to use it in my Java files.
I have tried the following and both of these kick back compilation errors when trying to make reference to in Java:
ScanAction test = ScanAction.Continue;
ScanAction test = new ScanAction.Continue();
Does anyone know how I can reference the instance in Java now?

You have to use the INSTANCE property:
ScanAction test = ScanAction.Continue.INSTANCE;

Related

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){ ... }

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

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.

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
}

attempting to get class names from a different package

Have got two projects javaapplication2 and javaapplication1. The same being their package names. In javaapplication2 ive imported javaapplication1 using
import javaapplication1.*;
i need to list all classses in the packeage. How to achieve this? I tried a simple code but it gets a null exception.
Package pck;
pck = Package.getPackage("javaapplication1");
System.out.println(pck.getClass());
I don't have enough rep to comment on this question or to mark it as such, but it is a duplicate of:
Getting all Classes from a Package
There are many good answers listed on that question - for instance the top is looking for classes that implement ICommand, so to implement this all you need to do is remove:
if (ICommand.class.isAssignableFrom(cls)) {
commands.add((Class<ICommand>) cls);
}
from the for loop and you have what you want.
I guess the jar containing package javaapplication1 is not in classpath as
Package.getPackage("javaapplication1");
is returning null for you.
Also,
You can have a look at the following link:
http://dzone.com/snippets/get-all-classes-within-package
or can explore the Reflection library from Google in order to get the required information, below is a sample code.
e.g.
Reflections reflections = new Reflections("javaapplication1");
Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class);
If you go throgh the object class API it is written as:
//Object API
getClass
public final Class getClass()Returns the runtime class of an object. That Class object is the object that is locked by static synchronized methods of the represented class.
Returns:
the object of type Class that represents the runtime class of the object.
It's clearly written as it represents the run time class of an object.
Suppose if you have class called as "Helloworld" in side "javaapplication1" package
create object of the class as:
Helloworld world=new Helloworld();
and then try to run as
System.out.println(wolrld.getClass());
It will return the class path of current object.

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