@@ -157,7 +157,7 @@ Ajoutez (et testez) à votre ressource une méthode `getMontantTotal` qui renver
...
@@ -157,7 +157,7 @@ Ajoutez (et testez) à votre ressource une méthode `getMontantTotal` qui renver
### Renvoyer des données plus complexes
### Renvoyer des données plus complexes
Jusqu'à maintenant, nous avons transmis de simples valeurs numériques prises en charge directement par Jersey dans le corps de la réponse HTTP. Jersey peut faire la même chose avec des classes Java qui respectent les conventions [`JavaBean`](https://fr.wikipedia.org/wiki/JavaBeans), à minima :
Jusqu'à maintenant, nous avons transmis de simples valeurs numériques prises en charge directement par Jersey dans le corps de la réponse HTTP. Jersey peut faire la même chose avec des classes Java qui respectent les conventions [`JavaBean`](https://fr.wikipedia.org/wiki/JavaBeans), à minima :
- la classe possède un constructeur sans paramètres (constructeur par défaut);
- la classe possède un constructeur sans paramètres (constructeur par défaut);
- les propriétés de la classe sont associées à des accesseurs `get`/`set` pour chaque attribut (par. ex pour un attribut `name` --> `getName()`/`setName()`)
- les propriétés de la classe sont associées à des accesseurs `get`/`set` pour chaque attribut (par. ex pour un attribut `name` --> `getName()`/`setName()`).
Pour un objet de ce type, Jersey va renvoyer dans le corps de la requête un objet (JSON par défaut). Chaque propriété de l'objet java sera représenté par une propriété de l'objet JSON.
Pour un objet de ce type, Jersey va renvoyer dans le corps de la requête un objet (JSON par défaut). Chaque propriété de l'objet java sera représenté par une propriété de l'objet JSON.
...
@@ -168,11 +168,13 @@ Nous allons ajouter une méthode permettant au client d'avoir la liste des nivea
...
@@ -168,11 +168,13 @@ Nous allons ajouter une méthode permettant au client d'avoir la liste des nivea
~~~java
~~~java
packagefr.ulille.iut.tva.dto;
packagefr.ulille.iut.tva.dto;
publicclassInfoTaux{
publicclassInfoTauxDto{
privateStringlabel;
privateStringlabel;
privatedoubletaux;
privatedoubletaux;
publicInfoTaux(Stringlabel,doubletaux){
publicInfoTauxDto(){}
publicInfoTauxDto(Stringlabel,doubletaux){
this.label=label;
this.label=label;
this.taux=taux;
this.taux=taux;
}
}
...
@@ -199,11 +201,11 @@ Nous pouvons maintenant utiliser ce DTO pour renvoyer la liste des taux existant
...
@@ -199,11 +201,11 @@ Nous pouvons maintenant utiliser ce DTO pour renvoyer la liste des taux existant
- pour chaque propriété de la classe `InfoTaux`, on a une propriété équivalente dans les objets JSON
- pour chaque propriété de la classe `InfoTauxDto`, on a une propriété équivalente dans les objets JSON
- la liste renvoyée en Java a été convertie en tableau d'objets JSON
- la liste renvoyée en Java a été convertie en tableau d'objets JSON
- Jersey a choisi le type MIME le plus adapté pour le résultat renvoyé dans le corps de la réponse : `Content-Type: application/json`
- Jersey a choisi le type MIME le plus adapté pour le résultat renvoyé dans le corps de la réponse : `Content-Type: application/json`
### Et les autres formats de données ?
Essayez de faire la requête suivante : `curl -i -H "Accept: application/xml" http://localhost:8080/api/v1/tva/lestaux`. Quel résultat obtenez vous ?
Du côté du serveur, vous devriez observer l'erreur suivante :
~~~
GRAVE: MessageBodyWriter not found for media type=application/xml, type=class java.util.ArrayList, genericType=java.util.List<fr.ulille.iut.tva.dto.InfoTauxDto>
~~~
Ce message indique que Jersey ne sait pas transformer la liste Java dans une représentation `application/xml`. `MessageBodyWriter` est la classe qui devrait être chargée de faire cette transformation (Elle le fait pour JSON).
Pour gérer XML, il faut deux choses. D'abord s'assurer d'avoir les bonnes libraires dans le projet maven (c'est déjà le cas, ici) :
~~~xml
<dependencies>
...
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>3.0.0</version>
<scope>runtime</scope>
</dependency>
...
</dependencies>
~~~
Ces librairies vont nous permettre d'utiliser [JAXB (Java Architecture for XML Binding)](https://javaee.github.io/jaxb-v2/) qui offre les moyens de définir une transformation entre Java et XML. `JAXB` utilise notamment un ensemble d'annotations qui permettent de spécifier comment les attributs d'une classe seront transformés en XML (et inversement).
Ici, nous allons utiliser tous les comportements par défaut de JAXB et nous n'auront besoin que d'une annotation sur notre DTO :
~~~java
importjakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
publicclassInfoTauxDto{
...
}
~~~
Nous pouvons maintenant ressayer notre requête précédente avec succès :
Refaisons notre requête par défaut par acquis de conscience : `curl -i http://localhost:8080/api/v1/tva/lestaux`. Que se passe-t-il ?
Il semble que du coup, notre ressource réponde en priorité en XML, vérifiez qu'elle sait toujours répondre en JSON.
Pour régler ce problème, nous allons spécifier les représentations possibles avec un ordre de préférence (plutôt du JSON) au moyen de l'annotation [@Produces](https://eclipse-ee4j.github.io/jaxrs-api/apidocs/3.0.0/jakarta/ws/rs/Produces.html) :