I would like to access the scope of the calling class when creating an "anonymous inner class"
in Kotlin. What would be the equivalent of Java's OuterScope.this syntax? example :
open class SomeClass {
open fun doSomething() {
// ...
}
}
class MyClass {
fun someFunc() {
object : SomeClass() {
override fun doSomething() {
super<SomeClass>.doSomething()
// Access the outer class context, in Java
// this would be MyClass.this
}
}
}
}
this#MyClass
JFYI:
the same syntax for access to receiver of extension function:
fun MyClass.foo() {
// in some nested thing:
this#foo
//...
}
Kotlin Reference: This expressions
in my case i accessed it like : this#MainActivity
class MainActivity : AppCompatActivity() {
inner class Anon : Observer<PagedList<ApplicationUsers>> {
override fun onChanged(pagedList: PagedList<ApplicationUsers>?) {
Toast.makeText(this#MainActivity, "hello", Toast.LENGTH_SHORT).show()
}
}
}
Related
I have some abstract with generic type:
interface Abstract<T> {
val dataHolder: T
}
class AbstractImplA : Abstract<String> {
override val dataHolder = "Test"
}
class AbstractImplB : Abstract<Int> {
override val dataHolder = 1
}
Now I want to create open class that persist this data:
open class Base<T>(private val abstract: Abstract<T>) {
val data : T get() = abstract.dataHolder
// ...
}
now for child class I have to explicitly specifiy generic type of Abstract:
class ClassA : Base<String>(AbstractImplA()) {
fun foo() {
assertEquals("Test", data)
}
}
class ClassB : Base<Int>(AbstractImplB()) {
fun foo() {
assertEquals(1, data)
}
}
I wander if Kotlin can infere this type.
Passing wrong generic type causes Type mismatch error ex. class ClassB : Base<Boolean>(AbstractImplB())
Can I somehow write it like this?:
class ClassB : Base(AbstractImplB()) {
fun foo() {
assertEquals(1, data)
}
}
In java, i hava code like below:
public class GenericTest {
private static final GenericTest instance = new GenericTest();
IRequirement requirement;
public static GenericTest getInstance() {
return instance;
}
public class ClassA {}
public interface InterfaceA {}
public void init(IRequirement requirement){
this.requirement = requirement;
}
public interface IRequirement {
<T extends ClassA & InterfaceA> T supply();
}
class ClassB {
void doSomeThing() {
ClassA a = requirement.supply();
InterfaceA ia = requirement.supply();
}
}
}
I can get ClassA or InterfaceA instance according to my needs.
But in kotlin, same codes like below:
open class ClassA(val name: String) {
fun function1() {}
fun function2() {}
}
interface InterfaceA {
fun iFunction1()
}
class ModuleX private constructor() {
var requirement: IRequirement? = null
companion object {
val instance = ModuleX()
}
fun init(requirement: IRequirement) {
instance.requirement = requirement
}
interface IRequirement {
fun <T> supply(): T where T : ClassA, T : InterfaceA
}
}
object ClassB {
inline fun <reified T> doSomeThing() where T : ClassA, T : InterfaceA{
val require = ModuleX.instance.requirement?.supply<T>()
require?.function1()
require?.iFunction1()
}
fun doAnotherThing() {
// IDE give an error when calling supply()
val require = ModuleX.instance.requirement?.supply()
require?.function1()
require?.iFunction1()
}
}
I must specify the actual type of the generic, or use the generic method, otherwise I will not be able to use the IRequirement in the code above, such as in ClassB.doAnotherThing() where IDE give an error "Type inference failed: Not enough information to infer parameter T in fun supply( ): T where T : InterfaceAPlease specify it explicitly."
My question is: In my module, it is required to provide a class that extends ClassA and implements InterfaceAd, but the module does not know the exact type of the class because it is outside the module. How should I use generics in this case?
fun doAnotherThing() {
val require: Any? = ModuleX.instance.requirement?.supply()
if (require != null) {
(require as ClassA).function1()
(require as InterfaceA).iFunction1()
}
}
I am new to Guice. I am trying to use requestInjection to inject the dependencies of a kotlin singleton object in this way.
APPROACH 1:
class SampleTest {
#Test
fun test() {
Guice.createInjector(object: KotlinModule() {
override fun configure() {
requestInjection(A)
}
})
assertEquals("Hello world", A.saySomething())
}
}
object A {
#Inject
private lateinit var b: B
fun saySomething(): String {
return b.sayHello()
}
}
class B {
fun sayHello(): String {
return "Hello world"
}
}
But I am getting this error:
kotlin.UninitializedPropertyAccessException: lateinit property b has not been initialized
If I change A to a class with no-arg constructor, it works.
APPROACH 2:
class SampleTest {
#Test
fun test() {
val a = A()
Guice.createInjector(object: KotlinModule() {
override fun configure() {
requestInjection(a)
}
})
assertEquals("Hello world", a.saySomething())
}
}
class A {
#Inject
private lateinit var b: B
fun saySomething(): String {
return b.sayHello()
}
}
class B {
fun sayHello(): String {
return "Hello world"
}
}
Instead, if I change requestInjection to requestStaticInjection, it also works.
APPROACH 3:
class SampleTest {
#Test
fun test() {
Guice.createInjector(object: KotlinModule() {
override fun configure() {
requestStaticInjection<A>()
}
})
assertEquals("Hello world", A.saySomething())
}
}
object A {
#Inject
private lateinit var b: B
fun saySomething(): String {
return b.sayHello()
}
}
class B {
fun sayHello(): String {
return "Hello world"
}
}
Why didn't APPROACH 1 work? Why did APPROACH 2 and APPROACH 3 work?
Kotlin's objects are treated as language static singletons, i.e. their initialization/instantiations happens outside the scope of the dependency injection framework.
Therefor, when using the KotlinModule to inject an object, you have to use requestStaticInjection like in APPROACH 3, or change that object to a class, so that the Guice KotlinModule sees it as non-static, as presented in APPROACH 2
Hope that clarifies things a bit.
I've got interfaces
interface IIMSIdentifiable {
fun setImsId(id : String)
fun getImsId() : String
}
interface IIMSConsumer : IIMSIdentifiable {
fun consumeAsync(message : GRLMessage)
}
And I've got a class that contains object with IIMSConsumer type
class IMSObject<IIMSConsumer> : Thread {
constructor(component : IIMSConsumer) {
obj = component
// IMSContext.instance.registerObject(this) // hm type mismatch
}
val objectMessageQueue = LinkedBlockingDeque<GRLMessage>()
val obj : IIMSConsumer
var isRunning = true
override fun run() {
while(isRunning) {
processMessages()
}
}
fun stopProcessing() {
isRunning = false
}
fun processMessages() {
objectMessageQueue.forEach {
obj.consumeAsync(it)
}
}
fun getObjectId() : String {
return obj.getImsId()
}
}
But it cannot resolve references
fun processMessages() {
objectMessageQueue.forEach {
obj.consumeAsync(it) // cannot resolve reference !!!
}
}
fun getObjectId() : String {
return obj.getImsId() // cannot resolve reference !!!
}
What is the problem? Oddly enought it did not ask for imports despite being located in different packages
com.lapots.game.journey.ims.domain.IMSObject
com.lapots.game.journey.ims.api.IIMSConsumer
I tried to test in on something simpler and get the same error with unresolved reference
interface IConsumer {
fun consume() : String
}
class Generic<IConsumer>(val consumer : IConsumer) {
fun invoke() {
print(consumer.consume()) // unresolved reference
}
}
fun main(args: Array<String>) {
val consumer = object : IConsumer {
override fun consume() : String {
return "I consume"
}
}
val generic = Generic<IConsumer>(consumer)
generic.invoke()
}
class Generic<IConsumer>(val consumer : IConsumer) {
You are creating a class Generic with a generic type parameter called IConsumer. This type parameter will shadow the interface you defined within that class, so you it actually says is:
class Generic<IConsumer : Any>(val consumer : Any) {
That is why it cannot resolve the method, since the generic parameter can only be interpreted as Any.
To fix either change the type parameter to have the appropriate names and bound (class Generic<T : IConsumer>(val consumer : T) {) or remove the generics entirely
I have got the following Java interfaces:
interface Action1<T> {
void call(T t);
}
interface Test<T> {
void test(Action1<? super T> action)
}
And the following Kotlin class:
interface A {
fun go()
}
abstract class Main {
abstract fun a(): Test<out A>
fun main() {
a().test(Action1 { it.go() })
a().test { it.go() }
}
}
Now in the function main, the first statement compiles, but IntelliJ gives a warning that the SAM-constructor can be replaced with a lambda.
This would result in the second statement.
However, this second statement does not compile, because it has type Any?, not A. Removing the out modifier makes it compile again.
Why does this happen?
The use case of this is when the implementing class of Main needs to return Test<B> for the function a(), where B implements A:
class B : A {
override fun go() {
TODO()
}
}
class MainImp : Main() {
override fun a(): Test<out A> {
val value: Test<B> = object : Test<B> {
override fun test(action: Action1<in B>?) {
TODO()
}
};
return value
}
}
It is a compiler bug. You can track it here: https://youtrack.jetbrains.com/issue/KT-12238.