Learning Kotlin: The map delegate

Submitted by Robert MacLean on Thu, 08/30/2018 - 09:00

More Information

The next delegate is actually built into something we have looked at before, map and if you use by to refer to one, when you get the value it goes to the map values to look it up.

As a way to illustrate this, we will take some JSON data and parse it with the kotlinx.serialization code. We then loop over each item and convert it into a map which we use to create an instance of User.

  1. import kotlinx.serialization.json.*
  2.  
  3. class User(userValues:Map<String, Any?>) {
  4.     val name: String by userValues
  5.     val eyeColour: String by userValues
  6.     val age : String by userValues
  7. }
  8.  
  9. fun main(args:Array<String>) {
  10.     val json = """[{
  11.        "name":"Robert",
  12.        "eyeColour":"Green",
  13.        "age":36
  14.    },{
  15.        "name":"Frank",
  16.        "eyeColour":"Blue"
  17.    }]""";
  18.  
  19.     (JsonTreeParser(json).read() as JsonArray)
  20.         .map{  
  21.             val person = it as JsonObject
  22.             person.keys.associateBy({it}, {person.getPrimitive(it).content})
  23.         }.map {
  24.             User(it)
  25.         }.forEach { println("${it.name} with ${it.eyeColour} eyes") }
  26.        
  27. }

This code outputs:

Robert with Green eyes
Frank with Blue eyes

However, if we change line 25 to include the age we get a better view of what is happening.

  1. }.forEach { println("${it.name} with ${it.eyeColour} eyes and is ${it.age} years old") }

This simple adjustment changes the output to be:

Robert with Green eyes and is 36 years oldException in thread "main"
java.util.NoSuchElementException: Key age is missing in the map.
        at kotlin.collections.MapsKt__MapWithDefaultKt.getOrImplicitDefaultNullable(MapWithDefault.kt:24)
        at sadev.User.getAge(blog.kt)
        at sadev.BlogKt.main(blog.kt:27)

As you can see, the map is not initialising the values ahead of time. Rather it is merely being used to look up what value in the map when the properties getter is called.

Learning Kotlin: The Observable Delegate (with a slight detour on reference functions)

Submitted by Robert MacLean on Wed, 08/29/2018 - 09:00

More Information

  • This is the 27th post in a multipart series.
    If you want to read more, see our series index
  • Koans used in here are 34 and 35

Following on from our introduction to the by operator and delegates, this post looks at the second of the five built-in delegates, observable.

The next built-in delegate is observable - this allows intercept all attempts to set the value. You can do this with a setter, but remember you would need to duplicate that setter code every time. With the observable, you can build the logic once and reuse it over and over again.

Once again let us start with the way we would do this without the delegated property:

  1. class User() {
  2.     var name: String = "<NO VALUE>"
  3.         set(value) {
  4.             DataChanged("name", name, value)
  5.         }
  6.  
  7.     var eyeColour: String = "<NO VALUE>"
  8.         set(value) {
  9.             DataChanged("eyeColour", name, value)
  10.         }
  11.  
  12.     fun DataChanged(propertyName: String, oldValue: String, newValue: String) {
  13.         println("$propertyName changed! $oldValue -> $newValue")
  14.     }
  15. }
  16.  
  17. fun main(args:Array<String>) {
  18.     val user = User()
  19.     user.name = "Robert"
  20.     user.eyeColour = "Green"
  21. }

Note, that we need to do the setter manually twice and in each one we will need to change a value, which you know you will get missed when you copy & paste the code.

In the next example, we change to use the observable delegate which allows us to easily call the same function.

While I don't recommend this for production, I did in the example call it in two different ways. For age, as the second parameter is a lambda I just create that and pass the parameters to my function. This is how all the demos normally show the usage of this. For name though, since my function has the same signature as the lambda I can pass it directly to the observable which seems MUCH nicer to me. Though since we need to pass a reference to our function we need to prefix it with ::.

  1. package sadev
  2.  
  3. import kotlin.properties.Delegates
  4. import kotlin.reflect.KProperty
  5.  
  6. class User() {
  7.     var name: String by Delegates.observable("<NO VALUE>", ::DataChanged)
  8.  
  9.     var eyeColour: String by Delegates.observable("<NO VALUE>") { property, old, new ->
  10.             DataChanged(property, old, new)
  11.         }
  12.  
  13.     fun DataChanged(property: KProperty<*>, oldValue: String, newValue: String) {
  14.         println("${property.name} changed! $oldValue -> $newValue")
  15.     }
  16. }
  17.  
  18. fun main(args:Array<String>) {
  19.     val user = User()
  20.     user.name = "Robert"
  21.     user.eyeColour = "Green"
  22. }

Learning Kotlin: The Lazy Delegate

Submitted by Robert MacLean on Tue, 08/28/2018 - 09:00

More Information

  • This is the 26th post in a multipart series.
    If you want to read more, see our series index
  • Koans used in here are 34 and 35

Following on from our introduction to the by operator and delegates, this post looks at the first of the five built-in delegates, lazy. Lazy property evaluation allows you to set the initial value of a property the first time you try to get it. This is really useful for scenarios where there is a high cost of getting the data. For example, if you want to set the value of a username which requires a call to a microservice but since you don't always need the username you can use this to initial it when you try and retrieve it the first time.

Setting up the context for the example, let us look at two ways you may do this now. The first way is you call the service in the constructor, so you take the hit immediately regardless if you ever need it. It is nice and clean though.

  1. class User {
  2.     val name: String
  3.  
  4.     constructor(id:Int){
  5.         // load service ... super expensive
  6.         Thread.sleep(1000)
  7.         name = "Robert"
  8.     }
  9. }
  10.  
  11. fun main(args:Array<String>) {
  12.     val user = User(1)
  13.     println(user.name)
  14. }

The second solution is to add a load function so we need to call that to load the data. This gets rid of the performance hit but is less clean and if you forget to call load your code is broken. You may think, that will never happen to me... I just did that right now while writing the sample code. It took me less than 2 min to forget I needed it. 🙈

Another pain is I need to make my name property variable since it will be assigned at a later point.

  1. class User(val id: Int) {
  2.     var name: String = ""
  3.  
  4.     fun load() {
  5.         // load service ... super expensive
  6.         Thread.sleep(1000)
  7.         name = "Robert"
  8.     }
  9. }
  10.  
  11. fun main(args:Array<String>) {
  12.     val user = User(1)
  13.     user.load()
  14.     println(user.name)
  15. }

The solution to this is obviously lazy - this gives us the best of all of the above (clean code, no performance hit unless I need it, can use val, no forgetting things) and none of the downsides.

  1. class User(val id: Int) {
  2.     val name: String by lazy {
  3.         // load service ... super expensive
  4.         Thread.sleep(1000)
  5.         "Robert"
  6.     }
  7. }
  8.  
  9. fun main(args:Array<String>) {
  10.     val user = User(1)
  11.     println(user.name)
  12. }

Learning Kotlin: by

Submitted by Robert MacLean on Mon, 08/27/2018 - 09:00

More Information

  • This is the 25th post in a multipart series.
    If you want to read more, see our series index
  • Koans used in here are 34 and 35

The fourth set of Koans looks at properties and the first two look at getters and setters. If you coming from another programming language then these should work the way you expect they should. This post will look at the amazing by keyword in the third and fourth examples. The by keyword enables us to delegate the getter/setter to be handled by a separate class which means that common patterns can be extracted and reused.

Out of the box, there are five built-in options which I will expand into in their own posts, but for now, let us build our own delegate class. In this example, we can assign any value but the result we get is always HAHAHA. We could store the result in the instance and return the value assigned but we do not have to. The key take away is that we have ensured the logic for our properties in one reusable place, rather than scattered across multiple getters and setters.

  1. import kotlin.reflect.KProperty
  2.  
  3. class User {
  4.     var name : String by Delegate()
  5.     var eyeColour : String by Delegate();
  6. }
  7.  
  8. class Delegate {
  9.     operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
  10.         println("$thisRef, thank you for delegating '${property.name}' to me!")
  11.         return "HAHAHA"
  12.     }
  13.  
  14.     operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
  15.         println("$value has been assigned to '${property.name}' in $thisRef.")
  16.     }
  17. }
  18.  
  19. fun main(args: Array<String>) {
  20.     val user = User()
  21.     user.name = "Robert"
  22.     user.eyeColour = "Green"
  23.     println("My word ${user.name} but your eyes are ${user.eyeColour}")
  24. }

Learning Kotlin: todo

Submitted by Robert MacLean on Fri, 08/24/2018 - 09:00

More Information

  • This is the 24th post in a multipart series.
    If you want to read more, see our series index

This post will be a shorter than normal one, as we are looking at a small feature that is easy to explain but can have major impacts to your code base and that is the todo function.

To use it, you simply call it and optionally pass in a string which gives a reason why that code is not done. For example:

  1. fun main(args:Array<String>) {
  2.   todo("Haven't started")
  3. }

This will throw a NotImplementedError when it is encountered. What I really like about this is that we are being explicit about the intent. In addition it makes it really easy to find in your IDE of choice.

Learning Kotlin: The .. operator

Submitted by Robert MacLean on Thu, 08/23/2018 - 09:00

More Information

  • This is the 23rd post in a multipart series.
    If you want to read more, see our series index
  • The code for this can be found on GitHub

No, I didn't forget what this operator is and just put two dots in place of it. The operator we are looking at is really ..! This operator pairs very nicely with the in operator we looked at previously in that it allows us to very easily create an instance of a class which can define a range. Let us look at a real example we have used already to help clear that up 1..10.

What we have in that is an Int, then the operator, then another Int and when we do that, we get an instance of ClosedRange<Int>. This is done by saying if you ask for a range of Ints, you get a different class which knows how to store the start and end Ints and work out the parts in that range. This is done with the rangeTo operator function which is added to the Int class.

In the same way that Ints support this, we can use it too. If we look at the previous post about the in operator, you can see we are using a custom class called MyDate to represent a date value and we also have a DateRange class to represent the start and end dates and we could check if a value fell in that range with this code:

  1. fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
  2.    return date in DateRange(first, last)
  3. }

If we add the rangeTo to the MyDate class and have it return a DateRange like this:

  1. data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) {
  2.     operator fun rangeTo(other: MyDate) = DateRange(this, other)
  3. }

We can now change our previous example to support the .. operator!

  1. fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
  2.    return date in first..last
  3. }

It compiles to the EXACT same code, but it just looks so much better!

Slides: Features of Kotlin I find exciting

Submitted by Robert MacLean on Wed, 08/22/2018 - 09:00

A few weeks ago I was honoured to speak at the first Developer User Group meetup in Cape Town, and it is no surprise I am sure, that I spoke for about 15min on what my favourite features in Kotlin are. Thank you to all who attended and if you are looking for the slides, they can be found below! They look broken, but this is because SlideShare can't deal with animation so be sure to download them to check them out!

If you are interested in more Kotlin talks, I will be speaking next week at the Facebook Developer Circle for over an hour giving an introduction to Kotlin. It is going to be a great session, I am biased though, so I do hope you join me!

Learning Kotlin: Looking at the In Operator & Contains

Submitted by Robert MacLean on Tue, 08/21/2018 - 09:00

More Information

  • This is the 22nd post in a multipart series.
    If you want to read more, see our series index
  • The code for this can be found here

One of my absolute favourite features in Kotlin are ranges. You can easily go 1..10 to get a range of numbers from one to ten. In addition, so much of the way I find I want to work with Kotlin is around working with collections like lists and arrays.

With all of those, we often want to know when something exists inside the range or the collection and that is where the in operator comes in. In the following example we use the in operator to first check for a value in an array, then in a range, then a substring in a string; each example below will return true.

  1. val letters = arrayOf("a", "b", "c", "d", "e")
  2. println("c" in letters)
  3.  
  4. println(5 in 1..10)
  5.  
  6. println("cat" in "the cat in the hat")

Naturally, Kotlin lets us add this to our own classes too. The example from the Koans starts with a class which represents a range of dates.

  1. class DateRange(val start: MyDate, val endInclusive: MyDate)

We then add an operator function named contains which checks if the value provided falls in between the two dates of the class:

  1. class DateRange(val start: MyDate, val endInclusive: MyDate) : Iterator<MyDate> {
  2.     operator fun contains(d: MyDate) = start <= d && d <= endInclusive
  3. }

With this new function we can write our own in statement, for example:

  1. fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
  2.    return date in DateRange(first, last)
  3. }

The security risk that is the humble link in your webpages

Submitted by Robert MacLean on Fri, 08/17/2018 - 09:00

tl;dr: When adding the target attribute to an a element which takes you to a property you do not own, you must add rel="noopener noreferrer".

Info

When you open a link using target, for example in a new tab (target="_blank"), the browser may, not done universally but Firefox & Chrome both do it, set the window.opener of the new tab to be the original window. This means that the new tab can access some of the info from the original window/tab.

If it is on the same domain then that is a lot, including cookies and content. If it is on a different domain then same origin policy will protect that information, though some things are still available.

Attack Vectors

These attack vectors are very targeted and don’t represent a major risk IMHO but at the same time, the cost of doing this is less than the risk so it is a recommendation from me.

Same Domain

It is not uncommon for a single domain to have pieces built by multiple teams, especially as web components get better adoption so a vulnerability in any team contributing to the content now has the potential to impact all teams.

For example: https://badsite.com/login.html is built by teamA and has a simple login to the backend. https://badsite.com/products.html is built by teamB and is a public site listing products. If the login had a link to products which opened in a new tab then all JS in products can manipulate the login page, for example by silently injecting code which sends the login details to the attacker. This example is also a good reason to embrace sub-resource integrity, especially if you are using a CDN for JS, CSS etc...

It is also possible to use document.domain to get increased access to super domains; though things like cookies are still not accessible since the change will have been detected.

Different Domain

In this scenario, the data is really locked down though there are two possible attack vectors here.

Location Changes

The location of the parent window/tab can be changed. This could allow an attacker to redirect the original window/tab to a page which has a vulnerability in it or in a targeted attack, it could open to a page that looks the same.

For example: You open a link from your bank's website to a 3rd party. That 3rd party has a piece of JS (either intentional or unintentional, for example, a compromised CDN resource) which checks the location and sees it is your bank and changes it to a phishing site. You go back to the tab, expecting it to be your bank and log in and have compromised your credentials.

Postmessage

postmessage is an API which allows pages to communicate with each other, even across different domains. If postmessage has been used on the parent and contains a vulnerability that could allow a new page to gain additional privileges.

Solution

Add rel="noopener noreferrer" to your links to prevent window.opener from being set unless you trust the property you are linking to.

Learning Kotlin: Invoke

Submitted by Robert MacLean on Thu, 08/16/2018 - 09:00

More Information

  • This is the 21st post in a multipart series.
    If you want to read more, see our series index

Today we tackle a weird operator, invoke which lets an instance of a class have a default function - which I am not sure I've ever seen any language do. So let us frame this with a simple example, we have a config class which returns the configuarion for something:

  1. class Config {
  2.     fun get():String {
  3.         // do stuff
  4.         return "stuff"
  5.     }
  6. }
  7.  
  8. fun main(args: Array<String>) {
  9.     val config = Config()
  10.     println(config.get())
  11. }

Now, in our world maybe get is the primary use, so we can actually make it that the instance config (line 9) can be called to get it:

  1. class Config {
  2.     operator fun invoke(): String {
  3.         return this.get();
  4.     }
  5.  
  6.     private fun get():String {
  7.         // do stuff
  8.         return "stuff"
  9.     }
  10. }
  11.  
  12. fun main(args: Array<String>) {
  13.     val config = Config()
  14.     println(config())
  15. }

Note that we add a new operator (line 2), and that calls the private get; it didn't need to be private but I thought let us have this be cleaner, and now on line 14 we can just call the instance itself.

Now, you may be thinking... nice but so what saving a few keystrokes isn't too awesome. Well, invoke can return anything, including itself which opens up something crazy.

  1. class Config {
  2.     var count = 0;
  3.     operator fun invoke(): Config {
  4.         count++
  5.         return this
  6.     }
  7. }
  8.  
  9. fun main(args: Array<String>) {
  10.     val config = Config()
  11.     config()()()()()()()()()()
  12.     println("config was called ${config.count} times")
  13. }

This will print out config was called 10 times. That is getting more interesting, so let us ramp up another level and pass parameters to invoke:

  1. class Config {
  2.     var word = ""
  3.     operator fun invoke(s: String): Config {
  4.         word += s
  5.         return this
  6.     }
  7. }
  8.  
  9. fun main(args: Array<String>) {
  10.     val config = Config()
  11.     config("R")("o")("b")("e")("r")("t")
  12.     println(config.word)
  13. }

While I do not know yet where I would use this myself, I do use invoke all the time... since it is what makes lambdas possible in Kotlin as when we create a lambda we get an object which is invoked with well... invoke.