Funcționalități din C# pe care aș vrea să le am în Java

Puteam să jur că am apăsat Publish 🙃

Și în nicio ordine anume

  • Nullable Reference Types – tip de dată referință care poate fi null (în anumite situații este acceptabil). În Java nu știu să existe așa ceva, cu toate că a apărut Helpfull NullPointerExceptions care oferă un mesaj mai clar asupra câmpului sau metodei care întoarce null
    Exception in thread "main" java.lang.NullPointerException: 
      Cannot invoke "String.toLowerCase()" because the return value of 
    "com.baeldung.java14.npe.HelpfulNullPointerException$PersonalDetails.getEmailAddress()" is null
      at com.baeldung.java14.npe.HelpfulNullPointerException.main(HelpfulNullPointerException.java:10)

     

  • Null-Conditional Operator(?. ) – prezent de vreo 5 ani și recent adăugat în JavaScript. Java a rămas în urmă, deși au fost discuții.  Alături l-aș include și pe null coalescing operator (??)
  • Expression-bodied members – la stadiul de discuție
  • Interpolare de string-uri – adio `String.format()` 🙂 Cel puțin pentru o treabă simplă. Totuși, Java 13 a introdus Text Blocks și în sfârșit se poate scrie un query SQL sau json fară a concatena sau a escapa 😁

Aș fi vrut sa menționez și var, dar intre timp au apărut 7 versiuni de Java în 3 ani și ceva. În acești ani, limbajul a evoluat și a mai redus din verbozitate (nu există cred acest cuvânt în limba română).

Acum, ce-i mai sus este ce mi-ar fi mie mai util in munca mea de zi cu zi. Pentru unii, Kotlin este raspunsul la cerințele de mai sus, dar nu (cred că) toată lumea vrea să schimbe limbajul pentru 3, 4 lucruri care cresc productivitatea. 🙂

Ar mai fi câteva proiecte de interes, dar momentan sunt în lucru.

În concluzie, de data aceasta, am apăsat butonul de Publish


Jur de roșu că nu este rant!

Extremely minimal Windows dev setup

From time to time, my auntie asks me to go to her flat and look after the kitty and usually I don’t take my laptop. I want to be able to write some code using her laptop in the fastest way.

After experimenting with multiple set-ups like XAMPP or any programming language + a database, I found out that the fastest setup is drum roll….

NodeJS (Javascript) + Visual Studio Code. Plus a few clicks on Next buttons 🙂

Seriously !

The installation of Node and VS Code took under 10 minutes and a short restart for updating the path and I was ready to go. At least for console applications, but this setup should be ok for web apps. Also, a database like PostgreSQL or MySql can be installed for persistence.

Swift pe Windows

Deși este disponibil de ceva vreme pe Windows, eu azi am observat că se poate instala frumos și în stiulul clasic cu next>next. 🙂 Bine, nu este încă de producție, dar este un început.

Nu am făcut nimic mai mult, decât să urmez pașii de aici și gata. Instalarea a decurs fără probleme și nici nu a durat prea mult. Deși aș fi vrut să nu am nevoie de Visual Studio plus 5 GB(SDK-ul Windows 10 plus altele) doar ca să rulez un Hello Wrold, dar heyy 😀. Nu uita de Python, in special versiunea 3.9, că astfel nu vei putea folosi interpretorul REPL. Nu dă eroare, dar nici nu zice ceva.

Mediul REPL se poate accesa prin comanda swift și în acest mod, poți să experimentezi limbajul făra niciun IDE , editor de text etc. Am văzut că este o extensie de VSCode care aduce suportul în editor, dar este încă în dezvoltare și eu nu am reușit să o instalez.

Ecosistemul este aproape inexistent pentru Windows, dar mai așteptăm. Din ce am văzut, vine insă la pachet cu wrapper peste Win32, deci pe viitor, poate se pot face aplicații desktop based in Swift. Cineva a făcut și un framework pentru acest lucru, dar cu limitările specifice.

Nu mă aștept că voi putea scrie aplicații pentru iOS și Mac pe Windows, tho’. Dar am văzut că există un framework pentru aplicații web, Vapor. Nu are suport pentru Windows, dar este disponibil pe Linux.

 

 

 

 

JAXB și timestamp-uri care nu pot fi citite

Am observat anumite formate de dată și timp care nu pot fi citite corecte cu api-ul JAXB din Java. Mai bine spus, nu pot fi citite, adică acel câmp mapat în clasa din aplicație  este null.

Un exemplu de format de dată și timp cu timezone ar fi acesta 2020-10-13T12:25:00+0200.

In aplicație, campul aferent timestamp-ului are ca tip de data XMLGregorianCalendar, o clasă destul de veche folosită pentru a reprezenta timestamp-uri. Clasă veche și un format de timp mai deosebit din punct de vedere al timezone-ului nu fac casă bună și când am pornit testul pentru a vedea dacă se poate citi acel fișier, a ieșit o foarte frumoasă exceție NullPointerException.

Soluția cea mai la îndemană a fost să înlocuiesc XMLGregorianCalendar cu String și astfel citirea se face corect, eventualele erori, cum ar fi lipsa timestamp-ului sau invaliditatea lui, rămânând de tratat la un nivel mai sus, al aplicației.

O altă soluție ar mai fi screrea unui XmlAdapter custom care poate fi folosit pentru a citi corect acel câmp de dată din fișier.

Un exemplu, în cazul problemei de față ar fi acesta:

package com.mycompany.app;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
public class DateTimeAdapter extends XmlAdapter<String, XMLGregorianCalendar> {
/**
* Convert a value type to a bound type.
*
* @param v The value to be converted. Can be null.
* @throws Exception if there's an error during the conversion. The caller is responsible for
* reporting the error to the user through {@link ValidationEventHandler}.
*/
@Override
public XMLGregorianCalendar unmarshal(String v) throws Exception {
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse(v);
GregorianCalendar c = new GregorianCalendar();
c.setTime(date);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
return date2;
}
/**
* Convert a bound type to a value type.
*
* @param v The value to be convereted. Can be null.
* @throws Exception if there's an error during the conversion. The caller is responsible for
* reporting the error to the user through {@link ValidationEventHandler}.
*/
@Override
public String marshal(XMLGregorianCalendar v) throws Exception {
return null;
}
}

view raw
DateTimeAdapter.java
hosted with ❤ by GitHub

Și se folosește ca adnotare pe campul respectiv din clasă

@XmlJavaTypeAdapter(DateTimeAdapter.class)
protected XMLGregorianCalendar timestamp;

 

 

 

 

 

Deserializarea răspunsului Json de la un API folosind Java records

Deși aveam în plan să scriu despre ele, dar având în vedere că au trecut vreo 4 luni și ceva decând au apărut și nu am ce să aduc nou, m-am gândit să vad cum se descurcă cu una din cele mai comune lucruri într-o aplicație, deserializarea unui răspuns json.

Ca API vom folosi unul dummy care va returna o lista de ToDo-uri cu true sau false, în funcție dacă au fost efectuate sau nu și le vom agrega după acestă condiție.

Primul lucru este să creăm un record care să aibă câmpurile json-ului din răspuns.

{
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
  }

Deci record-ul va avea un userId și un id de tip int, precum un câmp title de tip string si un completed boolean.

record Todo(
            @JsonProperty("userId")
            int userId,

            @JsonProperty("id")
            int id,

            @JsonProperty("title")
            String title,

            @JsonProperty("completed")
            boolean completed) {}

Întrucât folosim Jackson pentru deserializare și record-urile fiind o funcționalitate în preview, va fi nevoie să specificam că acele câmpuri sunt chiar cele din json. Fără ele, Jackosn va arunca o exceptie:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException

Cu record-ul creat după strucutura json-ului, este nevoie să facem call-ul la api, folosind clinetul http.

String DATA_URL = "https://jsonplaceholder.typicode.com/todos";
var httpClient = HttpClient.newHttpClient();
var httpRequest = HttpRequest.newBuilder()
        .uri(URI.create(DATA_URL))
        .build();
var httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

var body = httpResponse.body();

Codul este simplu, nu are nimic special. Întrucât este un raspuns de tip text, sunt interesat să îl primesc așa cum este și îl pun într-o variabilă

Urmează etapa de deserializare și agregare

var mapper = new ObjectMapper();
        Todo[] todos = mapper.readValue(body, Todo[].class); //because in json representation, there is  an array of todos
        //System.out.println(todos[1].title());

         var doneTodos = Arrays.stream(todos)
                .filter(Todo::completed)
                .count();

         System.out.println("Completed: " + doneTodos);
         System.out.println("Not completed: " + (todos.length - doneTodos));

Avem un array de todo-uri,  lucru pe care trebuie sa il specificam metodei readValue(), împreună cu ceea ce vrem să deserializăm, în cazul nostru, variabila body, mai precis, conținutul ei.

Urmează o simplă filtrare dupa todo-urile completed. Aici se vede unul din avantajele de a folosi record-uri. Avem acces la propietați, exect ca la clase cu getteri și setteri, dar în cazul record-urilor sunt generate de compilator. Plus altele.

Marele final reprezinta afișarea la consolă 🙂

Ca pe final de articol, adaugarea lor în Java este binevenită și va reduce mult zgomotul de cod. Codul complet:

package com.company;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
// write your code here
String DATA_URL = "https://jsonplaceholder.typicode.com/todos";
var httpClient = HttpClient.newHttpClient();
var httpRequest = HttpRequest.newBuilder()
.uri(URI.create(DATA_URL))
.build();
var httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
var body = httpResponse.body();
var mapper = new ObjectMapper();
Todo[] todos = mapper.readValue(body, Todo[].class); //because in json representation in an array of todos
//System.out.println(todos[1].title());
var doneTodos = Arrays.stream(todos)
.filter(Todo::completed)
.count();
System.out.println("Completed: " + doneTodos);
System.out.println("Not completed: " + (todos.length doneTodos));
}
}
//https://angiejones.tech/deserializing-api-responses-into-java-records
record Todo(
@JsonProperty("userId")
int userId,
@JsonProperty("id")
int id,
@JsonProperty("title")
String title,
@JsonProperty("completed")
boolean completed) {}

PS: Vom avea record-uri și in C# la versiunea 9.

 

 

Noutăți Microsoft Build 2020

Datorită situației mai speciale, conferința s-a ținut online. Printre tot felul de sesiuni, care mai de care, s-au anunțat câteva lucruri interesante.

  • PowerToys – utilitare de sistem pentru utilizatorii mai profi. Era disponibil si inainte de conferinta, dar acum a capatat mai multe optiuni plus o interfață mai bogată. Un fel de Spotlight in variantă de Windows. Am instalat noua versiune, dar trebuie să ma mai joc cu aplicația. Multe opțiuni de explorat și încercat 🙂 Se poate descărca de aici.
  • Windows Terminal a ajuns la versiunea 1.0. Anunțat anul trecut, este un terminal mai capabil fata de CMD. În plus integreaza și CMD și PowerShell și unul pentru Azure. Acesta versiune vine cu accelerare GPU pentru randarea de text, tot felul de opțiuni de personalizare, tabs and panes(nu am idee cum aș putea să traduc ca să nu sune stupid)
  • Versiunea 9 a limbajului C#. în special records(aici Java a luat-o înainte 😁). În afară de records, mai prezintă interes și un pattern matching mai îmbunătățit.
  • Windows Package Manager – un manager de pachete(în sfârșit!!!)  pentru Windows. Foarte util, în special pentru insalarea unor utilitare din lumea Linux și nu numai. Momentan este in preview

Pe lânga cele de mai sus, mai sunt multe altele din toate domeniile, machine learning, c++ tooling, dar astea nu pot spune că mă interesează așa mult. Dar nici nu lucrez cu ele.

Oh Microsoft!

What a great times to be alive 🙂

 

 

Link-uri de răsfoit pe timp de ploaie

La mine plouă :/

Astea fiind zise și fără nicio ordine a preferinței:

Cam atât pentru moment.

Am actualizat la PHP 7.4

A mers mai smooth decât mă  aștepatm! 🙂

Am instalat toate extensiile necesare pe care trebuie să le aibă PHP-ul ca WordPresul să funcționeze corect, dar pentru versiunea 7.4. Care erau aceleași ca cele pentru PHP 7.2, versiunea cu care am instalat blogul.

Poți să le vezi cu următoarea comandă:

apt list --installed | grep php7.x

Unde x reprezintă numărul versiunii. Valabil și pentru output-ul comenzii.

Și primești acest rezultat:

libapache2-mod-php7.2/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed,automatic]
php7.2/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 all [installed]
php7.2-cli/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed,automatic]
php7.2-common/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed,automatic]
php7.2-curl/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]
php7.2-dev/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]
php7.2-gd/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]
php7.2-json/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed,automatic]
php7.2-mbstring/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]
php7.2-mysql/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]
php7.2-opcache/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed,automatic]
php7.2-readline/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed,automatic]
php7.2-xml/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]
php7.2-xmlrpc/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]
php7.2-zip/bionic,now 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 amd64 [installed]

Și cu apt install php7.4-nume_extensie le instalezi. Se poate folosi tasta Tab pentru completarea automată a numelui.

După ce au fost instalate, trebuie să îi spui server-ului Apache, ce versiune de handler pentru PHP să folosească. Înainte era cel pentru vechea versiune de PHP, care acum trebuie dezactivat.

a2dismod php7.2 //dezactivare handler
systemctl restart apache2 //restart server
a2enmod php7.4 //activare handlerphp 7.4

Bineînteles că eu am procedat fix invers, dar dupa ce am dezactivat handler-ul pentru 7.2, cel de 7.4 a intrat automat.

Cam aceste lucruri le-am facut și până acum nu s-a stricat nimic. Încă nu m-am uitat in log-uri. 🙂

PS: Să faci un back-up înainte de actualizare! 😁

Corona tracker – tracking the virus

De vreo 2 săptămâni, meșteresc la o aplicație de vizualizare a evoluției cazurilor de COVID19 în lume și în țară. Față de altele, este mai simplistă, dar pentru mine este un exercițiu de a prezenta datele într-o manieră ușor de înțeles de către toată lumea și de a experimenta diferite concepte de programare.

Stack-ul folosit cuprinde Java, Spring Boot și o bază de date MySQL, pe backend, iar pe frontend Bootstrap pentru layout, DataTables pentru tabelele din aplicație și HighCharts pentru chart-ul cu evoluția globală a cazurilor. Datele pentru chart sunt stocate în baza de date.

Sursele de date folosite sunt:

* CSV-ul cu situația la nivel global. Mai multe informații precum și alte csv-uri cu diferite agregări de date aici

  • Pentru satisticile cu evoluția în țară, am folosit api-ul pus la dispoziție de comuitatea geo-spațial.org

Aplicația este open source și codul poate fi văzut aici, iar acesta este live aici.

Alte proiecte similare

 

Java 13 si reducerea verbozității

Puteam să jur că am apăsat pe butounul de Publish din editor. 👴

La momentul în care am început să scriu articolul, Java 13 nu era in stadiul de GA, dar acum mai sunt 5 zile si și apare Java 14. 😀

Două noi funcționalități vor contribui la reducerea verbozității in baza de cod a aplicațiilor.

 

 Text blocks sau multi line strings sau raw strings

Un feture bine venit. Pe scurt:

String html = """
               <html>
                   <body>
                       <p>Hello, World</p>
                   </body>
               </html>
       """;

String json = """
               {
                   "name":"mkyong",
                   "age":38
               }
               """;

Sintaxa este asemănatoare, dacă nu identică cu ce este in Kotlin și Python. Încă nu există conceptul de string interpolation ca în C# sau Javascript, darrrrr este binevenit și acest lucru. Văd utilitatea acestei construcții în query-urile sql complexe. Dacă mai intră în joc și parametrii, se poate folosi String#format

var query = String.format("""
        select * from table where name = %s
        """, name);

var query1 = """
select * from table where name = %s"""
        .formatted(Main.class.getName());//deprecated method

System.out.println(query);
System.out.println(query1);

Rezultatul este următorul:

select * from table where name = cosmin

select * from table where name = com.company.Main

Mai multe lucruri despre aceast feature si o analiză mai detaliată, in acest link

 

Switch expressions

Sunt multe de discutat despre acest lucru, alții au făcut-o mai bine si mai în detaliu. Eu mă voi rezuma la un exemplu de cod scurt și la obiect

    static void howMany(int k) {
        System.out.println(
                switch (k) {
                    case  1 -> join("-", "java", "javascript", "C#"); // a complicated expression :D
                    case  2 -> "two" ;
                    default -> "many";
                }
        );
    }
// howMany(1) = java-javascript-C#

Sigur, nu recomand acel mod de screre al codului 😀

 

In loc de concluzie

Cam atât din partea mea!

Cel putin pe partea de scriere de cod.

De asemenea, las câteva link-uri cu mai multe detalii despre ce am scris mai sus, precum si alte functionalități introduse in limbaj

  1. https://blog.codefx.org/java/java-13-guide/
  2. https://mkyong.com/java/what-is-new-in-java-13/
  3. https://openjdk.java.net/projects/jdk/13/
  4. https://www.baeldung.com/java-pattern-matching-instanceof
  5. https://blog.codefx.org/java/enable-preview-language-features/
  6. https://vladmihalcea.com/multiline-string-java-text-blocks/