how do you declare static property in kotlin? - kotlin

public class Common {
public static ModelPengguna currentModelPengguna;
}

public class Common {
companion object {
val currentModelPengguna: ModelPengguna = ModelPengguna()
}
}
or if the object is static and you want it as Singleton
you can use
object Common {
val currentModelPengguna: ModelPengguna = ModelPengguna()
}
a static property in kotlin is introduced by the companion object further reading:
https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects

Related

in kotlin, how to access protected static member in parent class from sub class

It is code worked in java but after convert to kotlin it does not compile.
Having a base class which has some defines as static protected member in the companion object:
abstract class ParentClass {
companion object {
#JvmField
final protected val SERVICE_TYPE_A = "the_service_type_a"
}
}
and the child class:
class ChildClass: ParentClass {
public override fun getServiceType(): String {
return SERVICE_TYPE_A. //<== got compile error
}
}
it does not compile.
how to access a parent class static protected member from subclass?
You need to use #JvmStatic instead as follows:
abstract class ParentClass {
companion object {
#JvmStatic
protected val SERVICE_TYPE_A = "the_service_type_a"
}
abstract fun getServiceType(): String
}
The final keyword in SERVICE_TYPE_A is redundant since everything is final by default in Kotlin. This also mean that if you want ParentClass to be extended, then you need to explicitly define it as open.
Then your ChildClass would look as follows:
class ChildClass: ParentClass() {
override fun getServiceType(): String {
return SERVICE_TYPE_A
}
}

Map abstract type in Kotlin with MapStruct

I'm trying to map an abstract class with Mapstruct in Kotlin, but getting the following error:
AnimalMapper.java: error: The return type AnimalOutput is an abstract class or interface. Provide a non abstract / non interface result type or a factory method.
My implementation:
#Mapper(componentModel = "jsr330")
interface AnimalMapper {
fun mapToDogOutput(dogInput: DogInput): DogOutput
fun mapToCatOutput(catInput: CatInput): CatOutput
fun mapToAnimalOutput(animalInput: AnimalInput): AnimalOutput {
when (animalInput) {
is DogInput -> mapToDogOutput(animalInput)
is CatInput -> mapToCatOutput(animalInput)
}
throw RuntimeException("Unsupported animal type");
}
}
sealed class AnimalInput {
abstract val name: String
}
data class CatInput(
override val name: String,
val catProperty: Int,
) : AnimalInput()
data class DogInput(
override val name: String,
val dogProperty: Float,
) : AnimalInput()
sealed class AnimalOutput {
abstract val name: String
}
data class CatOutput(
override val name: String,
val catProperty: Int,
) : AnimalOutput()
data class DogOutput(
override val name: String,
val dogProperty: Float,
) : AnimalOutput()
In my old java project, this corresponding implementation works as expected:
#Mapper(componentModel = "jsr330")
interface AnimalMapper {
DogOutput mapToDogOutput(DogInput dogInput);
CatOutput mapToCatOutput(CatInput catInput);
default AnimalOutput mapToAnimalOutput(AnimalInput animalInput) {
if (animalInput instanceof DogInput) {
return mapToDogOutput((DogInput) animalInput);
}
if (animalInput instanceof CatInput) {
return mapToCatOutput((CatInput) animalInput);
}
throw new RuntimeException("Unsupported animal type");
}
}
public abstract class AnimalInput {
public String name;
}
public abstract class CatInput extends AnimalInput {
public String name;
public int catProperty;
}
public abstract class DogInput extends AnimalInput {
public String name;
public float dogProperty;
}
public abstract class AnimalOutput {
public String name;
}
public abstract class CatOutput extends AnimalOutput {
public String name;
public int catProperty;
}
public abstract class DogOutput extends AnimalOutput {
public String name;
public float dogProperty;
}
I'm using the following dependency versions:
mapstructVersion: 1.4.2.Final
kotlinVersion: 1.5.21 (jvmTarget 16)
Anyone have an idea, how to fix this issue in my Kotlin project?
The reason why this is not working in Kotlin is due to the fact that the generated code by Kotlin marks the mapToAnimalOutput method as an abstract method.
You'll need to use #JvmDefault on that method in order for Kotlin to generate the correct modifiers for the method.

Dagger 2 public field injection produces 'private field injection' error

I'm trying to set up a very basic field injection using Dagger2 with the following structure:
class ToInject {}
class Injected {
#Inject
var toInject: ToInject? = null
}
#Module
object BaseModule {
var toInject: ToInject? = null
#Provides
#JvmStatic
fun toInjectProvider(): ToInject {
if (toInject == null) {
toInject = ToInject()
}
return toInject as ToInject
}
}
The field I'm trying to inject is definately PUBLIC but the compiler returns the following error
Dagger does not support injection into private fields
Can anyone please explain why am I getting this error and how to fix it?
BTW constructor injection works:
class Injected #Inject constructor(var toInject: ToInject){}
Try explicitly annotating the setter method:
class Injected {
#set:Inject
var toInject: ToInject? = null
}
or
class Injected {
var toInject: ToInject? = null
#Inject set
}
You can also annotate your field as #JvmField:
class Injected {
#JvmField
#Inject
var toInject: ToInject? = null
}
The problem is how Kotlin is translated to Java.
This Kotlin class:
class Injected {
var toInject: ToInject? = null
}
actually becomes this Java class:
public final class Injected {
#Nullable
private ToInject toInject;
#Nullable
public final ToInject getToInject() {
return this.toInject;
}
public final void setToInject(#Nullable ToInject value) {
this.toInject = value;
}
}
So despite the fact you set your field public in Kotlin, under the hood it's just a private field with a public setter and getter.
I am having similar issue while injecting primitive Int value. Only adding #JvmField worked for me. Thanks #jsamol for pointing out.
#JvmField
#Inject
#Named(NAMED_APP_LOGO)
var appLogo: Int = 0

Kotlin visibility of nested members

I have a class with a nested, private class. I have a Builder, standard Java builder pattern, that constructs instances of this class. I don't want anyone outside of my class to be able to see my hidden class.
In Java I could do this:
public class Example {
private SneakyType doNotExposeThis;
private Example(Builder builder) {
// OK 'cause in Java you can access the private
// members of a nested class
doNotExposeThis = builder.doNotExposeThis;
}
private static class SneakyType {
SneakyType(String x) {
// stuff
}
}
public static class Builder {
private SneakyType doNotExposeThis;
public void addFoo(String something) {
doNotExposeThis = new SneakyType(something);
}
public Example build() { return new Example(this); }
}
}
But I can't figure out how to do the same in Kotlin:
class Example(builder: Builder) {
private lateinit var doNotExposeThis: SneakyType
init {
doNotExposeThis = builder.doNotExposeThis
}
class Builder {
// If private or internal I can't access it in Example.init
// and if public it gets exposed.
val doNotExposeThis: SneakyType
fun addFoo(something: String) {
// actual construction is quite a bit more complex
doNotExposeThis = SneakyType(something)
}
}
}
Note that for the sake of Java interop I want to keep my builder. I also want it because my object is complicated to construct and I want it to be immutable so I have a builder with lots of setters, adders, vals, etc. and then in init I construct a single immutable Example.
The only alternatives I see are:
Instead of have a SneakyType in my builder save all the info necessary to construct one and then construct it in Example. Works but adds a ton of complexity.
Give up on Example being immutable and allow the builder to call into it to set up a Sneaky
Expose the Sneaky
Is there no way to mimic the Java version?
I see two viable options:
Use the internal visibility modifier:
class Example private constructor(builder: Builder) {
private val doNotExposeThis: SneakyType
init {
doNotExposeThis = builder.doNotExposeThis
}
internal class SneakyType(x: String)
class Builder {
internal lateinit var doNotExposeThis: SneakyType
fun addFoo(something: String) {
doNotExposeThis = SneakyType(something)
}
fun build(): Example {
return Example(this)
}
}
}
This will make SneakyType only visible within your Kotlin compilation module.
Make Example independent of its builder (this is what I recommend):
class Example private constructor(private val doNotExposeThis: SneakyType) {
private class SneakyType(x: String)
class Builder {
private lateinit var doNotExposeThis: SneakyType
fun addFoo(something: String) {
doNotExposeThis = SneakyType(something)
}
fun build(): Example {
return Example(doNotExposeThis)
}
}
}

Kotlin : Interface with immutable property implemented by class with mutable

I have the following code:
Works around a limitation in Spring where #ConfigurationProperties classes need to follow the JavaBeans convention with mutable properties.
Instead of inject the mutable TokenConfigurationConfig we inject the interface.
public interface TokenAuthenticationConfig {
public fun apiKey() : String
}
#Component
#ConfigurationProperties(prefix = "service.api")
public open class TokenAuthenticationConfigImpl : TokenAuthenticationConfig
{
public var apiKey : String
constructor() {
this.apiKey = ""
}
override fun apiKey(): String
{
return this.apiKey
}
}
It works ok, but just wondering:
Is it possible in Kotlin to define an interface with an immutable property, that is implemented by class with a mutable property.
Uses of the interface would see the property as immutable, while users of the class would see it as mutable.
Yes, it definitely is possible to define such an interface and a class.
Any (publicly visible) property x in Kotlin means a pair of methods getX() and setX(..), generated by the compiler to satisfy the Java convention. That said, it is consistent that you can override getX in a class and add setX.
Here is an example:
interface SomethingImmutable {
val Somevar: String
}
class MyClass: SomethingImmutable {
override var Somevar: String = "Initial Value"
}