Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fields in Java and Kotlin and What to Expect

Fields in Java and Kotlin and What to Expect

In this document I show an example of using Use-site targets in Kotlin. This is a relatively misunderstood feature of Kotlin that gets greatly overlooked by developers used to working with annotations in frameworks like the Spring Framework. The idea is that Kotlin doesn't really has a strategy to go about annotations in data classes if we don't specify the target. In Java, the target was very tangible. In Kotlin is all about abstraction. There can be negatives about this or maybe not.

More Decks by João Filipe Sabino Esperancinha

Other Decks in Technology

Transcript

  1. Topics of today • Traditional data structures in Java •

    Data classes in Kotlin • Records in Java • How do data classes look like • Stereotyping with frameworks • The problem with applying annotations • How to fix the problem • Maybe not a problem, maybe not And just for fun… …we’ll make examples with…
  2. Who am I? • Software Engineer for 10+ years •

    Java, Kotlin, Scala Clojure, Groovy • Studied at ISEL Lisboa in Computer Science and Telecom Engineering • Spring Professional 2020 • OCP11 • Kong Champion
  3. How did Java structures used to look like? Note Java

    structures and their standard although has changed a lot, it is still a part of every JVM oriented language. (getter, setters, fields, parameters and constructor 1995 probably?
  4. public class GoldenGirlsJava { public String goldenGirl1; private final String

    goldenGirl2; private final String goldenGirl3; private final String goldenGirl4; public GoldenGirlsJava() { this.goldenGirl1 = "Dorothy Zbornak"; this.goldenGirl2 = "Rose Nylund"; this.goldenGirl3 = "Blanche Devereaux"; this.goldenGirl4 = "Sophia Petrillo"; } public GoldenGirlsJava( String goldenGirl1, String goldenGirl2, String goldenGirl3, String goldenGirl4 ) { this.goldenGirl1 = goldenGirl1; this.goldenGirl2 = goldenGirl2; this.goldenGirl3 = goldenGirl3; this.goldenGirl4 = goldenGirl4; } public String getGoldenGirl1() { return goldenGirl1; } public void setGoldenGirl1(String goldenGirl1) { this.goldenGirl1 = goldenGirl1; } public String getGoldenGirl2() { return goldenGirl2; } public String getGoldenGirl3() { return goldenGirl3; } public String getGoldenGirl4() { return goldenGirl4; } @Override public String toString() { return "GoldenGirlsJava{" + "goldenGirl1='" + goldenGirl1 + '\'' + ", goldenGirl2='" + goldenGirl2 + '\'' + ", goldenGirl3='" + goldenGirl3 + '\'' + ", goldenGirl4='" + goldenGirl4 + '\'' + '}'; } } Fields Properties Mega code! …however… Attributes Keeps state? Accessors Traditional Java Getters Setter goldenGirl1 not final!
  5. public static void main(String[] args) { var goldenGirlsJava = new

    GoldenGirlsJava( "Dorothy Zbornak", "Rose Nylund", "Blanche Devereaux", "Sophia Petrillo" ); System.out.println(goldenGirlsJava); } Traditional Java Arguments
  6. Lombok was a game changer! Note Lombok, although being able

    to simplify code, it introduce the usage of annotations which a lot of developers found not to be very easy to use (all concepts still visible with an annotation processor) 2009
  7. @Getter @Setter @AllArgsConstructor @ToString public class GoldenGirlsLombok { public String

    goldenGirl1; private final String goldenGirl2; private final String goldenGirl3; private final String goldenGirl4; public GoldenGirlsLombok() { this.goldenGirl1 = "Dorothy Zbornak"; this.goldenGirl2 = "Rose Nylund"; this.goldenGirl3 = "Blanche Devereaux"; this.goldenGirl4 = "Sophia Petrillo"; } } Java with Lombok Fields Properties Attributes Keeps state? Setter goldenGirl1 not final! Getter Accessors Massively reduced! …however…
  8. public static void main(String[] args) { var goldenGirlsLombok = new

    GoldenGirlsLombok( "Dorothy Zbornak", "Rose Nylund", "Blanche Devereaux", "Sophia Petrillo" ); System.out.println(goldenGirlsLombok); } Arguments Java with Lombok … the call itself doesn’t change
  9. Data classes in Kotlin changed that! Note Code simplification is

    very important for many developers. It can arguably create misleading expectations for the average developer (only class members with all concepts compacted in a few lines of code) 2016
  10. data class GoldenGirls( var goldenGirl1: String = "Dorothy Zbornak", private

    val goldenGirl2: String = "Rose Nylund", private val goldenGirl3: String = "Blanche Devereaux", private val goldenGirl4: String = "Sophia Petrillo" ) Kotlin Fields Properties Attributes Keeps state? Setter goldenGirl1 not final! Getter Accessors Even more reduced! …however…
  11. class GoldenGirlsLauncher { companion object { @JvmStatic fun main(args: Array<String>

    = emptyArray()) { val goldenGirls = GoldenGirls( "Dorothy Zbornak", "Rose Nylund", "Blanche Devereaux", "Sophia Petrillo" ) } } } Arguments Kotlin … the call itself doesn’t change again …however…
  12. And Java reacted to that with records Note Java records

    didn’t compacted everything. Java keeps some old semantics, but does introduces that concept of hiding the accessors of a class (same principle, less code and a contentious accolade at the end {}!) 2020
  13. public record GoldenGirlsRecord( String goldenGirl1, String goldenGirl2, String goldenGirl3, String

    goldenGirl4 ) { public GoldenGirlsRecord() { this( "Dorothy Zbornak", "Rose Nylund", "Blanche Devereaux", "Sophia Petrillo" ); } } Java Records Fields Properties Attributes Keeps state? No Setter allowed Getter Accessors The same, but records are truly immutable …however…
  14. public static void main(String[] args) { var goldenGirlsRecord = new

    GoldenGirlsRecord( "Dorothy Zbornak", "Rose Nylund", "Blanche Devereaux", "Sophia Petrillo" ); System.out.println(goldenGirlsRecord); } Arguments Java Records … the call itself also doesn’t change …however…
  15. • Source Repository ◦ https://github.com/jesperancinha/jeorg-kotlin-test-drives • Location Directory: ◦ https://github.com/jesperancinha/jeorg-kotlin-test-drives/tree/main/jeorg-kotlin-crums/jeorg-kotlin

    -crums-3/src/main/kotlin/org/jesperancinha/ktd/crums3/goldengirls Use git clone from the command prompt to download the full code base: > git clone https://github.com/jesperancinha/jeorg-kotlin-test-drives.git You’ll be prompted for a username and password which should be your github account. > cd jeorg-kotlin-crums/jeorg-kotlin-crums-3/src/main/kotlin/org/jesperancinha/ktd/crums3/goldengirls The easy way: > make b > make run The manual way: > mvn clean install > mvn spring-boot:run The Golden Girls Example location
  16. Spring Framework Issues when Kotlin Note CDI implemented with Inversion

    of Control (IoC) was groundbreaking when Spring was released. But along the years it has been also criticized because of its “magic” (annotations need to be assigned to the previous concepts in classes) 2004
  17. @Entity @Table(name = "shelf_case") data class Case( @Id @GeneratedValue(strategy =

    GenerationType.SEQUENCE) val id: Long?, var designation: String?, var weight: Long? ) public final class Case { @Id @GeneratedValue( strategy = GenerationType.SEQUENCE ) @Nullable private final Long id; @Nullable private String designation; @Nullable private Long weight; Decompiling the bytecode to Java Will this work? Of course! The annotations are applied to fields in the bytecode which is what the JPA understands Just using the annotations in the same way as always
  18. • Source Repository ◦ https://github.com/jesperancinha/jeorg-spring-master-test-drives • Location Directory: ◦ https://github.com/jesperancinha/jeorg-spring-master-test-drives/tree/main/furniture-k-shop

    Use git clone from the command prompt to download the full code base: > git clone https://github.com/jesperancinha/jeorg-spring-master-test-drives.git You’ll be prompted for a username and password which should be your github account. > cd furniture-k-shop The easy way: > make b > make run The manual way: > mvn clean install > mvn spring-boot:run Furniture Shop Example location
  19. data class AccountNumbersPassiveDto( @NotNull val accountNumberLong: Long?, val accountNumberNullable: Long?,

    @DecimalMax(value = "10") @DecimalMin(value = "5") val accountNumber: BigDecimal, val accountNumberEven: Int, val accountNumberOdd: Int, @Positive val accountNumberPositive: Int, @Negative val accountNumberNegative: Int, val accountNumberMaxList:Int ) Will this work? Not really … 🤔 public final class AccountNumbersPassiveDto { @Nullable private final Long accountNumberLong; @Nullable private final Long accountNumberNullable; @NotNull private final BigDecimal accountNumber; private final int accountNumberEven; private final int accountNumberOdd; private final int accountNumberPositive; private final int accountNumberNegative; private final int accountNumberMaxList; Decompiling the bytecode to Java No annotation has been applied to a field! How is this possible? Since we do not specify where the annotation is supposed to be applied, it gets applied however it is configured by default. @Nullable is applied because that is how the bytecode translates back to Java when we mark it as final with val and nullable with. The solution? Use-site targets! The problem
  20. data class AccountNumbersPassiveDto( @field:NotNull val accountNumberLong: Long?, val accountNumberNullable: Long?,

    @field:DecimalMax(value = "10") @field:DecimalMin(value = "5") val accountNumber: BigDecimal, val accountNumberEven: Int, val accountNumberOdd: Int, @field:Positive val accountNumberPositive: Int, @field:Negative val accountNumberNegative: Int, val accountNumberMaxList:Int ) Will this work? Yes!👌 public final class AccountNumbersPassiveDto { @NotNull @Nullable private final Long accountNumberLong; @Nullable private final Long accountNumberNullable; @DecimalMax("10") @DecimalMin("5") @org.jetbrains.annotations.NotNull private final BigDecimal accountNumber; private final int accountNumberEven; private final int accountNumberOdd; Decompiling the bytecode to Java The annotations are now applied as they are expected. Because we now specify where the target of our annotation should be, the Kotlin compiler now knows exactly where to use these annotations in the bytecode Use-site targets …however…
  21. • Source Repository ◦ https://github.com/jesperancinha/jeorg-spring-master-test-drives • Location Directory: ◦ https://github.com/jesperancinha/jeorg-spring-master-test-drives/tree/main/furniture-k-shop

    Use git clone from the command prompt to download the full code base: > git clone https://github.com/jesperancinha/jeorg-spring-master-test-drives.git You’ll be prompted for a username and password which should be your github account. > cd the-validation-company The easy way: > make b > make run The manual way: > gradle build > ./gradlew bootRun The Validation Company Example location
  22. The usage of Use-site targets Note The continuous use of

    use-site targets solves a problem, but removes the visibility of how we used to see Java classes and therefore fields, properties, attributes, getters, setters, accessors and arguments have become an abstraction and not something tangible that we can see and map in our mind the way we used to. Java records can be a part of this same problem as well. (the use-site targets try to solve this problem with current frameworks)
  23. Conclusions • The targets are not longer that much visible

    as they used to be before. • Data classes and records are revolutionary in the sense that they reduce boilerplate code and are of course more elegant. • Confusion related especially with annotations costs a lot of time and effort especially for people that just started out in Kotlin and are also beginning with the Spring Framework. • Efforts are underway to create a reliable framework like the Spring Framework like Ktor that uses other paradigms to implement a new framework that no longer uses annotations. The Future • Considering the support of frameworks like IntelliJ, was the boilerplate code a good reason? • There is something better about java records in relation to data classes and that is that they are truly immutable in the sense that at least no reference can be changed in them once created. • Data classes in Kotlin and records in Java are here to stay. • In efforts to make languages simpler, we may be heading into a direction where they actually become more complex. • With the rejection of boilerplate code, we inadvertently also rejected a part of the code that gave visibility to the targets for our annotations. • As immutability indeed has proven multiple times to be a good paradigm to follow, this is where the argument to use data classes and records will rise, but Java appears to have a better advantage here since by not giving the option to make fields mutable in records, we are sure to have a value that never changes across its lifetime. I guess we’ll see later on in the future how it all rolls out…
  24. Resources • https://kotlinlang.org • Vasic, M. (21st May 2018). Building

    Applications with Spring 5 and Kotlin. (First Edition). Packt Publishing • Griffiths, D. Griffiths, D. (February 2019). Head First A Brain-Friendly Guide. (First Edition). O'Reilly • Skeen, J. Greenhalgh, D. (July 2018). Kotlin Programming - The Big Nerd Ranch Guide. (First Edition). Big Nerd Ranch • Jemerov, D. Isakova, S. (2017). Kotlin in Action. (First Edition). Manning Publications Online Books
  25. About me • Homepage - https://joaofilipesabinoesperancinha.nl • LinkedIn - https://www.linkedin.com/in/joaoesperancinha/

    • YouTube - JESPROTECH ▪ https://www.youtube.com/channel/UCzS_JK7QsZ7ZH-zTc5kBX_g ▪ https://www.youtube.com/@jesprotech • Bluesky - https://bsky.app/profile/jesperancinha.bsky.social • Mastodon - https://masto.ai/@jesperancinha • GitHub - https://github.com/jesperancinha • Hackernoon - https://hackernoon.com/u/jesperancinha • DevTO - https://dev.to/jofisaes • Medium - https://medium.com/@jofisaes