Kotlin extension function for View.setMargins - kotlin

I am trying to write a kotlin extension function for view to update the current view margin. I know that for the same you need to make change to view's layoutParams, although I am trying to create a generic method & unable to understand how to pass the parent viewgroup / layout type to handle this.
fun <T> View.setMargins(margin:Int){
var lp = // don't know how to get layout params here
// how to get RelativeLayout.LayoutParams or ViewGroup.LayoutParams etc..
// if I do this.layoutParams then I am unable to call setMargins function on that since it is only available for RelativeLayout.LayoutParams / VeiwGroup.LayoutParams etc etc..
}

When you are using extension function your receiver type will become parameter as this inside that block.
So you can use like this way.
fun <T> View.setMargins(margin:Int){
if (this.layoutParams is ViewGroup.MarginLayoutParams) {
val params = this.layoutParams as ViewGroup.MarginLayoutParams
params.setMargins(<your_margins>);
}
}

I think kotlinx already done that, check it out

Related

Can't understand specific kind of kotlin functions

For example:
private fun TextView.onEndDrawableClicked(onClicked: (view: TextView) -> Unit) {
this.setOnTouchListener { v, event ->
var hasConsumed = false
if (v is TextView) {
if (event.x >= v.width - v.totalPaddingRight) {
if (event.action == MotionEvent.ACTION_UP) {
onClicked(this)
}
hasConsumed = true
}
}
hasConsumed
}
}
In the example above we see extension function. I know what it is and can use use/create similar ones. But there's onClicked: (view: TextView) -> Unit in the example's parameters. What is this? Callback? I see this kind of parameters too often, but don't have any idea how to understand that. Does it reference to some lambda function? Can someone send me detailed manual/example of this kind of parameters/functions/whatever?
onClicked is a function that gets passed to onEndDrawableClicked. It's type is a functional type (view: TextView) -> Unit. That function, when called, expects one parameter view of type TextView and returns Unit.
So yes, it is a callback, passed as a lambda. It can be used like:
val textView: TextView = ...
textView.onEndDrawableClicked {
// code that should be executed when onClicked gets called.
}
Functions are first class citiziens in Kotlin. Meaning you can store function in variables and pass them to other functions. Or let functions return functions.
When to use?
You can pass a function whenever you want to pass behavior (rather than state) to or from your functions. So the caller can decide what to do in those cases. That allows you to write highly flexible code / API's.
Alternatively you could create an interface with one ore many functions to be called and pass an instance of that interface to your function.

Using Kotlin's extension function to suppress a returned value

I am using Kotlin in a spring boot application. Especially in the services, I have found that some of the function need to suppress the returned value from repository. For example, here is a save() that saves an entity without returning the persisted entity id:
fun save(person: Person) {
personRepository.save(person)
}
As you can see that this function simply delegates the call to the JpaRepository#save(...) and does not return anything. What I wanted to do was something like this:
fun save(person: Person) = personRepository.save(person)
In order to do this, I have created an extension function:
fun Any.ignoreReturn() = Unit
and then make the call to the `personRepository#save(...) as:
fun save(person: Person) = personRepository.save(person).ignoreReturn()
What I wanted to know was:
Is this the right way to do it?
Are there side effects to such extension function as I am extending Any?
One way could be to do it like this:
fun save(person: Person): Unit = let { personRepository.save(person) }
Important part there is to declare the function to return Unit so the generated code from let wont need to return what personRepository.save(person) is returning. You can test it, just remove : Unit part and you get different signature for your save function.

Using Fuel's responseObject with a generic call site

I've a problem using Fuel's responseObject in a generic fashion. I'm trying to develop a centralized method with components getting their HTTP response object already deserialized, ready to go. It looks like this:
class Controller(private val url: String) {
fun <T> call(endpoint: String): T {
return "$url/$endpoint".httpGet().responseObject<T>()
}
}
class App(private val controller: Controller) {
fun getModel() {
val model = controller.call<AppModel>("model")
// use model
}
}
Of course, Controller.call would handle errors, and add common request parameters. The deserialization from JSON is supposed to be handled by Jackson (AppModel is a simple data class Jackson should pick up automatically), so I'm working with fuel-jackson:1.12.0 as an added dependency.
Now, using Kotlin-1.2.21, I get this compiler error:
Error:(35, 97) Kotlin: Cannot use 'T' as reified type parameter. Use a class instead.
How do I work around this, perhaps by switching to a different Fuel method?
I've considered making call inline (to reify T), but this defeats the purpose of having a private val url.
I don't think there's a simple workaround to this problem.
First, there's no way to call a Kotlin inline function with a reified type parameter without either using a concrete type or propagating the type argument through a chain of generic calls to inline functions, so you have to call .httpGet().responseObject<T>() from an inline function and use a reified type parameter as T.
Next, there's a reason for the restrictions on what an inline function can access. Basically, allowing inline functions to access non-public API would sometimes break binary compatibility. This is described in the docs here.
What you can do is, as suggested in the docs, make private val url: String a #PublishedApi internal val and, accordingly, go on with inline fun <reified T> call(...).
If you are worried about url becoming effectively public, you might want to take a look at this Q&A suggesting a workaround with #JvmSynthetic.

Kotlin - Extension for final class

Is it possible to create extension of final classes like String? Like in swift it is possible to add additional methods inside a extension of final class.
For an example - I would like to create a method in String extension which will tell me String have valid length for password.
val password : String = mEdtPassword!!.getText().toString()
// how to define haveValidLength method in extension
val isValid : Boolean = password.haveValidLength()
Note - That example is just for a sake to understand usability of extension, not a real scenario.
yes, you can. Kotin extension method provides the ability to extend a class with new functionality without having to inherit from the class or use any type of design pattern such as Decorator.
Below is an extension method for a String:
// v--- the extension method receiver type
fun String.at(value: Int) = this[value]
And the extension method code generated as Java below:
public static char at(String receiver, int value){
return receiver.charAt(value);
}
So an extension method in Kotlin is using delegation rather than inheritance.
Then you can calling an extension method like as its member function as below:
println("bar".at(1))//println 'a'
You also can write an extension method for the existing extension function, for example:
fun String.substring(value: Int): String = TODO()
// v--- throws exception rather than return "ar"
"bar".substring(1)
But you can't write an extension method for the existing member function, for example:
operator fun String.get(value: Int): Char = TODO()
// v--- return 'a' rather than throws an Exception
val second = "bar"[1]
Trying to add more detail, this answer might be helpful for someone.
Yes we can add additional methods to final classes like String. For an example I would like to add one method in String which will tell me that my String have valid number of characters for password or not.
So what I have to do is, I have ti create a below function which can be written in same class or at different separate class file.
fun String.hasValidPassword() : Boolean {
// Even no need to send string from outside, use 'this' for reference of a String
return !TextUtils.isEmpty(this) && this.length > 6
}
And now from anywhere call
val isValid : Boolean = password.haveValidLength()
Suggestion
If your application just has a single password validation, then there is no problem.
However, I don't suggest you write such a extension method hasValidPassword if the application has more than one validation. since the extension method is satically, you can't change your hasValidPassword in runtime. So if you want to change the validation in runtime, you should using a function instead, for example:
class PasswordRepository(private val validate:(String)->Boolean){
fun save(value:String){
if(validate(value)){
//TODO persist the password
}
}
}
val permitAll = PasswordRepository {true}
val denyAll = PasswordRepository {false}
permitAll.save("it will be persisted")
denyAll.save("it will not be persisted")
In other words, the extension method above violates Single Responsibility Principle, it does validation & string operations.
You can do that with extension functions in Kotlin. With extensions, you are able to add extra functionality to a class that you do or do not have access to; for example a legacy code base. In the example given in the Kotlin docs here, swap was added to MutableList<Int> which doesn't have swap originally. A this keyword is used that refers to the object that the swap functionality will operate on. In the example below, this refers to testList
val testList = mutableListOf(1, 2, 3)
testList.swap(0, 2)

How i can reused/compose part of a JOOQ query in a repository method?

With a JOOQ DSLContext variable ctx I have a method to select all relationship data.
open fun selectAllSomethings(id: String): List<SomeDto> = ctx
.select(..),
.from(..)
.join(..)
.leftJoin(...)
.fetch()
.map()
And I need to reused this logic with an add method where for a concrete id I want to change the code to use fetchOne and map. How can I reuse the first part of query and share it between both methods? This part:
ctx.select(..),
.from(..)
.join(..)
.leftJoin(...)
Is it necessary to divide this into two different methods? Or need to add an if ?
This answer is not syntactically perfect -- without having your generated model, nor knowing the full types I can only show a rough sample. The solution would basically be a shared method used by two other methods:
private fun DSLContext.baseThingQuery(id: String): ResultQuery<Record> {
return select(...)
.from(...)
.join(...).on(...)
.leftJoin(...).on(...)
}
fun fetchAllThings(id: String): List<ThingDto> {
return ctx.baseThingQuery(id).fetch(...).map(...)
}
fun doSomethignWithOneThing(id: String): ThingDto {
return ctx.baseThingQuery(id).fetchOne(...).map(...)
}
Note: I made the shared utility function extend the DSLContext just so that it is more obvious that it is intended as a function to only be used within a context (i.e. transaction) and also private to make it truly internal. You could easily change this to pass in the context as a parameter.