Le but de cette examen est d'écrire une classe
DictionaryDecoder qui permet
de décoder des dictionnaires, c'est à dire des objets définis par des chaîne de caractères organisées en couples clé/valeur séparés par des virgules.
Par exemple, un dictionnaire représentant un
Point peut être défini par la chaîne de caractères suivante
x: 12, y: 67
Le décodeur permet de décoder des dictionnaires
-
soit sous forme d'un objet Java utilisant la représentation Java beans
-
soit sous la forme d'un record.
Un
DictionaryDecoder possède deux méthodes
-
register(class) qui permet d'enregistrer une classe qui sera utilisée
pour décoder un dictionnaire
-
decode(dictionary) qui demande de décoder un dictionnaire et
renvoyée une instance initialisée avec les valeurs du dictionnaire.
Par exemple, avec une classe
Point définie comme un Java bean
class Point {
private int x;
private int y;
public Point() {
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
La classe
DictionaryDecoder permet de décoder un dictionnaire avec
le code suivant.
var dictionary = Dictionary.parseLine("x: 12, y: 67");
var decoder = new DictionaryDecoder();
decoder.register(Point.class);
var point = decoder.decode(dictionary);
System.out.println(point); // Point(x: 12, y: 67)
L'implantation fonctionne de cette façon : la méthode
register() va trouver l'ensemble des propriétés
(
PropertyDescriptor) associées à la classe prise en paramètre et enregistre
que cette classe est associée à l'ensemble des noms des propriétés.
Dans notre exemple,
Point.class a les propriétés
x et
y donc
Point est associé à l'ensemble
(x, y).
Lorsque l'on appelle la méthode
decode, celle-ci calcule l'ensemble des clés du dictionnaire
pris en paramètre, trouve la classe correspondant à l'ensemble, appelle le constructeur sans paramètre
de la classe trouvée afin d'en créer une instance et enfin appelle les setters pour initialiser l'instance
avec les valeurs.
Dans notre exemple, le constructeur
Point() est appelé, puis les méthodes
setX
et
setY sont appelées avec respectivement les valeurs 12 et 67.
Pour me faciliter la correction, vous écrirez le code dans le fichier
DictionaryDecoder
sachant que le code pour transformer une chaîne de caractères en un dictionnaire
(la méthode
Dictionary.parseLine) est déjà écrite.
public class DictionaryDecoder {
private static final Pattern PATTERN = Pattern.compile("([^ \t:]+)[ \t]*:[ \t]*([^ \t,]+)");
private static final Pattern NUMBER = Pattern.compile("[0-9]*\\.[0-9]+");
private static final Pattern INTEGER = Pattern.compile("[0-9]+");
public record Data(String key, Object value) {
public Data {
Objects.requireNonNull(key);
Objects.requireNonNull(value);
}
}
private static Object decodeAsObject(String text) {
return switch (text) {
case "true", "false" -> Boolean.parseBoolean(text);
case String s -> NUMBER.matcher(text).matches() ? Double.parseDouble(text) :
(INTEGER.matcher(text).matches() ? Integer.parseInt(text) : text);
};
}
public record Dictionary(List<Data> dataList) {
public static Dictionary parseLine(String line) {
return new Dictionary(PATTERN.matcher(line)
.results()
.map(result -> new Data(result.group(1), decodeAsObject(result.group(2))))
.toList());
}
}
// --- don't change the code above that line
// TODO write your code here
}