Runtime polymorphism in Kotlin - 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()
}

Related

Kotlin: use generic on interface level as argument type for function

Is it impossible to use generic on interface level as argument type for function?
I read about out and in keywords but as I understand they don't work for this case.
interface BaseB
open class ChildB1: BaseB
open class ChildB2: BaseB
abstract class BaseMapper<V: BaseB> {
open fun test(v: V) {
return
}
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
return
}
}
class TestMapper2: BaseMapper<ChildB2>() {
override fun test(v: ChildB2) {
return
}
}
#Test
fun t() {
//ERROR
val mappers: List<BaseMapper<BaseB>> = listOf(TestMapper1(), TestMapper2())
mappers[0].test(ChildB1())
}
A BaseMapper<ChildB1> is not logically a BaseMapper<BaseB>. It consumes ChildB’s, so if you passed some other implementation of Base it would cause a ClassCastException if the compiler let you do that. There is no common subtype of your two subclasses besides Nothing, so the only way to put both of these types in the same list is to make it a List<BaseMapper<in Nothing>>.
Example of why it is not logically a BaseMapper<BaseB>:
open class ChildB1: BaseB {
fun sayHello() = println("Hello world")
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
v.sayHello() // if v is not a ChildB1, this would be impossible
}
}
//...
val impossibleCast: BaseMapper<BaseB> = TestMapper1()
// TestMapper1 cannot call sayHello() because it's undefined for ChildB2.
// This is impossible:
impossibleCast.test(ChildB2())
// ...so the compiler prevents you from doing the impossible cast in the first place.

Custom Gradle Task having Kotlin Delegate

Gradle tasks using Kotlin are implemented as either abstract class ... or interface ....
In either case it is not clear how to use delegation.
The following works correctly but requires delegation to be performed manually (i.e. it does not use Kotlin delegation).
#CacheableTask
abstract class FooTask : DefaultTask(), CopySourceSpec {
#get:InputFiles
#get:Optional
#get:SkipWhenEmpty
#get:IgnoreEmptyDirectories
#get:PathSensitive(PathSensitivity.RELATIVE)
abstract val sourceFiles: ConfigurableFileCollection
#TaskAction
fun canonize() {
val sourceFileTree = sourceFiles.asFileTree
// do something with the sourceFileTree
}
override fun from(vararg sourcePaths: Any?): ProtobufHeaderTask {
this.sourceFiles.from(sourcePaths)
return this
}
override fun from(sourcePath: Any, closure: Closure<*>): ProtobufHeaderTask {
this.sourceFiles.from(sourcePath, closure)
return this
}
override fun from(sourcePath: Any, configureAction: Action<in CopySpec>): ProtobufHeaderTask {
this.sourceFiles.from(sourcePath, configureAction)
return this
}
}
It seems like this could be done more simply using Kotlin delegation.
#CacheableTask
abstract class FooTask : DefaultTask(), ConfigurableFileCollection by sourceFiles {
#get:InputFiles
#get:Optional
#get:SkipWhenEmpty
#get:IgnoreEmptyDirectories
#get:PathSensitive(PathSensitivity.RELATIVE)
abstract val sourceFiles: ConfigurableFileCollection
#TaskAction
fun canonize() {
val sourceFileTree = sourceFiles.asFileTree
// do something with the sourceFileTree
}
}
This latter case produces an error that sourceFiles is not defined.
Is it possible to use Kotlin delegation in this way?

Compilation throws `None of the following functions can be called with the arguments supplied`

Trying to implement a custom JSONB binding that maps to an object containing a map. Generated code throws a None of the following functions can be called with the arguments supplied error caused by the following line:
val SOME_FIELD: TableField<SomeRecord, Jsonb?> = createField(DSL.name("meta"), SQLDataType.JSONB.nullable(false).defaultValue(DSL.field("'{}'::jsonb", SQLDataType.JSONB)), this, "", JsonbBinding())
Here's my configuration:
class JsonbBinding : Binding<Any, Jsonb> {
private val mapper = ObjectMapper()
override fun converter(): Converter<Any, Jsonb> {
return object : Converter<Any, Jsonb> {
override fun from(dbObject: Any?): Jsonb {
if (dbObject == null) return Jsonb()
val props = mapper.readValue<MutableMap<String, Any>>(dbObject.toString())
return Jsonb(props)
}
override fun to(userObject: Jsonb?): Any? {
return mapper.writeValueAsString(userObject)
}
override fun fromType(): Class<Any> {
return Any::class.java
}
override fun toType(): Class<Jsonb> {
return Jsonb::class.java
}
}
}
override fun sql(ctx: BindingSQLContext<Jsonb>) {
ctx.render()?.let {
if (it.paramType() == ParamType.INLINED) {
it.visit(
DSL.inline(ctx.convert(converter()).value())
).sql("::jsonb")
} else {
it.sql("?::jsonb")
}
}
}
override fun register(ctx: BindingRegisterContext<Jsonb>) {
ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR)
}
override fun set(ctx: BindingSetStatementContext<Jsonb>) {
ctx.statement().setString(
ctx.index(),
ctx.convert(converter()).value()?.toString()
)
}
override fun set(ctx: BindingSetSQLOutputContext<Jsonb>) {
throw SQLFeatureNotSupportedException()
}
override fun get(ctx: BindingGetResultSetContext<Jsonb>) {
ctx.convert(converter()).value(ctx.resultSet().getString(ctx.index()))
}
override fun get(ctx: BindingGetStatementContext<Jsonb>) {
ctx.convert(converter()).value(ctx.statement().getString(ctx.index()))
}
override fun get(ctx: BindingGetSQLInputContext<Jsonb>) {
throw SQLFeatureNotSupportedException()
}
}
<forcedType>
<userType>org.example.Jsonb</userType>
<binding>org.example.JsonbBinding</binding>
<includeExpression>.*</includeExpression>
<includeTypes>jsonb</includeTypes>
</forcedType>
Also, it seems like the line causing problems is mapping database data to JOOQ's default JSONB object. Is that what's causing the issue? Is there anything I may want to do about it? Is there some other way of doing mapping database JSONB data to a map by JOOQ?
I think you're confusing the type variables on Binding<T, U> here:
T is the database / JDBC type (in this case org.jooq.JSONB)
U is the user type (in this case Any)
You have to implement the binding the other way round: Binding<JSONB?, Any?>. Since jOOQ already takes care of properly binding the JSONB type to JDBC, you can probably do with your Converter<JSONB?, Any?> implementation alone, and attach that to your generated code instead:
class JsonbConverter : Converter<JSONB?, Any?> { ... }
Also, you don't have to use your own Jsonb type to wrap JSON data here.

Is there a way to verify that a top-level function passed as a dependency to a class has been called during testing?

I have a class that receives a function allowing it to display things on the UI during a failure case. What's the best way that I can verify that the function is called in my test?
MyClass(private val uiPrinter: (String) -> Unit) {
fun foo() {
// do some stuff
uiPrinter("printing from foo!")
// do some more stuff
}
}
MyClassTest() {
val testUiPrinter: (String) -> Unit = { System.out.println(it) }
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
// can I verify that testUiPrinter has been invoked?
}
}
You may want to check out the Model-View-Presenter architecture. Its purpose is to hide the Android framework behind an abstract View interface which a purely Java Presenter can interact with. In your example:
interface ViewInterface {
fun printError(error: String)
}
class MyPresenter(private val view: ViewInterface) {
fun foo() {
// do some stuff (testable stuff)
view.printError("Printing from foo()!")
// do some more (testable) stuff
}
}
class MyPresenterTest() { // Test using Mockito to mock the abstract view
private val view = mock(ViewInterface::class.java)
private val presenter = MyPresenter(view)
#Test
fun printsError() {
// set up preconditions
presenter.foo()
verify(view).printError("Printing from foo()!")
}
}
Your concrete view will generally be an Android Activity, Fragment, or View which implements the view interface. Notice MyPresenter only expects the abstract view and does not need knowledge of the framework-dependent operations.
class MyActivity : Activity(), ViewInterface {
// ...
override fun printError(error: String) {
textView.text = error // For example
}
// ...
}
This can be achieved by mocking the higher-order function as higher-order functions are objects unless inlined.
#Mock
val testUiPrinter: (String) -> Unit
#Test
fun uiPrinterIsInvoked() {
val myClass = MyClass(testUiPrinter)
myClass.foo()
verify(testUiPrinter).invoke("Printing from foo!")
}

How kotlin delegation is useful?

I'm really confused about the kotlin delegation. Let me describe the regular polymorphism approach here which looks same like the kotlin delgation.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
fun main(args: Array<String>) {
val b : Base = BaseImpl(10)
b.print() // prints 10
}
I can pass any implemented class of Base interface to b variable to call the method of specified class's object. Then what is the benefit of kotlin's delegation? Which is described here.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b // why extra line of code?
// if the above example works fine without it.
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}
I know this is the simple scenario where the both codes are working fine. There should be a benefit of delegation that's why kotlin introduced it. What is the difference? and how kotlin delegation can be useful? Please give me a working example to compare with polymorphism approach.
Also remember that you're not restricted to just one delegate. Kotlin's way of implementing delegation is similar to traits implementation in languages like Groovy. You can compose different functionality via delegates. Kotlin's way can also be considered more powerful because you can "plug in" different implementations too.
interface Marks {
fun printMarks()
}
class StdMarks() : Marks {
override fun printMarks() { println("printed marks") }
}
class CsvMarks() : Marks {
override fun printMarks() { println("printed csv marks") }
}
interface Totals {
fun printTotals()
}
class StdTotals : Totals {
override fun printTotals() { println("calculated and printed totals") }
}
class CheatTotals : Totals {
override fun printTotals() { println("calculated and printed higher totals") }
}
class Student(val studentId: Int, marks: Marks, totals: Totals)
: Marks by marks, Totals by totals
fun main(args:Array<String>) {
val student = Student(1,StdMarks(), StdTotals())
student.printMarks()
student.printTotals()
val cheater = Student(1,CsvMarks(), CheatTotals())
cheater.printMarks()
cheater.printTotals()
}
Output:
printed marks
calculated and printed totals
printed csv marks
calculated and printed higher totals
You can't do this with inheritance.
It is extremely useful for creating decorators and for object composition.
Joshua Bloch in Effective Java, 2nd Edition, Item 16 'Favor Composition Over Inheritance' shows a good example: inheritance is easy-to-break, and decorators are not.
Inheritance:
class LoggingList<E> : ArrayList<E>() {
override fun add(e: E): Boolean {
println("added $e")
return super.add(e)
}
override fun addAll(e: Collection<E>): Boolean {
println("added all: $e")
return super.addAll(e) // oops! Calls [add] internally.
}
}
Delegation:
class LoggingList<E>(delegate: MutableList<E>) : MutableList<E> by delegate {
override fun add(e: E): Boolean {
println("added $e")
return delegate.add(e)
}
override fun addAll(e: Collection<E>): Boolean {
println("added all: $e")
return delegate.addAll(e) // all OK
// it calls [delegate]'s [add] internally, not ours
}
}
It is useful because of the Delegation Pattern where most of the behavior can be the same as the target of the delegation (b) but you just want to override a subset of methods to act differently.
An example would be an InputStream implementation which delegates all work to another InputStream but overrides the close() method to not close the underlying stream. This could be implemented as:
class CloseGuardInputStream(private val base: InputStream)
: InputStream by base {
override fun close() {}
}
Following is the example :-
interface Mode{
val color:String
fun display()
}
class DarkMode(override val color:String) : Mode{
override fun display(){
println("Dark Mode..."+color)
}
}
class LightMode(override val color:String) : Mode {
override fun display() {
println("Light Mode..."+color)
}
}
class MyCustomMode(val mode: Mode): Mode{
override val color:String = mode.color
override fun display() {
mode.display()
}
}
Now, the custom mode can reuse display() function of both modes DarkMode & LightMode
fun main() {
MyCustomMode(DarkMode("CUSTOM_DARK_GRAY")).display()
MyCustomMode(LightMode("CUSTOM_LIGHT_GRAY")).display()
}
/* output:
Dark Mode...CUSTOM_DARK_GRAY
Light Mode...CUSTOM_LIGHT_GRAY
*/
Kotlin natively support delegation pattern.
Kotlin provides by keyword to specify the delegate object which our custom mode will be delegating to.
We can achieve the same result of the code above using by keyword.
class MyCustomMode(val mode: Mode): Mode by mode
fun main() {
MyCustomMode(DarkMode("CUSTOM_DARK_GRAY")).display()
MyCustomMode(LightMode("CUSTOM_LIGHT_GRAY")).display()
}
/* output:
Dark Mode...CUSTOM_DARK_GRAY
Light Mode...CUSTOM_LIGHT_GRAY
*/