MFormations
Modern Java Engineering

Chapitre 17

17 - Exercices

> 40 exercices pratiques pour maîtriser Java moderne : des streams aux microservices

Chapitre 17 — Exercices : 40 exercices Java modernes

Mise en pratique intensive : de la manipulation de streams aux architectures microservices


Exercice 1 — Streams : Filter, Map, Reduce

Contexte : Vous disposez d'une liste de transactions bancaires. Calculez le solde total des transactions de type "CREDIT" dont le montant dépasse 100€.

record Transaction(String type, double amount, String category) {}
List<Transaction> transactions = List.of(
    new Transaction("CREDIT", 150.0, "Salaire"),
    new Transaction("DEBIT", 50.0, "Courses"),
    new Transaction("CREDIT", 80.0, "Freelance"),
    new Transaction("CREDIT", 200.0, "Vente")
);

Critères :

  • Utiliser exclusivement l'API Stream (pas de boucle)
  • Gérer le cas où la liste est vide
  • Retourner un OptionalDouble

Exercice 2 — Streams : FlatMap et groupingBy

Contexte : À partir d'une liste de commandes contenant plusieurs articles, regroupez les articles vendus par catégorie avec le total des quantités.

record Article(String name, String category, int quantity) {}
record Order(String id, List<Article> articles) {}

Attendu : Map<String, Integer> — catégorie → quantité totale


Exercice 3 — Optional : Chaînage et transformation

Contexte : Service de recherche d'utilisateur par email. Enchaînez les appels findByEmail, map to profile, flatMap to address.

Optional<User> findByEmail(String email);
Optional<Profile> getProfile(User user);
Optional<Address> getAddress(Profile profile);
// Retourner la ville ou "Unknown"

Contrainte : Un seul pipeline, pas de ifPresent ou isPresent.


Exercice 4 — Streams : Partitionnement et statistiques

Contexte : Partitionnez une liste d'employés entre ceux qui gagnent plus et moins de 50000€. Pour chaque groupe, calculez la moyenne, le min, le max, et le total.

Utilisez Collectors.partitioningBy et Collectors.summarizingDouble.


Exercice 5 — Streams : Custom Collector

Contexte : Implémentez un Collector personnalisé qui collecte les éléments en une String avec un séparateur, un préfixe et un suffixe (équivalent à Collectors.joining mais en mode custom).

static <T> Collector<T, ?, String> customJoining(
    String delimiter, String prefix, String suffix
)

Exercice 6 — CompletableFuture : Appels parallèles

Contexte : Trois services HTTP indépendants (prix, stock, avis). Appelez-les en parallèle et combinez leurs résultats.

CompletableFuture<Price> fetchPrice(String productId);
CompletableFuture<Stock> fetchStock(String productId);
CompletableFuture<Review> fetchReviews(String productId);

Utilisez CompletableFuture.allOf puis combinez les résultats.


Exercice 7 — CompletableFuture : Timeout et fallback

Contexte : Appelez un service externe avec un timeout de 2 secondes. Si le délai est dépassé, retournez une valeur par défaut.

CompletableFuture<Product> fetchProduct(String id);
// Timeout 2s, fallback = Product.DEFAULT

Utilisez orTimeout (Java 9+) et exceptionally.


Exercice 8 — CompletableFuture : Pipeline asynchrone

Contexte : Enchaînez : validation → enrichissement → persist → notification. Chaque étape est asynchrone.

CompletableFuture<Order> validate(Order o);
CompletableFuture<Order> enrich(Order o);
CompletableFuture<Order> save(Order o);
CompletableFuture<Void> notify(Order o);

Utilisez thenCompose et thenAccept.


Exercice 9 — CompletableFuture : Rate Limiting

Contexte : Vous avez 100 URLs à télécharger. Limitez à 5 appels concurrents maximum.

// Utiliser un Executor avec un thread pool de taille 5
ExecutorService executor = Executors.newFixedThreadPool(5);

Exercice 10 — CompletableFuture : Composition conditionnelle

Contexte : Appelez un service de cache, si absent appelez le service distant. Avec gestion de fallback et retry (1 tentative).

CompletableFuture<Data> fromCache(String key);
CompletableFuture<Data> fromRemote(String key);

Exercice 11 — JPA : Entity Mapping avancé

Contexte : Créez un modèle JPA complet pour un système de e-commerce avec :

  • User (id, name, email, addresses)
  • Address (street, city, zipCode, type: LIVRAISON/FACTURATION)
  • Order (id, date, status, user, items)
  • OrderItem (product, quantity, unitPrice)
  • Product (id, name, price, category)

Utilisez @OneToMany, @ManyToOne, @ElementCollection, @Enumerated, @Embeddable.


Exercice 12 — JPA : Criteria API dynamique

Contexte : Implémentez une recherche dynamique de produits avec des filtres optionnels : nom, catégorie, prixMin, prixMax, enStock.

List<Product> search(String name, String category,
                     Double minPrice, Double maxPrice, Boolean inStock);

Utilisez CriteriaBuilder, Predicate, Root.


Exercice 13 — JPA : Pagination et tri

Contexte : Implémentez une méthode Page<Product> avec tri par nom, prix ou date d'ajout. Support des filtres.

Page<Product> getProducts(ProductFilter filter, Pageable pageable);

Exercice 14 — JPA : Transaction et Optimistic Locking

Contexte : Implémentez une réservation de billets avec contrôle de concurrence. Utilisez @Version et @Transactional.

Gérez l'exception OptimisticLockException avec un retry.


Exercice 15 — Spring Boot REST : CRUD complet

Contexte : Créez un contrôleur REST pour Product avec :

  • GET /api/products — liste avec pagination
  • GET /api/products/{id} — détail
  • POST /api/products — création
  • PUT /api/products/{id} — mise à jour
  • DELETE /api/products/{id} — suppression soft

Utilisez @RestController, @Valid, ResponseEntity, @ExceptionHandler.


Exercice 16 — Validation avancée

Contexte : Créez un DTO CreateOrderRequest avec validation :

  • @NotBlank userId
  • @NotEmpty items (min 1)
  • @Positive chaque quantité et prix
  • @Future deliveryDate optionnelle
  • Validation cross-champ : si livraison, adresse requise

Exercice 17 — Gestion globale des exceptions

Contexte : Créez un @RestControllerAdvice qui gère :

  • MethodArgumentNotValidException → 400 avec détails
  • EntityNotFoundException → 404
  • DataIntegrityViolationException → 409
  • GenericException → 500 (log + correlationId)

Exercice 18 — HATEOAS avec Spring Boot

Contexte : Ajoutez des liens HATEOAS à l'API Products :

  • Self link sur chaque ressource
  • Lien vers la collection
  • Lien vers les actions possibles (update, delete)
  • Pagination links (first, prev, next, last)

Exercice 19 — JUnit 5 : Parametrized Tests

Contexte : Testez une méthode de validation ISBN avec différents cas :

boolean isValidISBN(String isbn);

Utilisez @CsvSource, @ValueSource, @MethodSource pour 20+ cas.


Exercice 20 — Mockito : Mock avancé

Contexte : Testez un OrderService qui dépend de PaymentGateway, InventoryService, NotificationService.

  • Vérifiez les interactions
  • Utilisez ArgumentCaptor, doThrow, verify
  • Testez le cas où le paiement échoue → rollback

Exercice 21 — Testcontainers : PostgreSQL

Contexte : Testez un UserRepository avec une vraie base PostgreSQL via Testcontainers.

@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");

Testez CRUD, contraintes d'unicité, requêtes personnalisées.


Exercice 22 — Testcontainers : Kafka

Contexte : Testez un producer/consumer Kafka avec Testcontainers.

@Container
static KafkaContainer kafka = new KafkaContainer(
    DockerImageName.parse("confluentinc/cp-kafka:7.6.0")
);

Exercice 23 — ArchUnit : Tests d'architecture

Contexte : Écrivez des tests ArchUnit qui vérifient :

  • Les services ne dépendent pas des contrôleurs
  • Les repositories sont des interfaces
  • Les packages respectent la structure hexagonale
  • Aucune dépendance cyclique

Exercice 24 — Feign Client : Appel inter-service

Contexte : Créez un client Feign pour appeler un service de catalogue depuis un service de commande.

@FeignClient(name = "catalog-service")
interface CatalogClient {
    @GetMapping("/api/products/{id}")
    Product getProduct(@PathVariable String id);
}

Avec configuration des timeouts, retry et fallback.


Exercice 25 — Resilience4j : Circuit Breaker

Contexte : Ajoutez un Circuit Breaker sur l'appel au service de paiement. Configurez :

  • Seuil d'échec : 50%
  • Fenêtre : 10 appels
  • Délai d'attente : 5 secondes
  • Fallback : paiement en attente (PENDING)

Exercice 26 — Spring Cloud Config : Configuration externalisée

Contexte : Créez un service config-server et un client qui lit sa configuration depuis un dépôt Git.

# application.yml dans le repo config
database:
  url: jdbc:postgresql://localhost:5432/mydb
  pool:
    max-size: 20

Exercice 27 — Service Discovery : Eureka

Contexte : Configurez un service registry Eureka et deux microservices qui s'enregistrent et se découvrent mutuellement.


Exercice 28 — API Gateway : Spring Cloud Gateway

Contexte : Configurez une gateway avec :

  • Routage vers les services
  • Rate limiting (50 req/s par client)
  • Filtre JWT pour valider les tokens
  • Logging des requêtes

Exercice 29 — JFR : Flight Recorder

Contexte : Lancez une application Spring Boot avec JFR, déclenchez un dump, puis analysez :

  • GC events, CPU sampling, allocation profiler
  • Thread locks, IO waits
  • Méthodes les plus chaudes (hot methods)

Commandes : jcmd <pid> JFR.start, JFR.dump, JFR.stop


Exercice 30 — GC Tuning : G1 / ZGC

Contexte : Une application de 8 Go de heap avec des pics de latence. Configurez :

  • G1GC : -XX:G1HeapRegionSize=4m -XX:MaxGCPauseMillis=50
  • Ou ZGC : -XX:+UseZGC -XX:ConcGCThreads=4

Testez avec un benchmark et comparez les métriques.


Exercice 31 — Profiling : Async Profiler

Contexte : Utilisez Async Profiler (ou IntelliJ profiler) pour identifier un goulot d'étranglement CPU dans une application qui traite des fichiers CSV.


Exercice 32 — Memory Analysis : Heap Dump

Contexte : Générez un heap dump d'une application qui a une fuite mémoire. Analysez avec Eclipse MAT ou IntelliJ :

  • Identify the leak suspect
  • Dominator tree
  • GC roots

Exercice 33 — JVM Tuning : Flags et diagnostics

Contexte : Optimisez les flags JVM pour une application Spring Boot avec :

  • Heap : 2 Go initial, 4 Go max
  • Metaspace : 256 Mo
  • Stack : 512 Ko par thread
  • GC Logging avec rotation
  • JMX exposé

Exercice 34 — Spring Security : Configuration basique

Contexte : Configurez Spring Security avec :

  • Login form et JWT token
  • Deux rôles : USER et ADMIN
  • Endpoints protégés : /api/admin/** (ADMIN only)
  • /api/public/** accessible sans authentification

Exercice 35 — JWT : Generation et validation

Contexte : Implémentez un service JWT complet :

String generateToken(UserDetails user);
Claims validateToken(String token);
boolean isTokenExpired(String token);
String refreshToken(String token);

Utilisez jjwt (io.jsonwebtoken).


Exercice 36 — OAuth2 : Keycloak integration

Contexte : Intégrez Keycloak comme fournisseur OAuth2 avec Spring Security :

  • Authorization Code flow
  • Resource Server avec JWT
  • Roles mapping (realm → application)

Exercice 37 — Method Security

Contexte : Sécurisez les méthodes avec @PreAuthorize, @PostAuthorize, @Secured :

  • Un utilisateur ne peut modifier que son propre profil
  • Un ADMIN peut tout modifier
  • Vérification basée sur l'ID de l'utilisateur connecté

Exercice 38 — CSRF et CORS

Contexte : Configurez CSRF et CORS pour une application Angular front-end :

  • CSRF : activé avec CookieCsrfTokenRepository
  • CORS : autoriser origin http://localhost:4200
  • Méthodes autorisées : GET, POST, PUT, DELETE, OPTIONS

Exercice 39 — Mini-projet : API de réservation

Contexte : Créez une API REST complète pour un système de réservation :

  • Créneaux horaires (disponible/réservé)
  • Réservation utilisateur avec confirmation email
  • Annulation avec pénalité si < 24h
  • Reporting (réservations par jour/semaine/mois)
  • Tests complets (unitaires + intégration)

Stack : Spring Boot 3.2+, PostgreSQL 16, Testcontainers, JUnit 5, Mockito


Exercice 40 — Mini-projet : Pipeline de traitement

Contexte : Implémentez un pipeline ETL qui :

  1. Lit un fichier CSV de commandes (100k+ lignes)
  2. Valide et transforme avec Streams
  3. Enrichit avec des appels parallèles (CompletableFuture)
  4. Persiste en base avec JPA batch insert
  5. Notifie via Kafka
  6. Archive le fichier traité

Avec monitoring JFR et tests de performance.


Récapitulatif des compétences

#CompétenceNiveau
1-5Streams & OptionalIntermédiaire
6-10CompletableFutureIntermédiaire
11-14JPA/HibernateAvancé
15-18Spring Boot RESTIntermédiaire
19-23TestingAvancé
24-28MicroservicesAvancé
29-33PerformanceExpert
34-38SecurityAvancé
39-40ProjetsExpert

Barème indicatif

  • 30+ exercices réussis : Prêt pour poste Senior
  • 20-29 : Développeur confirmé
  • 10-19 : Débutant à intermédiaire
  • < 10 : Réviser les fondamentaux