Slide 1

Slide 1 text

Remembering fields in Java A Lightning Presentation (support slides 2024) By João Esperancinha (2024/03/19)

Slide 2

Slide 2 text

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…

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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?

Slide 5

Slide 5 text

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!

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

@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…

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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…

Slide 12

Slide 12 text

class GoldenGirlsLauncher { companion object { @JvmStatic fun main(args: Array = emptyArray()) { val goldenGirls = GoldenGirls( "Dorothy Zbornak", "Rose Nylund", "Blanche Devereaux", "Sophia Petrillo" ) } } } Arguments Kotlin … the call itself doesn’t change again …however…

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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…

Slide 15

Slide 15 text

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…

Slide 16

Slide 16 text

● 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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

@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

Slide 19

Slide 19 text

● 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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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…

Slide 22

Slide 22 text

● 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

Slide 23

Slide 23 text

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)

Slide 24

Slide 24 text

Conclusions

Slide 25

Slide 25 text

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…

Slide 26

Slide 26 text

Questions?

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Support Video https://youtu.be/rTCjlyGVDGE

Slide 30

Slide 30 text

Thank you!!