How to convert a complex Java lambda to Kotlin? - kotlin

I'm trying to convert following Java code to Kotlin (interface implementations omitted for readability):
public class Test {
public static void main(String[] args) {
validate("some text", extractor -> s -> check(s, extractor));
}
private static void validate(String s, Function<Extractor, Validator> factory) {
final Extractor extractor = all -> all; // use some more meaningful extractor here
factory.apply(extractor).validate(s);
}
private static boolean check(String s, Extractor extractor) {
return s.equals(extractor.extract(s));
}
interface Extractor {
String extract(String all);
}
interface Validator {
boolean validate(String s);
}
}
This contains a very compact lambda-expression which I would like to translate to Kotlin (for a slightly more readable alternative of the Java lambda, see [1]). My current solution keeps the interfaces, but this seems to result in a rather complex call (compare validate-invocations in main):
object Test {
fun main(args: Array<String>) {
validate("test", object : Function<Extractor, Validator> {
override fun apply(extractor: Extractor): Validator {
return object : Validator {
override fun validate(s: String): Boolean {
return check(s, extractor)
}
}
}
})
}
private fun validate(s: String, factory: Function<Extractor, Validator>) {
val extractor : Extractor = object : Extractor { // use some more meaningful extractor here
override fun extract(all: String): String {
return all
}
}
factory.apply(extractor).validate(s)
}
private fun check(s: String, extractor: Extractor): Boolean {
return s == extractor.extract(s)
}
internal interface Extractor {
fun extract(all: String): String
}
internal interface Validator {
fun validate(s: String): Boolean
}
}
Question: when keeping the interfaces as is, is there some more efficient validate-call?
Follow-up question: the logic requires a configurable validation (Validator) with complex check-methods using configurable extraction (Extractor). What would be a more idiomatic design?
[1] The compact lambda corresponds to following more readable code:
public static void main(String[] args) {
validate("some text", extractor -> {
return s -> {
return check(s, extractor);
};
});
}

Function can already be converted to a lambda. Next, declare Extractor and Validator as fun interface. Then code can finally be rewritten as:
object Test {
fun main(args: Array<String>) {
validate("test") { extractor -> Validator { s -> check(s, extractor) } }
}
private fun validate(s: String, factory: Function<Extractor, Validator>) {
val extractor = Extractor { all -> all } // use some more meaningful extractor here
factory.apply(extractor).validate(s)
}
private fun check(s: String, extractor: Extractor): Boolean {
return s == extractor.extract(s)
}
internal fun interface Extractor {
fun extract(all: String): String
}
internal fun interface Validator {
fun validate(s: String): Boolean
}
}

Related

Converting Java Retrofit callback to Kotlin

I have this Java code:
Services.nfGetIncreasedRiskZones(new Callback() {
#Override
public void onResponse(Call call, Response response) {
}
#Override
public void onFailure(Call call, Throwable t) {
}
});
The service it is calling:
public static void nfGetIncreasedRiskZones(Callback callback) {
NfGetIncreasedRiskZones service = App.getRetrofitWithHeaders(App.getBaseUrl()).create(NfGetIncreasedRiskZones.class);
Call call = service.getRiskZones();
call.enqueue(callback);
}
And the NfGetIncreasedRiskZones interface:
interface NfGetIncreasedRiskZones {
#GET(Constants.NfGetIncreasedRiskZones)
Call getRiskZones();
}
The retrofit Callback interface look like this:
public interface Callback<T> {
void onResponse(Call<T> call, Response<T> response);
void onFailure(Call<T> call, Throwable t);
}
How can I convert the first part, the "Services.nfGetIncreasedRiskZones", to Kotlin
Thank you
My best guess here is, that you are interested in how to instantiate anonymous interfaces in Kotlin and this is probably how you'd do it. Here is a quick example I hacked together on my Kotlin REPL. It's probably not the same interface you are using but it should work the same way.
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Response
import java.io.IOException
val callback = object: Callback {
override fun onResponse(call: Call, t: Response?){
println("onResponse")
}
override fun onFailure(call: Call?, t: IOException?){
println("onFailure")
}
}
callback.onFailure(null, null) //prints "onFailure"
callback.onResponse(null, null) //prints "onSuccess"
So basically you need the object: in front of your interface and you don't need the () after the interface. The rest is more or less the same except for the slightly different syntax.
BTW: If you are sure that the parameters of the methods are never null, you don't need the ? after the parameter type.
Here I implemented a sample Service and set the anonymous callback, then run it:
class Service {
companion object {
var cb: Callback? = null
fun set(callback: Callback){
cb = callback
}
fun run() {
cb?.onResponse(null, null)
}
}
}
Service.set(object: Callback{
override fun onResponse(call: Call?, t: Response?){
println("onResponse")
}
override fun onFailure(call: Call?, t: IOException?){
println("onFailure")
}
})
Service.run() //prints "onResponse"

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}

Kotlin fallback wrapper

I'm looking for an elegant solution to the following.
I'd like to implement a Wrapper class that:
Accepts 2 implementations of the same Interface, and returns a new instance of that same Interface.
Any method call to the Wrapper object, tries to call the same method on the 1st implementation.
If the first call results into UnsupportedOperationException, then the 2th implementation should be used instead.
interface API {
fun getData(): String
}
class Main: API {
override fun getData(): String {
throw UnsupportedOperationException()
}
}
class Fallback: API {
override fun getData(): String {
return "data"
}
}
class Wrapper {
companion object {
fun getInstance(main: API, fallback: API): API {
// TODO
}
}
}
class Test {
#Test
fun `invokes the fallback instance`() {
val wrapper = Wrapper.getInstance(Main(), Fallback())
val response = wrapper.getData()
assertEquals(response, "data")
}
}
The best thing I have come up with so far is Delegate with Overrides:
class Wrapper(fallback: API): API by Main() {
val fallback = fallback
override fun getData(): String {
return fallback.getData()
}
}
What I don't like about this solution is that:
It requires overriding each unsupported operation
It gets quite verbose as the Interface grows into a complex multilevel structure with more sub interfaces
I'd also like to avoid Reflection for performance reasons and because this is a Kotlin Multiplatform project.
Any suggestions are appreciated.
Thanks,
Juan
Your proposed solution won't work because it will always favor the fallback for any overridden function.
There's no solution for your needs that can avoid having to manually handle every function of your interface. But you can have an intermediate function that handles the cascading selection of implementation for functions with the same signature.
class Wrapper (private val delegates: Array<out API>): API {
companion object {
fun getInstance(vararg delegates: API) = Wrapper(delegates)
}
private fun <R> delegate0Arg(function: API.() -> R): R {
for (delegate in delegates) {
try {
return delegate.function()
} catch (e: UnsupportedOperationException) {
// continue
}
}
throw UnsupportedOperationException()
}
override val name: String get() = delegate0Arg(API::name)
override fun getData(): String = delegate0Arg(API::getData)
}
But you would need additional functions to handle each unique number of arguments the interface functions have.
private fun <T, R> delegate1Arg(t: T, function: API.(t: T) -> R): R {
for (delegate in delegates) {
try {
return delegate.function(t)
} catch (e: UnsupportedOperationException) {
// continue
}
}
throw UnsupportedOperationException()
}
override fun getData(x: String) = delegate1Arg(x, API::getData)

How to convert Flow into Flowable?

I've just added
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:1.3.3"
to the project. And I have suspend fun foo(): Flow<Bar> in class A (from external package).
I need to get Flowable<Bar> to use in java.
I'd like to use extention fun A.fooRx(): Flowable<Bar> if possible.
You have to sneak out the returned Foo<Bar> from the coroutine in Kotlin:
// SomeSuspendAPI.kt
// -----------------
// the method to convert
suspend fun <T> Flow<T>.foo() : Flow<Int> {
return flow { emit(0) }
}
#ExperimentalCoroutinesApi
fun <T> Flow<T>.fooRx() : CompletableFuture<Flowable<Int>> {
val self = this
val future = CompletableFuture<Flowable<Int>>()
GlobalScope.launch {
try {
future.complete(self.foo().asFlowable())
} catch (ex: Throwable) {
future.completeExceptionally(ex);
}
}
return future
}
// Demo purposes
fun <T> just(v: T) = flow { emit(v) }
Then you can use that within Java:
public class UseFoo {
public static void main(String[] args) throws Exception {
SomeSuspendAPIKt.fooRx(
SomeSuspendAPIKt.just(1)
)
.thenAccept(flowable -> flowable.subscribe(System.out::println))
.join();
}
}
Edit 1:
You can, of course move some code back to the kotlin side:
fun <T> Flow<T>.fooRx2() : Flowable<Int> {
val self = this
val subject = SingleSubject.create<Flowable<Int>>()
GlobalScope.launch {
try {
subject.onSuccess(self.foo().asFlowable())
} catch (ex: Throwable) {
subject.onError(ex)
}
}
return subject.flatMapPublisher { it }
}
Then
public class UseFoo {
public static void main(String[] args) throws Exception {
SomeSuspendAPIKt.fooRx2(SomeSuspendAPIKt.just(1))
.blockingSubscribe(System.out::println);
}
}
Edit 2:
You can generalize this by using a transformation on the Kotlin side which gets you a continuation object to pass along:
fun <T, R: Any> Flow<T>.transformAsync(fn: suspend (t: Flow<T>) -> Flow<R>) : Flowable<R> {
val self = this
val subject = SingleSubject.create<Flowable<R>>()
GlobalScope.launch {
try {
val r = fn(self).asFlowable();
subject.onSuccess(r)
} catch (ex: Throwable) {
subject.onError(ex)
}
}
return subject.flatMapPublisher { it }
}
public class UseFoo {
public static void main(String[] args) throws Exception {
SomeSuspendAPIKt.transformAsync(
SomeSuspendAPIKt.just(1),
(source, cont) -> SomeSuspendAPIKt.foo(source, cont)
)
.blockingSubscribe(System.out::println);
}
}

Binding custom data type transmit null to converter

I'm using Jooq and Kotlin in my project. I have object EventEnvelope in which field of type Event is composed. I want to store this field as JSON in my DB (postgres). I prepared jooq custom datatype bindings and converter as it is described here -> https://www.jooq.org/doc/3.10/manual/code-generation/custom-data-type-bindings/
Below I paste converter, binding and gradle generator code.
My questions are:
Is it ok to use kotlin non null types with jooq bindings?
Is this configuration ok? What should I change?
When I want to store value my converter gets null in from func. I don't why is that.
I am out of ideas what should I do to fix it.
class JSONEventConverter constructor(
private val objectMapper: ObjectMapper,
private val schemaMatcher: SchemaMatcher
) : Converter<Any, Event> {
override fun from(databaseObject: Any): Event {
return schemaMatcher.parse(databaseObject.toString())
}
override fun to(userObject: Event): Any {
return objectMapper.writeValueAsString(userObject)
}
override fun fromType(): Class<Any> {
return Any::class.java
}
override fun toType(): Class<Event> {
return Event::class.java
}
companion object {
fun create(): JSONEventConverter {
return JSONEventConverter(jacksonObjectMapper(),
SchemaMatcher.create())
}
}
}
class PostgresJSONEventBinding : Binding<Any, Event> {
override fun register(ctx: BindingRegisterContext<Event>?) {
ctx!!.statement().registerOutParameter(ctx.index(), Types.VARCHAR)
}
override fun sql(ctx: BindingSQLContext<Event>?) {
ctx!!.render().visit(DSL.`val`(ctx.convert(converter())
.value())).sql("::json")
}
override fun converter(): Converter<Any, Event> {
return JSONEventConverter.create()
}
override fun get(ctx: BindingGetResultSetContext<Event>?) {
ctx!!.convert(converter())
.value(ctx.resultSet().getString(ctx.index()))
}
override fun get(ctx: BindingGetStatementContext<Event>?) {
ctx!!.convert(converter())
.value(ctx.statement().getString(ctx.index()))
}
override fun get(ctx: BindingGetSQLInputContext<Event>?) {
throw SQLFeatureNotSupportedException()
}
override fun set(ctx: BindingSetStatementContext<Event>?) {
ctx!!.statement().setString(ctx.index(),
Objects.toString(ctx.convert(converter()).value(), null))
}
override fun set(ctx: BindingSetSQLOutputContext<Event>?) {
throw SQLFeatureNotSupportedException()
}
}
generator {
name = 'org.jooq.util.DefaultGenerator'
strategy {
name = 'org.jooq.util.DefaultGeneratorStrategy'
}
database {
name = 'org.jooq.util.postgres.PostgresDatabase'
schemata {
schema {
inputSchema = someSchema
}
schema {
inputSchema = otherSchema
}
}
forcedTypes {
forcedType {
userType = 'package.Event'
binding = 'package.PostgresJSONEventBinding'
expression = 'someSchema\\.event_store\\.event'
}
}
}
generate {
relations = true
deprecated = false
records = true
immutablePojos = true
fluentSetters = true
}
target {
packageName = appName
}
}
Is it ok to use kotlin non null types with jooq bindings?
jOOQ (or any Java library) will not respect your Kotlin non-nullable guarantees and might produce null values where you wouldn't expect them. So, perhaps it's not a good idea after all.
At the interface between jOOQ and your code, you must ensure yourself that this cannot happen.
Is this configuration ok? What should I change?
That's an open ended question. If you have any specific questions, please ask.
When I want to store value my converter gets null in from func. I don't why is that.
There are not enough infos in your question to help you about this
Ok so in my case it was about java-kotlin interoperability between nullable types in Java and non-null types in kotlin. All I had to do was implementing converter using nullable types in kotlin (the ones with ?).
Correct converter look like this:
class JSONEventConverter constructor(
private val objectMapper: ObjectMapper,
private val schemaMatcher: SchemaMatcher
) : Converter<Any, Event> {
override fun from(databaseObject: Any?): Event? {
return databaseObject?.let { schemaMatcher.parse(it.toString()) }
}
override fun to(userObject: Event?): Any? {
return userObject?.let { objectMapper.writeValueAsString(it) }
}
override fun fromType(): Class<Any> {
return Any::class.java
}
override fun toType(): Class<Event> {
return Event::class.java
}
companion object {
fun create(): JSONEventConverter {
return JSONEventConverter(serializingObjectMapper(),
SchemaMatcher.create())
}
}
}