23 decembrie 2022

What’s New in Java 11 - partea 2

Ce e nou introdus

java.net.HttpURLConnection -> HttpClient, HttpRequest, HttpResponse

Exemplu #1:











Exemplu #2:















- CompletableFuture a fost introdus în Java8, pentru apeluri asincrone

- join este necesar pentru a aștepta unirea thread-ului curent (main) cu cel care face apelul Http; pentru ca programul să nu se termine înainte de primirea răspunsului


Ce e nou în librării

String:

> "he".repeat(3); // "hehehe"

> "".isBlank(); // true

> "\n\t    text     \u2005".strip();  // "text"

> "1 \n 2 \n 3 \n 4".lines().forEach(System.out::println);   // scrie pe linii noi 1 2  3  4

   

Files:

String readString (Path path);

Path writeString(Path path, CharSequence cs, OpenOptions options);


Optional:  Optional.ofNullable(null).isEmpty();  // true

Predicate::not


Unicode 10

  • update de la Unicode 8 (Java 10)
  • sunt adăugate mai mult de 16.000 caractere noi
  • caracterele aparțin la 10 sisteme de scriere noi, printre care și cel nepalez


Inferența tipului de variabilă locală cu var:

> var name = "Ana";

> (@Nonnull var a, @Nullable var b) -> a.concat(b)










Performanță și securitate

Garbage collector: G1 GC (încă din Java 9)

Noutate: Epsilon GC = rulare fără GC până când crapă aplicația = No GC paradigm

- pt aplicații predictibile în ce privește consumul de memorie, eventual cu o durată de viață mică

- util pt testarea performanței unei aplicații

- este o opțiune experimentală: -XX:+UnlockExperimentalVMOptions, -XX:+UseEpsilonGC

Noutate: Z Garbage Collector

- ia pauză sub 10 secunde

- durata pauzei e constantă (nu crește odată cu heap size)

- disponibil doar în Linux x64: -XX:+UnlockExperimentalVMOptions, -XX:+UseZGC


TLS 1.3 = transport layer security (asemănător https)

11 decembrie 2022

What’s New in Java 11 - partea 1

Java - acum este lansată o dată la 6 luni

Java 11 - marcat pentru suport pe termen lung (LTS)

LTS este doar pentru Oracle JDK (cu subscripție); pentru OpenJDK suportul este de 6 luni, până la următorul release


Java 9: module system

Java 10: local variable type inference

Java 11

  • convergența Oracle JDK cu OpenJDK (singura diferență rămâne LTS)
  • lansat în 2018, în același an cu Java 10; noul plan este de 2 release-uri pe an, cu un LTS o dată la 3 ani („garanția” este minim 3 ani pt produs)
  • poți compila direct java Hello.java (în loc să treci prin pasul intermediar de creare class file) - este limitat la un singur fișier sursă; nu se creează un fișier .class
  • fișier care poate fi rulat ca script (dacă este prefixat cu #! ./bin/java --source 11) - fișierul poate să aibă orice extensie (dacă nu era script se primea eroare)


Deprecări

API-uri scoase din JDK: 

  • java.xml.bind (JAXB) -> jaxb-api & jaxb-impl din javax.xml.bind respectiv com.sun.xml.bind
  • java.xml.ws, java.xml.ws.annotation
  • java.corba
  • java.transaction 
  • java.activation

Metode scoase:

  • destroy & stop(Throwable) din Thread
  • runFinalizersOnExit din java.lang.System & java.lang.Runtime
  • 4 metode din SecurityManager (la functionalitati awt care nu mai sunt suportate)

JavaFX

  • a făcut parte din Oracle JDK 8, 9, 10
  • nu mai face parte din Oracle JDK 11 -> mutat în OpenJFX
  • Javapackager scos -> este propus jpackager

Tehnologii scoase:

  • applet 
  • Java Web Start -> jlink, jpackager?
  • Nashorn (marcat ca deprecated)

28 noiembrie 2022

Spring 5 Fundamentals - ziua 3

Configurări XML

Încă există = se pot folosi. Unele lucruri sunt mai simple cu XML. Se poate separa mai bine de restul codului.

----  application-context.xml  ----

<beans xmlns="" xmlns:xi="" xsi:schemaLocation="">

  <bean name="" class="cale_completă_către_implementare" >
    <property name="speakerRep" ref="speakerRep"> </property>   <!-- setter injection: name definește care setter, iar ref valoarea parametrului (definit mai sus, ca alt bean)  -->
  </bean>

  <bean name="" class="cale_completă_către_implementare" >
    <constructor-arg index="0" ref="speakerRep"> </constructor-arg>   <!-- constructor injection -->
  </bean>

</beans>


 Beans 
  • în esență sunt clase
  • înlocuiesc ce urmează după new 
  • se obțin tot cu appContext.getBean(...)

 Autowiring 
  • byType - face wire cu o instanță de tipul cerut (trebuie să fie unică)
  • byName - face wire după numele bean-ului
  • constructor
  • no (nu dă voie să se facă autowiring)

  <bean name="" class="cale_completă_către_implementare"  autowire="constructor">
  </bean>


Factory Bean


 SpEL  = Spring Expression Language - folosit mai mult în librării 

@Value ("#{ T(java.lang.Math.random() * 100) }")  // se determină la runtime, util în chestiuni de securitate
private double seedNum;


Spring AOP Proxies


 Bean Profiles  

@Repository("speakerRepository")
@Profile("dev")
public class HibernateSpeakerRepositoryImpl implements SpeakerRepository {
  . . .
}


VM option: -Dspring.profiles.active=dev
Altfel, bean-ul nu este disponibil. 

23 noiembrie 2022

Spring 5 Fundamentals - ziua 2

5 scopes

  • Singleton: un singur bean (o singură instanță per container Spring), este scopul prestabilit
  • Prototype: un bean nou (instanță) la fiecare request = opusul lui Singleton
  • Request: un bean la fiecare request http
  • Session: un bean la fiecare sesiune 
  • Global: un bean per aplicație (racordat la durata aplicației, și nu a vizitei mele în aplicație)

Singleton, prototype --> în orice configurație

Request, session, global --> doar în proiecte web


@Service("customerService")

@Scope("singleton")

public class CustomerServiceImpl ...


sau

@Bean(name = "customerRepository")

@Scope(value = BeanDefinition.SCOPE_SINGLETON) // BeanDefinition.SCOPE_PROTOTYPE

public CustomerRepository getCustomerRepository() { ... }


@Autowired

Adnotarea poate fi deasupra setter-ului = injectează bean-ul. Poate fi și în constructor.

Fully autowired - cu stereotipuri: 
  • @Component - echivalentul unui bean la nivel de clasă
  • @Repository
  • @Service (cu sensul că găzduiește business logic)
  • @Controller (pentru creare de servicii web sau microservicii)

@Repository("speakerRepository")
public class HibernateSpeakerRepositoryImpl implements SpeakerRepository {
  . . .
}


@Service("speakerService")
public class SpeakerServiceImpl implements SpeakerService {
  . . .
}


@Configuration
@ComponentScan( {"com.application.path"} )
public class AppConfig {
  // nu mai este nevoie de declarare beans
}

22 noiembrie 2022

Spring 5 Fundamentals - notițe ziua 1

Spring = JEE, POJO based (plain old java object), construit în jurul conceptelor considerate best practice

WORA = write once run anywhere

Spring este folosit pentru a nu mai scrie cod de configurare în aplicație => mai citeț, mai ușor de testat.


Diferențe Spring 5 față de versiuni anterioare:

  • lipsește applicationContext.xml
  • configurări din Java direct în loc de xml-uri


Transformare în proiect Spring:

@Configuration  // înlocuitorul pt applicationContext.xml

public class AppConfig {


  // un bean rămâne „înregistrat” în Spring => este un singleton

  // name e opțional 

  // aplicabil doar la nivel de metodă, nu și de clasă


  @Bean(name = "customerRepository")   

  public CustomerRepository getCustomerRepository() {

    CustomerRepository cust  = new CustomerRepositoryImpl();

    cust.setCustomerAttr(getCustomerAttr());   // setter injection

    return cust;

  }


  @Bean(name = "customerAttr")

  public CustomerAttr getCustomerAttr() {

    return new ... ();

  }

}


public class Application {

  public static void main(String args[]) {

    ApplicationContext appContext = new AnnotationConfigApplicationContext(AppConfig.class);

    CustomerRepository custRepo = appContext.getBean("customerRepository", CustomerRepository.class);

    // do something with custRepo

  }

}


Alternativă la setter injection ----> constructor injection

15 noiembrie 2022

Maven - ziua 2 (finală)

 























Plugins

Goals = plugin-uri configurabile; se pot suprascrie
Exemple: clean, compile, etc

Phases:
  • validate
  • compile
  • test
  • package
  • integration-test nou!
  • verify - verifică integritatea
  • install - instalează pachetul în repo local
  • deploy - copiază pachetul într-un repo remote











JAR plugin - configurat automat ca parte a fazei package, dar se poate suprascrie. Se pot configura atât ce trebuie inclus cât și exclus.













> mvn package   // descarcă tot ce este nevoie în proiect, creează un jar 


Source plugin - parte din package, rulat între fazele install și deploy, împachetează codul sursă















> mvn install  // va crea în /target un project-1.0-SNAPSHOT-sources.jar pe lângă project-1.0-SNAPSHOT.jar deja creat


Javadoc plugin - aproape identic cu source plugin doar că împachetează documentația Java, parte din package, are opțiuni de customizare















> mvn install   // va crea în /target un folder apidocs în care se poate explora javadoc în variantă web (index.html) + project-1.0-SNAPSHOT-javadoc.jar pe lângă project-1.0-SNAPSHOT.jar deja creat

10 noiembrie 2022

Maven class - ziua 1

Introducere

Build tool --> produce un artifact

Maven is built with Maven :)

ANT - construit ca alternativă la Make - nu este rival Maven, se pot folosi împreună


mvn versions:update-properties  - face update la toate dependințele din pom cu ultimele lor versiuni publicate


<build>

  <finalName> GEO </finalName>   <!-- app se va numi GEO.jar -->

  <plugins>

    <plugin>

          ...

    </plugin>

  </plugins>

</build>


> mvn compile --> .class files

> mvn package --> .jar files


Structura Maven

- Maven se uită prestabilit în src/main/java

- compilează in /target

- pom.xml: project info (groupId, artifactId, version, packaging (jar/war)), dependencies (same info), goals, etc

Goals

  • clean
  • compile
  • package (rulează deja compile)
  • install (ruleaza package și instalează jar/war în local repository)
  • deploy (rulează install și copiază rezultatul într-un repo remote)


Maven storage prestabilit: ~/.m2/repository


Dependencies

Dependency: specificare groupId, artifactId, version

SNAPSHOT este versiunea inițială a proiectului în dezvoltare

  - se pot folosi si sufixele M1 (milestone1) sau RC1 (release candidate1) când urmează să fie lansat

  - sufixe RELEASE sau FINAL pt proiectul final


Tipuri de packaging: pom, jar, war, ear, maven-plugin; toate sunt arhive zip la bază; tipul prestabilit este jar

Diferențe între jar, war și ear:

  • create pentru medii diferite
  • la nivel intern: ear trebuie să aibă un META-INF/application.xml , un war cere un WEB-INF/web.xml , iar un jar nu are astfel de cerințe

Pentru tipul de packaging pom: toate dependințele sunt descărcate în arhivă


Dependințe tranzitive: dependințe descărcate automat, de care depind dependințele declarate în proiect


Scope:

  • compile - prestabilit, dependința este disponibilă oriunde în aplicație, propagată în proiectele dependente (tranzitivă)
  • provided - la fel ca compile, dar dependința nu va fi inclusă în artifactul final; disponibilă doar la momentul compilării. Nu este tranzitivă
  • runtime - este nevoie de ea doar la execuție 
  • test (ex. junit)
  • system - deprecated, a nu se folosi! - pt a specifica direct un jar anume din sistem
  • import (...)

27 octombrie 2022

Kotlin - colecții - ziua 7

Colecții

var people: List<Pers?> = listOf(Pers(23), null)
for (person: Pers? in people) {
println(person?.age)
}

val items = IntArray(2)
items[0] = 1
items[1] = 2

val numbers = intArrayOf(1,2,3,4,5)
numbers.forEachIndexed {index, element ->
println("$index is $element")
}


High order functions

= o funcție care ia ca parametru o altă funcție

val action = { println("Hello World") }
// val calc = {x:Int, y:Int -> x*y}
val calc: (Int, Int) -> Int = {x, y -> x*y}
doSomething(action)

fun doSomething(func: () -> Unit) {
func()
}


Inlining 

- ajută la performanță

val ints = listOf(1,2,3,4)
val i = first(ints, { i -> i == 3})
println(i)


inline fun <T> first(items: List<T>, predicate: (T) -> Boolean): T {
for (item in items) {
if (predicate(item)) return item
}
throw Exception()
}

19 octombrie 2022

Kotlin - NULL handling - ziua 6

Java functional interfaces

Ex. Runnable, Callable 


variabila lambda este refolosita la al doilea apel;

variabila lambda nu mai poate fi refolosita la al doilea apel din cauza lui count;


Constructor SAM - pentru dezambiguizare (când compilatorul nu știe să transforme lambda în interfață funcțională)



Constrângeri de nulabilitate

Evitare NPE prin „cod defensiv” --> mult cod în plus

Kotlin:

- tipuri non-nullable

fun closeMeeting(m: Meeting): Boolean { // m: Meeting, deci nu poate fi null
return if (m.canClose()) m.close()
else false
}

fun main(args: Array<String>) {
closeMeeting(
null) // EROARE de COMPILARE
}


- tipuri nullable:  fun closeMeeting(m: Meeting?): Boolean

- safe calls: obj?.method()  === if (obj != null) obj.method()

- operatorul Elvis: newMeeting = m ?: Meeting()   === newMeeting = (m != null) ? m : new Meeting();

- safe cast:  val saveable = obj as? ISaveable    === saveable = obj instanceof ISaveable ? obj : null;

- not-null assertion:  m!!.close()  === assert (m != null) si arunca NPE daca s-a gasit null

- LET: cheama ce e in paranteze doar daca m != null

  m?.let { closeMeeting(m) }

- lateinit: Kotlin nu te lasă să declari o variabilă fără să fie inițializată. Soluții: inițializare cu o valoare default, cu null (și atunci devine nullable), sau cu lateinit (când știu că nu vreau să fie nullable).

  lateinit var address: Address // promisiune compilatorului că voi inițializa variabila


Interacțiune cu Java (adnotări)

public @Nullable String getTitle() {
  return meetingTitle;
}

public void setTitle(@NotNull String title) {
  this.meetingTitle = title;
}

// Kotlin
var title: String? = meeting.getTitle()


Platform type

Când nu există adnotări, compilatorul Kotlin știe că este doar un tip din Java, nu se știe dacă poate fi null sau nu, apare cu semnul exclamării, ex. String! = String sau String?
- dacă Kotlin implementează o interfață din Java unde există return type de tip platform, atunci return type al metodelor implementate poate fi atât nullable cât și non-nullable

15 octombrie 2022

Kotlin - Objects, High level functions & Filtre (ziua 5)

 object

- introduce un singleton (nu există constructor, instanțe)

- poate extinde un Comparator

- adnotare metodă din interiorul obiectului cu @JvmStatic pentru a putea fi chemată din Java

class Course(val id: Int, val title: String) {
}

object Courses {
var allCourses = arrayListOf<Course>()

init {
allCourses.add(Course(1, "Kotlin"))
allCourses.add(Course(2, "Maven"))
}
}

fun enroll(courseName: String){
val course = Courses.allCourses
.filter{it.title == courseName}
.firstOrNull()
}


Companion objects

- keyword: companion objects => Metodele din interiorul obiectului devin statice (factory methods)

open class Student : Person {
  // ....
  companion object : Internship<Student> {
    override fun applyToInternship(title: Student) {
TODO("Not yet implemented")
}

// adding static methods to the class
fun createUndergrad(name: String) = Undergrad(name)
fun createPostgrad(name: String) = Postgrad(name)
}
}

class Undergrad(name: String) : Student(name)

class Postgrad(name: String) : Student(name)

interface Internship<T> {
fun applyToInternship(title: T)
}


fun main(args: Array<String>) {
  Student.createPostgrad("Naim")
  Student.createUndergrad("Amir")
}


High level functions

program.fibonacci(8) { n -> println(n) }

program.fibonacci(8) { println(it) }

program.fibonacci(8, ::println)


Lambda

- pot schimba valori (in Java trebuie să fie final)

var total = 0

program.fibonacci(8) { it -> total += it }


with (student) {

  // asignari pe campurile obiectului student

  name = "Geo"

  city = "Bucharest"

}


student.apply {

  name = "Geo"

  city = "Bucharest"

}


Filter, map, predicate

val ints = listOf(1,2,3,4,5)
val smallInts = ints.filter { it < 4 }
for(i: Int in smallInts) println(i)

val sqInts = ints.map { it*it }
for(i: Int in sqInts) println(i)

val smallSqInts = ints.filter { it < 3 }.map { it*it }
for(i: Int in smallSqInts) println(i)

val largeInts = ints.all { it > 3 }
println(largeInts) // false: not all are grt than 3

val largeIntsAny = ints.any { it > 3 }
println(largeIntsAny) // true: there is one elem grt than 3

val grtThnThree = { v: Int -> v > 3 }
val largeCount = ints.count(grtThnThree)
println(largeCount) // 2

var found :Int? = ints.find(grtThnThree)
println(found) // 4 is the first elem found grt than 3

found = ints.find { it > 5 }
println(found) // null


Secvențe

- folosite atunci când listele create de filter/map ar fi imense

- folosesc evaluare leneșă

- se preferă secvențele în locul listelor

- în Java8, echivalentul este streams

Exemplu:

val titles = meetings.asSequence().filter { ... }.map { ... }

// for (i: String in titles) println(i)

Diferențe

- cu asSequence si fara println (comentat), nu se evalueaza deloc expresia (lazy)

- cu asSequence si println, ordinea este filtru + map + printare element din meetings, deoarece rezultatul este evaluat la cerere, cand este nevoie de el in println

- fara asSequence se evalueaza expresia indiferent daca rezultatul este sau nu folositor; ordinea este: toate filtrele, apoi toate maparile, apoi toate printarile

- cu asSequence operatiile pot fi mai eficiente, in special daca se cere doar primul rezultat (ca exemplu cu find = terminal operator)

06 octombrie 2022

KOTLIN - Clase (ziua 4)

 Interfețe

- public by default

- nu există implements / extends

interface Time {
fun setTime(hrs: Int, mins: Int = 0, secs: Int = 0)
fun setTime(time: String) = setTime(0) // default implementation
}

interface NoTime {
fun setTime(time: String) {}
}

class MyTime : Time, NoTime {
override fun setTime(hrs: Int, mins: Int, secs: Int) {}

override fun setTime(time: String) {
super<Time>.setTime(time)
super<NoTime>.setTime(time)

}
}


Clase

- public, final by default (și metodele sunt final by default)

- dacă vrei să nu fie final - se specifică open

In Java era o practică bună să adaugi final claselor care nu trebuiesc extinse

- suport pt abstract

- clase sigilate (sealed)

- internal: clase vizibile doar în modulul respectiv 

- protected, private; dar nu există package private

open abstract class Person () {
var firstName: String = ""
var lastName: String = ""

open fun getName(): String = "$firstName $lastName" // can be overriden

abstract fun getWork() // can be implemented

fun getVacations() {} // cannot be overriden
}

class Student : Person() {
override fun getName(): String{return ""}
override fun getWork() {
TODO("Not yet implemented")
}
}


Clase sigilate

- ierarhizare, asemănare cu enum

sealed class PersonEvent {
// nested subclasses
class Awake: PersonEvent()
class Asleep: PersonEvent()
class Eating(val food: String): PersonEvent()
}

fun handlePersonEvent(event: PersonEvent) =
when(event) {
is PersonEvent.Awake -> println("Awake")
is PersonEvent.Asleep -> println("Asleep")
is PersonEvent.Eating -> println("Eating ${event.food}")
}


Constructori

open class Person (_fname: String, _lname: String) {
var firstName: String = ""
var lastName: String = ""

init {
this.firstName = _fname
this.lastName = _lname
}

constructor(name: String) : this(name, "")
}


class Student : Person {
var age: Int;
init {
age = 0;
}

constructor(name: String) : super(name)

constructor(first: String, last: String) : super(first, last)

constructor(first: String, last: String, age: Int) : super(first, last) {
this.age = age;
}
}


Data classes

- furnizează metodele toString, equals, hashCode + metoda copy pentru clonare

- sunt clase imutabile

- introdusă prin keywork data class

fun main(args: Array<String>) {
var st1 = Steward(1, "Lina")
var st2 = Steward(1, "Lina")
var st3 = st2.copy(name = "Roberta")
// toate câmpurile la fel mai puțin name

println("Equal? ".plus(st1 == st2)) // true numai dacă există keyword data peste Steward
println(st3) // apelează toString, rezultat citibil față de un Steward@5e2de80c, dacă nu era data
}

data class Steward(val id: Int, val name: String)

30 septembrie 2022

KOTLIN - Funcții (ziua 3)

 Functii

- pot fi standalone (in afara unei clase)

- introduse prin fun

- pot avea parametri by default

- pot extinde tipuri deja existente

- pot fi chemate din Java (import pachetul de kotlin si chemare ca functie statica)

  @file:JvmName("DisplayFunctions") // redenumire oficiala a clasei in Kotlin, pt a putea chema din Java:

  DisplayFunctions.display("ce vrei tu");


fun max(a: Int, b: Int) : Int = if (a > b) a else b // function expression
println(max(1,2))


Parametri default

@JvmOverloads // ca sa poata fi chemata din Java cu sau fara parametrul optional
// Java va crea o metoda cu un singur parametru & una cu 2 parametri
fun log(message: String, logLevel: Int = 1) {
println("$message | $logLevel")
}
log("Salut")


Denumirea parametrilor  (Java nu suporta)

- pentru a ii putea da in orice ordine si ajuta la dezambiguizare atunci cand exista mai multi parametri optionali

log(logLevel = 2, message = "Salut")


Functii care extind

Idee: adăugare funcții la clase existente -> devin funcții statice; util pentru funcții utilitare de moment.

println("Salux Pexri".replaceX())
fun String.replaceX(): String { // extinde in clasa String
return this.replace("x", "t")
}


Funcții INFIX

- prefixate cu infix, au un singur parametru

class Header(var name: String) {}

infix fun Header.plus(other: Header): Header {
return Header(this.name + " " + other.name)
}
var h1 = Header("Petri")
var h2 = Header("Mimi")
val h3 = h1 plus h2

println(h3.name) // Petri Mimi


Operator overloading

operator infix fun Header.plus(other: Header): Header {
return Header(this.name + " " + other.name)
}
val h4 = h1 + h2


Funcții foarte recursive

tailrec - cuvânt-cheie pus înainte de fun atunci când știm că vor avea loc prea multe apeluri recursive, iar Kotlin le va transforma intern într-o buclă; pentru evitarea stack overflow

29 septembrie 2022

KOTLIN - ziua 2

Fisier kt -> .class file

Rulare:

> java -cp ...\kotlin-runtime.jar MainKt 

Alta optiune: export jar

> java -jar MainKt.jar


Mai putina "ceremonie":

- poti defini clase oriunde, nu trebuie sa fie in fisier separat


STRINGS

- string interpolation: 

  println("Display $name")

  println("Display $(obj.name)")

- string comparison: if (str1 == str2)

- nullable vs non-nullable

  var answer: String// non-nullable

  var answer: String?// nullable

- string comparison with null check: if (str1?.prop == str2?.prop) // compara doar daca nu sunt nule


IF este o expresie care returneaza o valoare:

var message = if (str1 == str2) { "egal" } else { "gresit" } 


WHEN - asemanator cu switch

 when (str1) {

  "25" -> print("Corect")

  else -> print("Gresit")

}


TRY - CATCH

val num: Int = try {
Integer.parseInt("20s")
} catch (e: NumberFormatException) {
-1
}
finally {
}


Iteratii - WHILE, FOR

var range = 1..10 // inclusive
// poate fi si range = 'a'..'z' --- orice care implementeaza interfata Comparable

for (i in range step 3) {
println(i)
}
for (i in 10 downTo 1 step 4) {
println(i)
}
for (i in 1 until 10) { // non-inclusive
println(i)
}


LISTE

var nums = listOf(11,22,33)
for (i in nums) {
println(i)
}
for ((index, element) in nums.withIndex()) {
println("$element at index $index")
}


MAPS

var ages = TreeMap<String, Int>()
ages["Geo"] = 33
ages["Petri"] = 7
for ((name, age) in ages) {
println("$name's age is $age")
}

22 septembrie 2022

KOTLIN - ziua 1

KOTLIN este un limbaj OOP simplificat (cu mai puține linii de cod), care acomodează mai bine decât Java paradigma funcțională (fiind chiar limbaj funcțional) și care rulează pe JVM. Considerat o îmbunătățire a Javei.

> kotlinc hello.kt

Creează un fișier .class

> kotlinc hello.kt -include-runtime -d hello.jar

> java -jar hello.jar

Creează un jar și rulează java


var (înaintea declarării unei variabile) vs val (declară variabila immutable)

public este implicit în Kotlin

void este Unit


fun main (args: Array<String>) {
println("Hello world")

val geo = Person("Georgiana")

geo.display1()
geo.display2(::displayHelper)
}

fun displayHelper(name: String) {
println("Bravo $name")
}

class Person (var name: String) {
fun display1() {
println("Display $name")
}

fun display2 (func: (s:String) -> Unit) {
func(
name)
}
}

16 septembrie 2022

javax.validation

Un tutorial util: Spring MVC Custom Validation

Pont: se va adnota cu @Valid fiecare obiect care trebuie verificat (inclusiv in cascada, mergand pana la obiectul final ce contine adnotarea cu constrangere - cum era @ContactNumberConstraint)

--------------------------------

package secret***.controller;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class RandomValidator implements ConstraintValidator<RandomConstraint, String> {

@Override
public void initialize(RandomConstraint contactNumber) {
}

@Override
public boolean isValid(String value, ConstraintValidatorContext cxt) {
return value != null && value.matches("[0-9]+")
&& (value.length() > 8) && (value.length() < 14);
}
}
--------------------------
package secret***.controller;

import java.lang.annotation.*;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = RandomValidator.class)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RandomConstraint {
String message() default "Invalid phone number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
--------------------------
@PostMapping("/save")
public ResponseEntity<VrDeResultDTO> save(@RequestBody @Valid ContextDTO contextDTO) {
return new ResponseEntity<>(choreographer.save(contextDTO), HttpStatus.OK);
}
--------------------------
in ContextDTO ---> toate campurile care duc la campul adnotat cu @RandomConstraint trebuie sa aiba @Valid.