Source code of my website
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

🚚 : reorganize draft posts

+351 -1
+2 -1
content/posts/2025-05-30-java-logging/index.md content/posts/drafts/2025-05-30-java-logging/index.md
··· 4 4 title: Introduction au logging en Java 5 5 series: Logging en Java 6 6 tags: 7 - - Java 7 + - java 8 + - observability 8 9 draft: true 9 10 --- 10 11
+65
content/posts/drafts/2025-02-13-pact/index.md
··· 1 + --- 2 + date: "2025-02-13" 3 + language: fr 4 + tags: 5 + - java 6 + title: Contract Testing avec Pact 7 + draft: true 8 + --- 9 + 10 + ## Instanciation d'un broker 11 + 12 + Un broker se démarre facilement avec Docker. 13 + 14 + Le broker nécessite une base de données PostgreSQL pour pouvoir fonctionner. 15 + 16 + Pour démarrer rapidement, un fichier `docker-compose.yml` est mis à disposition sur le GitHub de [pact-broker-docker](https://github.com/pact-foundation/pact-broker-docker/blob/master/docker-compose.yml). 17 + 18 + J'en ai produit une version simplifiée, qui démarre une base de données, et une instance d'un pact-broker : 19 + 20 + ```yaml 21 + services: 22 + pactbroker-db: 23 + image: postgres 24 + environment: 25 + - POSTGRES_USER=pactbrokeruser 26 + - POSTGRES_PASSWORD=PactPassword 27 + - POSTGRES_DB=pact 28 + healthcheck: 29 + test: [ "CMD-SHELL", "pg_isready -U pactbrokeruser -d pact" ] 30 + interval: 10s 31 + timeout: 5s 32 + retries: 5 33 + 34 + pactbroker: 35 + image: pactfoundation/pact-broker:2 36 + environment: 37 + PACT_BROKER_DATABASE_USERNAME: pactbrokeruser 38 + PACT_BROKER_DATABASE_PASSWORD: PactPassword 39 + PACT_BROKER_DATABASE_HOST: pactbroker-db 40 + PACT_BROKER_DATABASE_NAME: pact 41 + PACT_BROKER_DATABASE_CONNECT_MAX_RETRIES: 5 42 + ports: 43 + - "9292:9292" 44 + depends_on: 45 + - pactbroker-db 46 + ``` 47 + 48 + Une fois le broker démarré, il est disponible à l'URL http://localhost:8080, et il est chargé avec des données de test : 49 + 50 + ![pact-broker-init](pact-broker-init.png) 51 + 52 + ## Instanciation d'un _consumer_ 53 + 54 + Le _consumer_ est le composant effectuant les appels. 55 + 56 + Pour créer le _consumer contract_, on passe par l'écriture de tests unitaires, qui seront exécutés sur un mock de serveur. 57 + 58 + Voici un exemple 59 + 60 + ## Liens et références 61 + 62 + * Documentation de [pact](https://docs.pact.io/) : 63 + 64 + * pact-broker-docker : 65 + * GitHub : https://github.com/pact-foundation/pact-broker-docker
content/posts/drafts/2025-02-13-pact/pact-broker-init.png

This is a binary file and will not be displayed.

+111
content/posts/drafts/2025-07-03-spring-security-oauth2-client/index.md
··· 1 + --- 2 + date: 2025-07-03 3 + language: fr 4 + title: Spring Security & OAuth 2 - Client 5 + tags: 6 + - java 7 + - spring-boot 8 + draft: true 9 + lastmod: 2025-11-14 10 + --- 11 + 12 + Pour les devs Java, Spring Security et OAuth2, ça reste souvent mal connu et mal maîtrisé. 13 + 14 + Le but de cet article est simple : démystifier la configuration de Spring Security pour les applications utilisant OAuth 2 pour l'authentification. 15 + 16 + Dans cet article, nous allons voir le premier côté du miroir : la partie cliente, appel d'un service sécurisé en Oauth2. 17 + La partie serveur, exposition d'un service avec OAuth2, sera décrite dans un second article. 18 + 19 + ## Côté client 20 + 21 + Le côté client consiste à pouvoir appeler un serveur sécurisé avec OAuth 2, depuis une application Spring Boot. 22 + 23 + Voici un diagramme qui illustre les interactions entre les différents acteurs dans le flow OAuth2 `client_credentials` : 24 + 25 + ```mermaid 26 + sequenceDiagram 27 + participant Client as Application Java Cliente 28 + participant Auth as Serveur d'Authentification 29 + participant Server as Application Java Serveur 30 + 31 + Client->>Auth: 1. Demande de token (client_id, client_secret) 32 + Note over Client,Auth: POST /oauth/token<br/>grant_type=client_credentials 33 + Auth->>Client: 2. Retourne un access_token JWT 34 + Note over Auth,Client: {"access_token": "eyJhbGci...", "expires_in": 3600, ...} 35 + 36 + Client->>Server: 3. Requête API avec Authorization: Bearer {token} 37 + Note over Client,Server: GET /api/resource<br/>Authorization: Bearer eyJhbGci... 38 + Server->>Server: 4. Vérifie la validité du token 39 + Server->>Client: 5. Réponse API 40 + ``` 41 + 42 + Cela consiste le plus souvent à récupérer un token _JWT_ auprès d'un serveur d'authentification, puis de transmettre ce token dans un header de requête HTTP. 43 + 44 + Bien que cela semble simple en surface, la récupération du token _JWT_ peut être compliquée à implémenter proprement. Il faut gérer les différents flows existants, l'expiration du token, la gestion du _refresh token_, les scopes etc. 45 + En fonction des implémentations et des configurations de serveurs d'authentification, la requête à envoyer pour récupérer le token peut aussi être différente. 46 + 47 + Spring Security Oauth2 Client implémente la récupération d'un token OAuth2 côté client, ainsi que sa gestion, son stockage (en cache ou en base de données), et fournit un moyen pratique de pouvoir injecter le token dans des requêtes HTTP avec le RestClient. 48 + 49 + ### Les librairies nécessaires 50 + 51 + Pour le côté client, il faut : 52 + 53 + * `org.springframework.boot:spring-boot-starter-oauth2-client` : implémente la récupération d'un token OAuth2 côté client. 54 + 55 + ### Les classes intéressantes 56 + 57 + OAuth2ClientHttpRequestInterceptor : 58 + 59 + Cette classe permet d'intercepter les requêtes émises par un `RestClient` ou un `RestTemplate`. Lors de l'interception, l'authentification est effectuée si besoin (si le token n'a pas expiré), et le token est automatiquement ajouté au header `Bearer` de la requête sortante. 60 + 61 + ### L'auto configuration avec Spring Boot 62 + 63 + ```yaml 64 + spring: 65 + security: 66 + oauth2: 67 + client: 68 + registration: 69 + your-registration-id: 70 + client-id: your-client-id 71 + client-secret: your-client-secret 72 + authorization-grant-type: client_credentials 73 + client-authentication-method: client_secret_post 74 + scope: read,write 75 + provider: your-registration-id 76 + provider: 77 + your-registration-id: 78 + token-uri: https://auth.example.com/oauth/token 79 + user-info-authentication-method: header 80 + ``` 81 + 82 + La configuration d'un `RestClient` se fait alors de cette manière : 83 + 84 + ```java 85 + var interceptor = new OAuth2ClientHttpRequestInterceptor(authorizedClientManager); 86 + var restClient = RestClient.builder() 87 + .baseUrl(apiUrl) 88 + .requestInterceptor(interceptor) 89 + .build(); 90 + ``` 91 + 92 + Le code *magique* dans l'interceptor est la méthode `authorizeClient`, qui récupère 93 + 94 + ```java 95 + private void authorizeClient(HttpRequest request, Authentication principal) { 96 + String clientRegistrationId = this.clientRegistrationIdResolver.resolve(request); 97 + if (clientRegistrationId == null) { 98 + return; 99 + } 100 + 101 + OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(clientRegistrationId) 102 + .principal(principal) 103 + .build(); 104 + OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest); 105 + if (authorizedClient != null) { 106 + request.getHeaders().setBearerAuth(authorizedClient.getAccessToken().getTokenValue()); 107 + } 108 + } 109 + ``` 110 + 111 + La magie opère sur les dernières lignes. L'intercepteur demande à l'`authorizedClientManager` d'authentifier le `principal` avec la client registration, récupère un `authorizedClient`, et attache l'access token de ce client au header `Authorization: Bearer` de la requête HTTP.
content/posts/drafts/2025-11-06-la-magie-de-jcmd/cover.jpg

This is a binary file and will not be displayed.

+150
content/posts/drafts/2025-11-06-la-magie-de-jcmd/index.md
··· 1 + --- 2 + date: 2025-10-31 3 + language: fr 4 + title: "Abracajava : La magie de `jcmd`" 5 + tags: 6 + - java 7 + - tools 8 + draft: true 9 + lastmod: 2025-11-14 10 + --- 11 + 12 + [//]: # (TODO intro) 13 + 14 + Cet article présente `jcmd`, quelques cas d'usage bien pratiques, pour comprendre le comportement d'une JVM en prod. 15 + 16 + # `jcmd` 17 + 18 + `jcmd` est l'un des binaires fournis avec les différentes distributions de JDK. Il existe depuis au moins la version 7 du JDK. 19 + 20 + Il est inclus par défaut dans les JDK Eclipse Temurin, OpenJDK et GraalVM. 21 + 22 + Attention, il n'est pas forcément inclus dans les JRE, donc pensez à vérifier s'il est bien présent dans votre version de Java. 23 + 24 + Il permet d'exécuter des commandes de diagnostic sur une JVM _en cours d'exécution_. 25 + C'est donc un outil bien pratique pour débugger une JVM qui tourne dans un container par exemple. 26 + 27 + Certaines de ces commandes ont un impact sur l'application. Il est par exemple possible de forcer l'exécution d'un _Garbage Collector_, ou d'extraire un _Heap Dump_. 28 + 29 + Les commandes disponibles évoluent avec les différentes versions de Java. 30 + 31 + Je liste ici les plus pratiques pour diagnostiquer une application. 32 + 33 + # Exécuter `jcmd` 34 + 35 + `jcmd` vient avec une aide en ligne de commande très minimale, si on lui passe le paramètre `--help` : 36 + 37 + ```shell 38 + $ jcmd --help 39 + Usage: jcmd <pid | main class> <command ...|PerfCounter.print|-f file> 40 + or: jcmd -l 41 + or: jcmd -h 42 + 43 + command must be a valid jcmd command for the selected jvm. 44 + Use the command "help" to see which commands are available. 45 + If the pid is 0, commands will be sent to all Java processes. 46 + The main class argument will be used to match (either partially 47 + or fully) the class used to start Java. 48 + If no options are given, lists Java processes (same as -l). 49 + 50 + PerfCounter.print display the counters exposed by this process 51 + -f read and execute commands from the file 52 + -l list JVM processes on the local machine 53 + -? -h --help print this help message 54 + ``` 55 + 56 + Lorsqu'on exécute `jcmd` sans paramètre, il liste l'ensemble des JVM en cours d'exécution, ainsi que leur PID (_Process ID_) sur le système d'exploitation. 57 + Cette exécution est alors très similaire à ce que l'on peut faire avec `jps`. 58 + On obtient le même résultat en exécutant `jcmd` avec le paramètre `-l` (pour _list_) : 59 + 60 + ```shell 61 + $ jcmd 62 + 308099 jdk.jcmd/sun.tools.jcmd.JCmd 63 + 2909 fr.univ_lille.gitlab.classrooms.GitlabClassroomsApplication 64 + 65 + $ jps 66 + 308100 Jps 67 + 2909 GitlabClassroomsApplication 68 + ``` 69 + 70 + On observe que `jcmd` et `jps` s'auto-découvrent (comme le fait la commande `ps` d'ailleurs). 71 + 72 + À noter que `jcmd` ne liste pas les process qui tournent dans des containers séparés. Il faut donc parfois utiliser `jcmd` directement dans les containers (ce qui est mon _use-case_ principal). 73 + 74 + Une fois qu'on a identifié le PID de la JVM concernée (2909 dans mon exemple), on peut invoquer la sous-commande `help` pour obtenir la liste des commandes disponibles d'une JVM 75 + (j'ai tronqué le résultat par souci de lisibilité) : 76 + 77 + ```shell 78 + $ jcmd 2909 help 79 + 2909: 80 + The following commands are available: 81 + Compiler.CodeHeap_Analytics 82 + Compiler.codecache 83 + [...] 84 + VM.uptime 85 + VM.version 86 + help 87 + 88 + For more information about a specific command use 'help <command>'. 89 + ``` 90 + 91 + Et de la même manière, on peut alors récupérer l'aide d'une sous-commande particulière. 92 + Un premier exemple avec la commande `VM.uptime` : 93 + 94 + ```shell 95 + $ jcmd 2909 help VM.uptime 96 + 2909: 97 + VM.uptime 98 + Print VM uptime. 99 + 100 + Impact: Low 101 + 102 + Syntax : VM.uptime [options] 103 + 104 + Options: (options must be specified using the <key> or <key>=<value> syntax) 105 + -date : [optional] Add a prefix with current date (BOOLEAN, false) 106 + ``` 107 + 108 + Et un autre exemple avec la commande `VM.flags` : 109 + ```shell 110 + $ jcmd 2909 help VM.flags 111 + 2909: 112 + VM.flags 113 + Print VM flag options and their current values. 114 + 115 + Impact: Low 116 + 117 + Syntax : VM.flags [options] 118 + 119 + Options: (options must be specified using the <key> or <key>=<value> syntax) 120 + -all : [optional] Print all flags supported by the VM (BOOLEAN, false) 121 + ``` 122 + 123 + En plus de la description de la commande et de ses options supportées, `jcmd` indique l'impact de l'exécution de la commande sur la JVM. 124 + L'impact est classé en 3 niveaux : 125 + 126 + * _Low_, avec potentiellement la mention _no impact_ : ces commandes ont donc un impact réduit sur la JVM. Il s'agit principalement des commandes qui listent les paramètres ou activent des options. À utiliser sans modération ; 127 + * _Medium_, avec parfois une indication de ce qui fait varier cet impact, comme _depends on number of threads_ ou _depends on number of classes_. Utiliser ces commandes sur une JVM en production est donc acceptable et sera le plus souvent invisible ; 128 + * _High_, avec souvent l'indication _depends on heap size_. Utiliser ces commandes occasionnera un impact fort sur les performances de la JVM et le code en cours d'exécution, potentiellement même une pause dans l'exécution pour l'exécution d'un _garbage collector_ ou la création d'un _heap dump_. 129 + 130 + > On retrouve tous ces éléments dans la doc de `jcmd` sur [docs.oracle.com](https://docs.oracle.com/en/java/javase/25/docs/specs/man/jcmd.html) 131 + 132 + Maintenant qu'on a compris comment fonctionnait `jcmd`, on va pouvoir voir quelles sont les commandes les plus utiles pour diagnostiquer une JVM. 133 + 134 + # Les commandes les plus utiles 135 + 136 + > Par "utile" je veux surtout dire "utile pour moi", ne soyez pas vexés si votre commande préf n'est pas dans cette liste. 137 + 138 + ## Lister les informations de la JVM 139 + 140 + * `VM.flags` : liste les options de la JVM 141 + * `VM.version` : affiche la version de la JVM 142 + * `VM.uptime` : affiche l'uptime de la JVM 143 + 144 + # Liens et références 145 + 146 + * La doc de `jcmd` sur [docs.oracle.com](https://docs.oracle.com/en/java/javase/25/docs/specs/man/jcmd.html) 147 + 148 + --- 149 + 150 + Photo de couverture par [Aron Visuals](https://unsplash.com/@aronvisuals?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) sur [Unsplash](https://unsplash.com/photos/multicolored-plasma-ball-in-dim-light-room-_l4yffWjgt4?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
+23
content/posts/drafts/jackson-databind/records.java
··· 1 + /// usr/bin/env jbang "$0" "$@" ; exit $? 2 + 3 + //DEPS com.fasterxml.jackson.core:jackson-databind:2.19.2 4 + 5 + import com.fasterxml.jackson.databind.ObjectMapper; 6 + 7 + record Person(String name, int age) { 8 + } 9 + 10 + class App { 11 + public static void main(String[] args) throws Exception{ 12 + var objectMapper = new ObjectMapper(); 13 + 14 + var json = objectMapper.writeValueAsString(new Person("Julien", 37)); 15 + 16 + System.out.println("json = " + json); 17 + 18 + var julien = objectMapper.readValue(json, Person.class); 19 + 20 + System.out.println("julien = " + julien); 21 + } 22 + 23 + }