Dans ce TP, nous allons un peu jouer avec les nouveautés du langage Java :
-
records
-
streams & lambdas
-
multi-line strings
Nous avons bien besoin de Java 17 (minimum) pour ce TP ! |
1. Initialisation du projet
Initialisez votre projet avec ce lien : https://gitlab-classrooms.cleverapps.io/assignments/9a50d05f-7a5b-4d26-8756-0ee8e82fac12/accept
Initialisez un pom.xml
, ainsi que les répertoires src/main/java
et src/test/java
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.miage.alom.tp</groupId>
<artifactId>w02-modern-java</artifactId>
<version>0.1.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source> (1)
<maven.compiler.target>17</maven.compiler.target> (2)
</properties>
<dependencies>
</dependencies>
</project>
1 | On indique à maven quelle version de Java utiliser pour les sources ! |
2 | On indique à maven quelle version de JVM on cible ! |
Maven considère par défaut que le code est écrit en Java 7 ! |
Ajoutez les dépendances JUnit :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
Il vous faut également surcharger la version du maven-surefire-plugin
(qui est le plugin maven qui implémente la phase d’exécution des tests).
1
2
3
4
5
6
7
8
9
10
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version> (1)
</plugin>
</plugins>
</pluginManagement>
</build>
1 | On a besoin de la version 2.22.0 minimum pour JUnit 5 comme indiqué dans la documentation junit |
Pour que votre TP soit évalué automatiquement, ajoutez également le fichier .gitlab-ci.yml
suivant à la racine de votre projet :
1
2
3
include:
project: gitlab-classrooms/autograding
file: maven-junit.yml
2. Records
Dans un premier temps, nous allons manipuler des records.
Créez les records suivants :
-
PokemonType
-
id: int
-
name: String
-
types: List<String>
-
-
Pokemon
-
type: PokemonType
-
nickname: String
-
level: int
-
Le record PokemonType
représente les types de Pokemon (Pikachu, Rattata, …).
Le record Pokemon
représente un Pokemon particulier (Le Pikachu de Sasha, le Rattata de Julien…).
Importez dans votre code les tests unitaires suivants :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class RecordsTest {
@Test
public void testPokemonTypeCreation(){
var pikachu = new PokemonType(25, "Pikachu", List.of("electric"));
assertThat(pikachu.id()).isEqualTo(25);
assertThat(pikachu.name()).isEqualTo("Pikachu");
assertThat(pikachu.types()).containsOnly("electric");
}
@Test
public void testPokemonCreation(){
var geodude = new PokemonType(74, "Racaillou", List.of("rock", "ground"));
var petersGeodude = new Pokemon(geodude, "Racaillou de Pierre", 12);
assertThat(petersGeodude.nickname()).isEqualTo("Racaillou de Pierre");
assertThat(petersGeodude.type()).isEqualTo(geodude);
assertThat(petersGeodude.level()).isEqualTo(12);
}
}
3. Streams et Lambdas
Nous allons maintenant charger une liste de types de Pokemons, et la manipuler avec des Streams.
Récupérez le fichier pokemons.json, et placez-le dans le répertoire src/main/resources
de votre projet.
Pour charger le fichier JSON, nous allons devoir utiliser la librairie jackson-databind
:
1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
Importez et complétez la classe suivante :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PokemonStreams {
private Collection<PokemonType> pokemonsTypes;
public void loadPokemonTypes() throws IOException {
var objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.pokemonsTypes = objectMapper.readValue(new FileInputStream("src/main/resources/pokemons.json"), new TypeReference<Collection<PokemonType>>() {});
}
public List<PokemonType> sortById(){
// TODO
}
public Set<PokemonType> findByType(String type) {
// TODO
}
public Optional<PokemonType> findFirstByTypes(String... types) {
// TODO
}
}
Vous pouvez valider vos développements avec la classe de test suivante :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class PokemonStreamsTest {
PokemonStreams pokemonStreams;
@BeforeEach
void setUp() throws IOException {
pokemonStreams = new PokemonStreams();
pokemonStreams.loadPokemonTypes();
}
@Test
public void testSortById(){
assertThat(pokemonStreams.sortById())
.extracting(it -> it.id())
.isSorted();
}
@Test
public void testFindElectricPokemons(){
assertThat(pokemonStreams.findByType("electric"))
.hasSize(9);
}
@Test
public void testFindFirePokemons(){
assertThat(pokemonStreams.findByType("fire"))
.hasSize(12);
}
@Test
public void testFindFirstPsychicPokemon(){
assertThat(pokemonStreams.findFirstByTypes("psychic"))
.isNotEmpty()
.get()
.extracting("name")
.isEqualTo("abra");
}
@Test
public void testFindFirstUnknownPokemon(){
assertThat(pokemonStreams.findFirstByTypes("unknown"))
.isEmpty();
}
}
4. Multi-Line Strings
Importez le test suivant, et faites ce qu’il faut pour qu’il passe !
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class TextBlockTest {
ObjectMapper objectMapper;
@BeforeEach
void setUp() {
objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Test
void pokemonAsJsonString() throws JsonProcessingException {
var jsonStringOldFashioned = "{\n" +
" \"id\": 47,\n" +
" \"name\": \"parasect\",\n" +
" \"baseExperience\": 142,\n" +
" \"weight\": 295,\n" +
" \"height\": 10,\n" +
" \"types\": [\n" +
" \"grass\",\n" +
" \"bug\"\n" +
" ],\n" +
" \"stats\": {\n" +
" \"speed\": 30,\n" +
" \"attack\": 95,\n" +
" \"defense\": 80,\n" +
" \"hp\": 60\n" +
" },\n" +
" \"sprites\": {\n" +
" \"front_default\": \"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/47.png\",\n" +
" \"back_default\": \"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/47.png\"\n" +
" }\n" +
" }";
var pokemonTypeFromJsonString = objectMapper.readValue(jsonStringOldFashioned, PokemonType.class);
System.out.println("pokemonType.toString() = " + pokemonTypeFromJsonString.toString());
// TODO : écrivez un text block ici !
String textBlockString = null;
var pokemonTypeFromTextBlock = objectMapper.readValue(textBlockString, PokemonType.class);
assertThat(pokemonTypeFromJsonString).isEqualTo(pokemonTypeFromTextBlock);
}
}