How to convert an enum from another enum in Kotlin - kotlin

I have an enum in the main repo:
enum class PilotType {
REMOVABLE,
FIXED
}
And I have another enum in another repo that is imported:
enum class PilotTypeDto {
REMOVABLE,
FIXED
}
In a class in my main repo I need to build this object:
(pilotType is of type PilotType)
(pilotTypeDto is of type PilotTypeDto)
return Pilot(
... = ...
pilotType = pilotTypeDto
... = ...
)
I need to convert pilotTypeDto to a pilotType.
I started building an extension function but it does not seem to let me create an enum:
fun pilotType(pilotTypeDto: PilotTypeDto): PilotType {
return PilotType(
... // this does not work
)
}

You can write this:
fun pilotType(pilotTypeDto: PilotTypeDto): PilotType =
when (pilotTypeDto) {
PilotTypeDto.REMOVABLE -> PilotType.REMOVABLE
PilotTypeDto.FIXED -> PilotType.FIXED
}
But as extension you could write this:
fun PilotTypeDto.toPilotType() = when (this) {
PilotTypeDto.REMOVABLE -> PilotType.REMOVABLE
PilotTypeDto.FIXED -> PilotType.FIXED
}
or make it part of the enum by writing this
enum class PilotTypeDto {
REMOVABLE,
FIXED;
fun toPilotType() = when (this) {
REMOVABLE -> PilotType.REMOVABLE
FIXED -> PilotType.FIXED
}
}

Related

Custom lint rule kotlin object

I'm trying to create a custom lint rule in order to avoid using a kotlin object class.
object AColors {
val white: Color = Color(0xFFFFFFFF)
}
fun main() {
val myColor = AColors.white //Lint error : Do not use AColors
}
How can I manage to get a lint issue when AColors is used?
In my case, AColors can't be private because I need it for a specific case.
I tried to create a custom lint rule to check the import but this is not a bullet-proof solution as you can use AColors without importing anything
class InvalidImportHandler(private val context: JavaContext) : UElementHandler() {
override fun visitImportStatement(node: UImportStatement) {
//check the import
}
}
For this specific case, you may check for USimpleNameReferenceExpressions and then check if the reference is to the AColors class. Like so:
class AColorsReferenceDetector : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement>> {
return listOf(USimpleNameReferenceExpression::class.java)
}
override fun createUastHandler(context: JavaContext): UElementHandler {
return object : UElementHandler() {
override fun visitSimpleNameReferenceExpression(
node: USimpleNameReferenceExpression
) {
val element = node.resolve()?.unwrapped
if (element is KtObjectDeclaration && element.name == "AColors") {
context.report(
ISSUE,
node,
context.getLocation(node.uastParent)
)
}
}
}
}
companion object {
val ISSUE = Issue.create(
AColorsReferenceDetector::class.simpleName.orEmpty(),
"Do not use AColors",
"Do not use AColors",
Category.CORRECTNESS,
10,
Severity.ERROR,
Implementation(
AColorsReferenceDetector::class.java,
EnumSet.of(Scope.JAVA_FILE)
)
)
}
}
Example IssueRegistry:
class IssueRegistry : IssueRegistry() {
override val api = CURRENT_API
override val minApi: Int
get() = 8
override val vendor: Vendor = Vendor()
override val issues
get() = listOf(AColorsReferenceDetector.ISSUE)
}
Example result:

Should I get rid of big switch case?

I have a factory which includes many HTML attribute generators which returns one of them based on the type of attribute, so I wanted to see if there is a better way of doing this.
class AttributeHtmlGeneratorFactory {
fun create(property: String): AttributeHtmlGenerator {
when (property) {
"animation" -> {
return AnimationHtmlGenerator()
}
...
"left", "top" -> {
return PositionHtmlGenerator()
}
...
"scaleX" , "scaleY", ... , "direction" -> {
return UnusedAttributesHtmlGenerator()
}
this when switch has like 20 switch cases in it.
this is the interface which all these classes are using
interface AttributeHtmlGenerator {
fun generateHtml(member: KProperty1<HtmlComponentDataModel, *>, component: HtmlComponentDataModel ): String
}
and this is where and how I'm using all of these:
var result = ""
HtmlComponentDataModel::class.memberProperties.forEach { member ->
val generator = AttributeHtmlGeneratorFactory().create(member.name)
result = result.plus(generator.generateHtml(member, component))
}
return result
also, this is a simple implementation of the interface:
class ButtonFillHtmlGenerator : AttributeHtmlGenerator {
override fun generateHtml(member: KProperty1<HtmlComponentDataModel, *>, component: HtmlComponentDataModel): String {
var result = ""
member.get(component)?.let {
result = result.plus("background-color:${it};")
}
return result
}
}
is there anyway to make this better?
If you just want to reformat the when statement, I suggest you you do like this:
fun create(property: String): AttributeHtmlGenerator = when (property)
{
"animation" -> AnimationHtmlGenerator()
"left", "top" -> PositionHtmlGenerator()
"scaleX", "scaleY", "direction" -> UnusedAttributesHtmlGenerator()
else -> error("No generator found for property $property")
}
If you want to split this logic across modules, you would use a Map.
class AttributeHtmlGeneratorFactory {
private val generatorMap = mutableMapOf<String, () -> AttributeHtmlGenerator>()
init {
assignGeneratorToProperties("animation") { AnimationHtmlGenerator() }
assignGeneratorToProperties("left", "top") { PositionHtmlGenerator() }
}
fun create(property: String): AttributeHtmlGenerator {
return generatorMap[property]?.invoke() ?: error("No generator found for property $property")
}
fun assignGeneratorToProperties(vararg properties: String, provider: () -> AttributeHtmlGenerator) {
properties.forEach {
generatorMap[it] = provider
}
}
}
This way you can call assignGeneratorToProperties in parts of the code and thus split the initialization logic.
Performance-wise, when/if-else statements are really performant when you have a few cases but a HashMap outperforms them for a lot of elements. You decide what to use depending on your case.

Runtime polymorphism in Kotlin

Is there any elegant way to apply polymorphism in this case? The parser provides the following classes at runtime:
class io.swagger.v3.oas.models.media.Schema //is parent of the rest :
class io.swagger.v3.oas.models.media.ComposedSchema
class io.swagger.v3.oas.models.media.ArraySchema
class io.swagger.v3.oas.models.media.StringSchema
class io.swagger.v3.oas.models.media.ObjectSchema
I'd like to have function for each class with the same name and simple, short method which will cast and call necessary function at runtime. Which is actually happening, but I hope there is more brief solution, without necessity of making this kind of duplicates:
fun main() {
val parser = OpenAPIV3Parser()
val asList = listOf(pathYaml3, pathYml2)
val map = asList.map(parser::read)
.flatMap { it.components.schemas.values }
.forEach(::parseRawSchema)
}
fun parseRawSchema(schema: Schema<Any>) {
if (schema is ComposedSchema) {
parseSchema(schema)
}
if (schema is StringSchema) {
parseSchema(schema)
}
...
}
fun parseSchema(schema: ComposedSchema) {
println("Compose-schema")
}
fun parseSchema(schema: StringSchema) {
println("Sting-schema")
}
...
Try use extension.
For example:
fun ComposedSchema.parseSchema() {
println("Compose-schema")
}
fun StringSchema.parseSchema() {
println("Sting-schema")
}
And than:
fun parseRawSchema(schema: Schema<Any>) {
schema.parseSchema()
}

How to create a MXBean with control methods?

We are planning to implement some behaviour control in our
CordApp, for testing purposes. Is that possible to create a
M(X)Bean, accessible via JMX, which is going to change some
internal flags in our CordApp ? If this is not a good design
choice, please inform the best practice to follow.
Basically, we have a set of flags, like these:
abstract class BaseFlow() : FlowLogic<SignedTransaction>() {
var flagBehaviourOne : Boolean = true
var flagBehaviourTwo : Boolean = true
var flagBehaviourThree: Boolean = true
var flagBehaviourFour : Boolean = true
...
}
then, in some implementing class, we have something like this:
object SomeFlow {
#InitiatingFlow
class Initiator(private val destinatario: Party,
private val parameter: StateObject,
private val isAnonymous: Boolean = false,
private val pointer: Any) : BaseFlow() {
...
#Suspendable
override fun call(): SignedTransaction {
if (flagBehaviourOne || flagBehaviorTwo) {
// enforce some specific behaviour
}
...
} // end of SomeFlow.Initiator
...
} // end of SomeFlow
I have (partially) solved my problem.
I have added a new object class, along with its jmx interface :
package vfalcao.example.jmx
import java.lang.management.ManagementFactory
import javax.management.MXBean
import javax.management.ObjectName
#MXBean
interface BehaviourControlMXBean {
fun setBehaviourOne(newValue: String)
fun isBehaviourOne() : String
...
// other "behaviours" ommited for brevity
}
object BehaviourControl : BehaviourControlMXBean {
// internal data
...
init {
val objectName = ObjectName("vfalcao.example.jmx:type=BehaviourControl,name=def")
val platformMBeanServer = ManagementFactory.getPlatformMBeanServer()
platformMBeanServer.registerMBean(this, objectName)
}
}
then, in my BaseFlow class:
abstract class BaseFlow() : FlowLogic<SignedTransaction>() {
companion object {
...
init {
println("${BehaviourControl}")
}
...
fun test() {
var behaviour1 = ((BehaviourControl.props["behaviour1"] as String).toBoolean())
if (behaviour1) {
// do something controlled by behaviour1
}
}
}
...
}

How to specify "own type" as return type in Kotlin

Is there a way to specify the return type of a function to be the type of the called object?
e.g.
trait Foo {
fun bar(): <??> /* what to put here? */ {
return this
}
}
class FooClassA : Foo {
fun a() {}
}
class FooClassB : Foo {
fun b() {}
}
// this is the desired effect:
val a = FooClassA().bar() // should be of type FooClassA
a.a() // so this would work
val b = FooClassB().bar() // should be of type FooClassB
b.b() // so this would work
In effect, this would be roughly equivalent to instancetype in Objective-C or Self in Swift.
There's no language feature supporting this, but you can always use recursive generics (which is the pattern many libraries use):
// Define a recursive generic parameter Me
trait Foo<Me: Foo<Me>> {
fun bar(): Me {
// Here we have to cast, because the compiler does not know that Me is the same as this class
return this as Me
}
}
// In subclasses, pass itself to the superclass as an argument:
class FooClassA : Foo<FooClassA> {
fun a() {}
}
class FooClassB : Foo<FooClassB> {
fun b() {}
}
You can return something's own type with extension functions.
interface ExampleInterface
// Everything that implements ExampleInterface will have this method.
fun <T : ExampleInterface> T.doSomething(): T {
return this
}
class ClassA : ExampleInterface {
fun classASpecificMethod() {}
}
class ClassB : ExampleInterface {
fun classBSpecificMethod() {}
}
fun example() {
// doSomething() returns ClassA!
ClassA().doSomething().classASpecificMethod()
// doSomething() returns ClassB!
ClassB().doSomething().classBSpecificMethod()
}
You can use an extension method to achieve the "returns same type" effect. Here's a quick example that shows a base type with multiple type parameters and an extension method that takes a function which operates on an instance of said type:
public abstract class BuilderBase<A, B> {}
public fun <B : BuilderBase<*, *>> B.doIt(): B {
// Do something
return this
}
public class MyBuilder : BuilderBase<Int,String>() {}
public fun demo() {
val b : MyBuilder = MyBuilder().doIt()
}
Since extension methods are resolved statically (at least as of M12), you may need to have the extension delegate the actual implementation to its this should you need type-specific behaviors.
Recursive Type Bound
The pattern you have shown in the question is known as recursive type bound in the JVM world. A recursive type is one that includes a function that uses that type itself as a type for its parameter or its return value. In your example, you are using the same type for the return value by saying return this.
Example
Let's understand this with a simple and real example. We'll replace trait from your example with interface because trait is now deprecated in Kotlin. In this example, the interface VitaminSource returns different implementations of the sources of different vitamins.
In the following interface, you can see that its type parameter has itself as an upper bound. This is why it's known as recursive type bound:
VitaminSource.kt
interface VitaminSource<T: VitaminSource<T>> {
fun getSource(): T {
#Suppress("UNCHECKED_CAST")
return this as T
}
}
We suppress the UNCHECKED_CAST warning because the compiler can't possibly know whether we passed the same class name as a type argument.
Then we extend the interface with concrete implementations:
Carrot.kt
class Carrot : VitaminSource<Carrot> {
fun getVitaminA() = println("Vitamin A")
}
Banana.kt
class Banana : VitaminSource<Banana> {
fun getVitaminB() = println("Vitamin B")
}
While extending the classes, you must make sure to pass the same class to the interface otherwise you'll get ClassCastException at runtime:
class Banana : VitaminSource<Banana> // OK
class Banana : VitaminSource<Carrot> // No compiler error but exception at runtime
Test.kt
fun main() {
val carrot = Carrot().getSource()
carrot.getVitaminA()
val banana = Banana().getSource()
banana.getVitaminB()
}
That's it! Hope that helps.
Depending on the exact use case, scope functions can be a good alternative. For the builder pattern apply seems to be most useful because the context object is this and the result of the scope function is this as well.
Consider this example for a builder of List with a specialized builder subclass:
open class ListBuilder<E> {
// Return type does not matter, could also use Unit and not return anything
// But might be good to avoid that to not force users to use scope functions
fun add(element: E): ListBuilder<E> {
...
return this
}
fun buildList(): List<E> {
...
}
}
class EnhancedListBuilder<E>: ListBuilder<E>() {
fun addTwice(element: E): EnhancedListBuilder<E> {
addNTimes(element, 2)
return this
}
fun addNTimes(element: E, times: Int): EnhancedListBuilder<E> {
repeat(times) {
add(element)
}
return this
}
}
// Usage of builder:
val list = EnhancedListBuilder<String>().apply {
add("a") // Note: This would return only ListBuilder
addTwice("b")
addNTimes("c", 3)
}.buildList()
However, this only works if all methods have this as result. If one of the methods actually creates a new instance, then that instance would be discarded.
This is based on this answer to a similar question.
You can do it also via extension functions.
class Foo
fun <T: Foo>T.someFun(): T {
return this
}
Foo().someFun().someFun()