Niveau : | Intermédiaire |
Version utilisée : | 1.0 |
Il existe différentes solutions open source (Jackson, Genson, Gson, ...) pour réaliser le binding entre des documents JSON et des objets Java mais JSON-B propose une API standard pour permettre ses opérations.
Java API for JSON Binding (JSON-B) est spécifié dans la JSR 367.
Le site web officiel est à l'url http://json-b.net
L'API JSON-B permet de réaliser des opérations de sérialisation et de désérialisation entre des documents JSON et des objets Java :
L'implémentation de référence de JSON-B 1.0 est Yasson
Les conversions de JSON-B se font avec un comportement par défaut mais il est possible de les personnaliser.
Ce chapitre contient plusieurs sections :
La mise en oeuvre de JSON-B pour le binding de documents JSON est similaire à celle de JAX-B pour le binding de documents XML.
Des règles de conversions par défaut sont utilisées lors des opérations exécutées par JSON-B. Il est possible de personnaliser ces règles en utilisant des annotations ou un objet de type JsonbConfig pour des règles globales.
Les classes et interfaces de l'API JSON-B sont dans le package javax.json.bind et ses sous-packages.
Pour utiliser Yasson, l'implémentation de référence de JSON-B 1.0, en dehors d'un serveur d'applications Java EE 8, il faut ajouter plusieurs dépendances :
Exemple avec Maven : |
<dependencies>
<!-- JSON-P API -->
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1</version>
</dependency>
<!-- JSON-B API -->
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
</dependency>
<!-- JSON-B RI -->
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
<!-- JSON-P RI -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
Il est ainsi possible de sérialiser/désérialiser de simples POJO.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
public class Personne {
private String nom;
private String prenom;
private int taille;
private boolean adulte;
private LocalDate dateNaissance;
// getters et setters
}
Pour sérialiser une instance, il suffit de la passer en paramètre de la méthode toJson() d'une instance de type Jsonb préalablement obtenue.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import java.time.Month;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Personne pers = new Personne();
pers.nom = "nom";
pers.prenom = "prenom";
pers.taille = 175;
pers.adulte = true;
pers.dateNaissance = LocalDate.of(1985, Month.AUGUST, 11);
Jsonb jsonb = JsonbBuilder.create();
String result = jsonb.toJson(pers);
System.out.println(result);
}
}
Résultat : |
{"adulte":true,"dateNaissance":"1985-08-11","nom":"nom","prenom":"prenom","taille":175}
La désérialisation se fait aussi de manière très simple : il suffit de passer le document JSON en paramètre de la méthode fromJson() d'une instance de type Jsonb préalablement obtenue.
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Personne pers = new Personne();
Jsonb jsonb = JsonbBuilder.create();
pers = jsonb.fromJson("{\"nom\":\"nom1\",\"prenom\":\"prenom1\",\"taille\":183}",
Personne.class);
System.out.println("nom=" + pers.nom);
System.out.println("prenom=" + pers.prenom);
System.out.println("taille=" + pers.taille);
}
}
Résultat : |
nom=nom1
prenom=prenom1
taille=183
L'interface JsonbBuilder est le point d'entrée pour utiliser l'API JSON-B.
Elle définit plusieurs méthodes mettant en oeuvre le design pattern builder dont le but est de créer une instance de type Jsonb en fonction des paramètres et de la configuration fournie avant l'invocation de la méthode build() :
Méthode |
Rôle |
Jsonb build() |
Obtenir l'instance à partir du builder |
static Jsonb create() |
Obtenir une nouvelle instance de Jsonb obtenue à partir du JsonbBuilder de l'implémentation par défaut |
static Jsonb create(JsonbConfig config) |
Créer une nouvelle instance en utilisant l'implémentation par défaut de JsonbBuilder et la configuration passée en paramètre |
static JsonbBuilder newBuilder() |
Obtenir une instance de type JsonbBuilder obtenue grâce au fournisseur par défaut |
static JsonbBuilder newBuilder(String providerName) |
Obtenir une instance de type JsonbBuilder obtenue grâce au fournisseur dont le nom est passé en paramètre |
static JsonbBuilder newBuilder(JsonbProvider provider) |
Obtenir une instance de type JsonbBuilder obtenue grâce au fournisseur passé en paramètre |
JsonbBuilder withConfig(JsonbConfig config) |
Préciser la configuration de l'instance qui sera obtenue |
JsonbBuilder withProvider(javax.json.spi.JsonProvider jsonpProvider) |
Préciser le fournisseur de l'implémentation de JSON-B à utiliser |
Si le comportement par défaut du moteur JSON-B respecte les besoins, il n'y a aucune configuration particulière à utiliser. L'obtention d'une instance configurée par défaut peut facilement être réalisée en invoquant la méthode create() de la classe JsonbBuilder.
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
}
}
Il est recommandé de n'avoir qu'une seule instance de type Jsonb par configuration de mapping d'autant que les instances de type Jsonb doivent être thread safe.
L'interface Jsonb permet de demander des sérialisations et des désérialisations au moteur JSON-B. Elle définit plusieurs surcharges de deux méthodes :
Méthode |
Rôle |
<T> T fromJson(String str, Class<T> type); |
Convertir un document JSON en un objet Java |
String toJson(Object object); |
Convertir un objet Java en un document JSON |
L'interface Jsonb hérite de l'interface AutoCloseable.
Le moteur JSON-B utilise un ensemble de règles pour réaliser les mapping.
Les implémentations de JSON-B doivent assurer la correspondance pour des documents JSON qui respectent la RFC 7159 (The JavaScript Object Notation (JSON) Data Interchange Format).
Le document JSON issue d'une sérialisation doit donc respecter la RFC 7159 et être encodé en UTF-8.
Le mapping par défaut ne requiert ni configuration ni annotation particulière. Ce mapping par défaut comporte des règles pour la sérialisation/désérialisation pour les principaux types :
Une implémentation de JSON-B doit prendre en charge les types de base et les types spécifiques du JDK ci-dessous :
Type de base |
Type spécifique du JDK |
java.lang.String |
java.math.BigInteger |
Exemple ( code Java 8 ) : |
public class Primitives {
public String unString = "string";
public char unChar = 'a';
public byte unByte = 1;
public short unShort = 2;
public int unInt = 3;
public long unLong = 4L;
public float unFloat = 5.1f;
public double unDouble = 6.2;
public boolean unBoolean = true;
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = (new JsonbConfig()).withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
Primitives primitives = new Primitives();
String result = jsonb.toJson(primitives);
System.out.println(result);
}
}
Résultat : |
{
"unString": "string",
"unBoolean": true,
"unByte": 1,
"unChar": "a",
"unDouble": 6.2,
"unFloat": 5.1,
"unInt": 3,
"unLong": 4,
"unShort": 2
}
Lors de la sérialisation, la valeur d'une instance de type BigInteger, BigDecimal, URL et URI est obtenue en invoquant leur méthode toString(). La désérialisation utilise leur constructeur qui attend une chaîne de caractère en paramètre.
La valeur sérialisée pour les Optionalxxx est la valeur encapsulée si elle est présente ou null si elle est vide.
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = (new JsonbConfig()).withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
Objets objets = new Objets();
String result = jsonb.toJson(objets);
System.out.println(result);
}
}
Exemple ( code Java 8 ) : |
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.OptionalInt;
public class Objets {
public BigInteger bigInteger = BigInteger.valueOf(1000L);
public BigDecimal bigDecimal = new BigDecimal("1.2");
public OptionalInt optionalInt = OptionalInt.of(1);
public OptionalInt optionalEmpty = OptionalInt.empty();
public URL url = null;
public Objets() {
try {
url = new URL("file://c:/temp");
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
Résultat : |
{
"bigDecimal": 1.2,
"bigInteger": 1000,
"optionalInt": 1,
"url": "file://c:/temp"
}
Une implémentation de JSON-B doit prendre en charge les types temporels en sérialisant leur valeur selon le tableau ci-dessous :
java.util.Date, java.util.Calendar, java.util.GregorianCalendar |
ISO_DATE ou ISO_DATE_TIME selon la présence d'informations sur l'heure |
java.util.TimeZone, java.util.SimpleTimeZone |
NormalizedCustomId (cf Javadoc de la classe TimeZone) |
java.time.Instant |
ISO_INSTANT |
java.time.LocalDate |
ISO_LOCAL_DATE |
java.time.LocalTime |
ISO_LOCAL_TIME |
java.time.LocalDateTime |
ISO_LOCAL_DATE_TIME |
java.time.ZonedDateTime |
ISO_ZONED_DATE_TIME |
java.time.OffsetDateTime |
ISO_OFFSET_DATE_TIME |
java.time.OffsetTime |
ISO_OFFSET_TIME |
java.time.ZoneId |
NormalizedZoneId (cf Javadoc de la classe ZoneId) |
java.time.ZoneOffset |
NormalizedZoneId (cf Javadoc de la classe ZoneOffset) |
java.time.Duration |
Représentation en secondes définie par l'ISO 8601 |
java.time.Period |
Représentation période définie par l'ISO 8601 |
Exemple ( code Java 8 ) : |
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.OffsetDateTime;
import java.time.Period;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
public class Dates {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
public Date date = null;
public Calendar calendar = Calendar.getInstance();
public LocalDate localDate = LocalDate.now();
public LocalTime localTime = LocalTime.now();
public LocalDateTime localDateTime = LocalDateTime.now();
public ZonedDateTime zonedDatetime = ZonedDateTime.now();
public OffsetDateTime offsetDateTime = OffsetDateTime.now();
public Duration duree = Duration.ofHours(1).plusMinutes(30);
public Instant instant = Instant.parse("2017-08-27T12:00:00Z");
public Period periode = Period.between(LocalDate.of(2017,
Month.DECEMBER, 25), LocalDate.of(2016, Month.DECEMBER, 25));
public Dates() {
calendar.clear();
calendar.set(2017, 7, 26);
try {
date = sdf.parse("15.11.2016");
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = (new JsonbConfig()).withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
Dates dates = new Dates();
String result = jsonb.toJson(dates);
System.out.println(result);
}
}
Résultat : |
{
"calendar": "2017-08-26+02:00",
"date": "2016-11-14T23:00:00Z[UTC]",
"duree": "PT1H30M",
"instant": "2017-08-27T12:00:00Z",
"localDate": "2017-08-27",
"localDateTime": "2017-08-27T15:24:48.241",
"localTime": "15:24:48.241",
"offsetDateTime": "2017-08-27T15:24:48.242+02:00",
"periode": "P-1Y",
"zonedDatetime": "2017-08-27T15:24:48.241+02:00[Europe/Paris]"
}
Le mapping par défaut d'une énumération suit plusieurs règles :
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
enum Taille { PETIT, MOYEN, GRAND };
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
String result = jsonb.toJson(Taille.GRAND);
System.out.println(result);
}
}
Résultat : |
"GRAND"
Le mapping par défaut d'un type quelconque suit plusieurs règles :
Le mapping par défaut d'un champ suit plusieurs règles :
Une implémentation de JSON-B doit respecter un certain ordre pour accéder ou alimenter des valeurs lors des opérations.
Pour la sérialisation :
Pour la désérialisation :
Exemple ( code Java 8 ) : |
public class Donnees {
public final int champPublicFinal = 1;
private final int champPublicPrivate = 2;
public static int champPublicStatic = 3;
public int champPublicSansGetter = 4;
public int champPublicAvecGetterPrivate = 5;
private int champPrivateSansGetter = 6;
private int champPrivateAvecGetter = 7;
public Integer champPublicNull = null;
public transient int champPublicTransient = 8;
public int getSansChamp() {
return 9;
};
public int getChampPrivateAvecGetter() {
return 10;
};
private int getChampPublicAvecGetterPrivate() {
return 11;
}
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
Donnees donnees = new Donnees();
String result = jsonb.toJson(donnees);
System.out.println(result);
}
}
Résultat : |
{"champPrivateAvecGetter":10,"champPublicFinal":1,"champPublicSansGetter":4,"sansChamp":9}
Le mapping par défaut prend en compte les tableaux mono ou multi-dimensions et les principales classes de bases de l'API Collection : Collection, Map, Set, HashSet, NavigableSet, SortedSet, TreeSet, LinkedHashSet, HashMap, NavigableMap, SortedMap, TreeMap, LinkedHashMap, List, ArrayList, LinkedList, Deque, ArrayDeque, Queue, PriorityQueue.
Exemple ( code Java 8 ) : |
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Valeurs {
public int[] tableau = new int[5];
public int[][] tab2d = { { 2, 4, 1 }, { 6, 8 }, { 7, 3, 6, 5 } };
public List<Integer> list = new ArrayList<>();
public Map<Integer, String> map = new HashMap<>();
public Set<Integer> set = new HashSet<>();
public Deque<Integer> deque = new ArrayDeque<>();
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
Valeurs valeurs = new Valeurs();
valeurs.tableau[0] = 1;
valeurs.tableau[1] = 2;
valeurs.list.add(3);
valeurs.list.add(null);
valeurs.list.add(4);
valeurs.map.put(1, "un");
valeurs.map.put(2, "deux");
valeurs.set.add(5);
valeurs.set.add(5);
valeurs.set.add(6);
valeurs.deque.push(7);
valeurs.deque.push(8);
String result = jsonb.toJson(valeurs);
System.out.println(result);
}
}
Résultat : |
{"deque":[8,7],"list":[3,null,4],"map":{"1":"un",
"2":"deux"},"set":[5,6],"tab2d":[[2,4,1],[6,8],[7,3,6,5]],"tableau":[1,2,0,0,0]}
Lors de la désérialisation d'un tableau JSON, il est nécessaire de préciser le type de l'instance retournée par la méthode fromJson(). Ce type peut être un tableau.
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
String[] valeurs = jsonb.fromJson("[\"valeur1\",\"valeur2\",\"valeur3\"]",
String[].class);
for (String valeur : valeurs) {
System.out.println(valeur);
}
}
}
Résultat : |
valeur1
valeur2
valeur3
Ce type peut aussi être une collection.
Exemple ( code Java 8 ) : |
import java.util.ArrayList;
import java.util.List;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
List valeurs = jsonb.fromJson("[\"valeur1\",\"valeur2\",\"valeur3\"]",
ArrayList.class);
for (Object object : valeurs) {
System.out.println(object);
}
}
}
JSON-B supporte aussi les collections génériques. Pour que le moteur puisse réaliser la désérialisation, il faut passer en second paramètre de la méthode fromJson() le type de l'objet renvoyé.
Exemple ( code Java 8 ) : |
import java.util.ArrayList;
import java.util.List;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
List<String> valeurs = jsonb.fromJson("[\"valeur1\",\"valeur2\",\"valeur3\"]",
new ArrayList<String>() {}.getClass().getGenericSuperclass());
for (String valeur : valeurs) {
System.out.println(valeur);
}
}
}
Le mapping par défaut peut utiliser des classes de l'API JSON-P :
Le mapping par défaut des classes de l'API JSON-P suit plusieurs règles :
Exemple ( code Java 8 ) : |
import javax.json.Json;
import javax.json.JsonBuilderFactory;
import javax.json.JsonObject;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
JsonBuilderFactory factory = Json.createBuilderFactory(null);
JsonObject jsonObject = factory.createObjectBuilder()
.add("nom", "nom1")
.add("prenom", "prenom1")
.add("dateNaissance", "1985-08-11")
.add("taille", 175)
.build();
String result = jsonb.toJson(jsonObject);
System.out.println(result);
}
}
Résultat : |
{"nom":"nom1","prenom":"prenom1","dateNaissance":"1985-08-11","taille":175}
Il est possible de modifier le comportement par défaut du moteur JSON-B, pour la sérialisation et la désérialisation, en utilisant une configuration particulière, encapsulée dans un objet de type javax.json.bind.JsonbConfig.
La classe JsonbConfig met en oeuvre le design pattern builder pour permettre de construire un objet qui encapsule les options de configuration particulière du moteur JSON-B.
Elle définit plusieurs méthodes permettant de définir la configuration qui sera utilisée par le moteur JSON-B :
Méthode |
Rôle |
Map<String,Object> getAsMap() |
Renvoyer une Map non modifiable de toutes les propriétés de configuration |
Optional<Object> getProperty(String name) |
Renvoyer la valeur de la propriété de configuration dont le nom est fourni en paramètre |
JsonbConfig setProperty(String name, Object value) |
Modifier la valeur de la propriété dont le nom est fourni en paramètre |
JsonbConfig withAdapters(JsonbAdapter... adapters) |
Enregistrer les adaptateurs fournis en paramètre |
JsonbConfig withBinaryDataStrategy(String binaryDataStrategy) |
Préciser la stratégie de conversion des données binaires |
JsonbConfig withDateFormat(String dateFormat, Locale locale) |
Préciser le format de conversion des dates |
JsonbConfig withDeserializers(JsonbDeserializer... deserializers) |
Enregistrer les Deserializers fournis en paramètres |
JsonbConfig withEncoding(String encoding) |
Préciser le jeu d'encodage des caractères des documents JSON |
JsonbConfig withFormatting(Boolean formatted) |
Préciser si le document JSON produit doit être formaté ou non |
JsonbConfig withLocale(Locale locale) |
Préciser la Locale à utiliser |
JsonbConfig withNullValues(Boolean serializeNullValues) |
Préciser si les propriétés ayant une valeur null sont sérialisées ou non |
JsonbConfig withPropertyNamingStrategy(String propertyNamingStrategy) |
Préciser la stratégie de nommage des propriétés parmi celles proposées en standard |
JsonbConfig withPropertyNamingStrategy(PropertyNamingStrategy propertyNamingStrategy) |
Préciser une stratégie personnalisée de nommage des propriétés |
JsonbConfig withPropertyOrderStrategy(String propertyOrderStrategy) |
Préciser la stratégie de gestion de l'ordre des propriétés |
JsonbConfig withPropertyVisibilityStrategy(PropertyVisibilityStrategy propertyVisibilityStrategy) |
Préciser une stratégie de gestion de la visibilité des propriétés |
JsonbConfig withSerializers(JsonbSerializer... serializers) |
Enregistrer des Serializers |
JsonbConfig withStrictIJSON(Boolean enabled) |
Préciser si le document JSON produit doit respecter la spécification I-JSON ou non |
Pour utiliser la configuration, il faut passer une instance de JsonbConfig en paramètre de la méthode withConfig() de la classe JsonbBuilder.
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = (new JsonbConfig()).withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
}
}
Pour demander le formatage du résultat de la sérialisation, ce qui augmente la taille du document mais le rend plus facile à lire par un humain, il suffit de passer la valeur true à la méthode withFormatting() de la classe JsonbConfig.
Exemple ( code Java 8 ) : |
JsonbConfig config = new JsonbConfig().withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
String result = jsonb.toJson(pers);
System.out.println(result);
Résultat : |
{
"adulte": true,
"dateNaissance": "1985-08-11",
"nom": "nom",
"prenom": "prenom",
"taille": 175
}
De nombreux aspects du mapping peuvent être configurés :
Cette configuration peut se faire soit :
Par défaut, le nom de la propriété dans le document est le nom de propriété dans l'objet Java. Il est possible de personnaliser le nom d'une propriété en utilisant l'annotation @JsonbProperty pour changer son nom.
L'annotation @JsonbProperty peut être utilisée sur :
Pour modifier le nom de la propriété d'un champ lors la sérialisation ou la désérialisation, il faut utiliser l'annotation @JsonbProperty sur un champ en lui passant comme valeur le nom de la propriété.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import javax.json.bind.annotation.JsonbProperty;
public class Personne {
@JsonbProperty("nom-special")
private String nom;
// ...
}
Résultat : |
{"adulte":true,"dateNaissance":"1985-08-11","nom-special":"nom","prenom":"prenom","taille":175}
Il est possible d'utiliser l'annotation @JsonbProperty sur les getters/setters pour permettre d'utiliser un nom de propriété différent lors de la sérialisation et de la désérialisation.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import javax.json.bind.annotation.JsonbProperty;
public class Personne {
// ...
@JsonbProperty("nom-serialise")
public String getNom() {
return nom;
}
@JsonbProperty("nom-deserialise")
public void setNom(String nom) {
this.nom = nom;
}
//...
}
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import java.time.Month;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Personne pers = new Personne();
pers.setNom("nom");
pers.setPrenom("prenom");
pers.setTaille(175);
pers.setAdulte(true);
pers.setDateNaissance(LocalDate.of(1985, Month.AUGUST, 11));
Jsonb jsonb = JsonbBuilder.create();
String result = jsonb.toJson(pers);
System.out.println(result);
pers = jsonb.fromJson(
"{\"nom-deserialise\":\"nom1\",\"prenom\":\"prenom1\",\"taille\":183}",
Personne.class);
System.out.println("nom=" + pers.getNom());
}
}
Résultat : |
{"adulte":true,"dateNaissance":"1985-08-11","nom-serialise":"nom","prenom":"prenom","taille":
175}
nom=nom1
Une stratégie de nommage de propriétés permet de définir d'une manière globale comment sont gérés les noms des propriétés.
Plusieurs stratégies de nommage sont proposées grâce à des constantes de l'interface PropertyNamingStrategy :
Stratégie de nommage |
Exemple |
IDENTITY |
nomDeMaPropriete |
LOWER_CASE_WITH_DASHES |
nom-de-ma-propriete |
LOWER_CASE_WITH_UNDERSCORES |
nom_de_ma_propriete |
UPPER_CAMEL_CASE |
NomDeMaPropriete |
UPPER_CAMEL_CASE_WITH_SPACES |
Nom De Ma Propriete |
CASE_INSENSITIVE |
nOmDeMaPrOpRiEtE |
Il est possible de définir et d'utiliser sa propre stratégie de nommage en implémentant l'interface JsonbNamingInterface.
La stratégie par défaut est IDENTITY.
Pour demander l'application d'une stratégie particulière, il faut utiliser une des deux surcharges de la méthode de la classe JsonbConfig :
Exemple ( code Java 8 ) : |
JsonbConfig config = new JsonbConfig().withPropertyNamingStrategy(
PropertyNamingStrategy.LOWER_CASE_WITH_DASHES);
Jsonb jsonb = JsonbBuilder.create(config);
String result = jsonb.toJson(pers);
System.out.println(result);
Résultat : |
{"adulte":true,"date-naissance":"1985-08-11","nom":"nom","prenom":"prenom","taille":175}
Il est possible de personnaliser l'ordre dans lequel les propriétés sont sérialisées en utilisant la classe PropertyOrderStrategy. Elle définit trois constantes pour désigner les stratégies supportées :
La stratégie de gestion de l'ordre de sérialisation des propriétés par défaut du moteur JSON-B est LEXICOGRAPHICAL. Il est possible de modifier ce comportement de deux manières :
Il est possible de modifier la configuration pour qu'elle utilise une stratégie d'ordonnancement des propriétés lors de la sérialisation en utilisant la méthode withPropertyOrderStrategy() de la classe JsonbConfig en lui passant en paramètre une des constantes définies dans la classe PropertyOrderStrategy.
Exemple ( code Java 8 ) : |
JsonbConfig config = new JsonbConfig().withPropertyOrderStrategy(PropertyOrderStrategy.ANY);
Jsonb jsonb = JsonbBuilder.create(config);
String result = jsonb.toJson(pers);
System.out.println(result);
Résultat : |
{"taille":175,"adulte":true,"dateNaissance":"1985-08-11","nom":"nom","prenom":"prenom"}
Pour appliquer une stratégie particulière à une classe, il faut lui appliquer l'annotation @JsonbPropertyOrder en lui passant comme valeur une des constantes définies dans la classe PropertyOrderStrategy
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import javax.json.bind.annotation.JsonbPropertyOrder;
import javax.json.bind.config.PropertyOrderStrategy;
@JsonbPropertyOrder(PropertyOrderStrategy.ANY)
public class Personne {
// ...
}
L'annotation @javax.json.bind.annotation.JsonbTransient permet de demander au moteur JSON-B d'ignorer une propriété lors de ses opérations de sérialisation et/ou de désérialisation selon l'élément sur lequel l'annotation est placée :
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import javax.json.bind.annotation.JsonbTransient;
public class Personne {
private String nom;
private String prenom;
private int taille;
private boolean adulte;
@JsonbTransient
private LocalDate dateNaissance;
// ...
public LocalDate getDateNaissance() {
return dateNaissance;
}
public void setDateNaissance(LocalDate dateNaissance) {
this.dateNaissance = dateNaissance;
}
}
Dans l'exemple ci-dessus, la propriété dateNaissance sera ignorée lors des opérations de sérialisation mais sera utilisée lors de désérialisations avec JSON-B.
Exemple ( code Java 8 ) : |
// ...
private LocalDate dateNaissance;
// ...
public LocalDate getDateNaissance() {
return dateNaissance;
}
@JsonbTransient
public void setDateNaissance(LocalDate dateNaissance) {
this.dateNaissance = dateNaissance;
}
}
Dans l'exemple ci-dessus, la propriété dateNaissance sera ignorée lors des opérations de sérialisation et de désérialisation avec JSON-B.
Exemple ( code Java 8 ) : |
// ...
private LocalDate dateNaissance;
// ...
public LocalDate getDateNaissance() {
return dateNaissance;
}
public void setDateNaissance(LocalDate dateNaissance) {
this.dateNaissance = dateNaissance;
}
}
Dans l'exemple ci-dessus, la propriété dateNaissance sera utilisée lors des opérations de sérialisation et sera ignorée lors de désérialisations avec JSON-B.
Il est possible de définir une stratégie personnalisée de visibilité des propriétés. Cela peut, par exemple, permettre de sérialiser des champs private sans getter.
Exemple ( code Java 8 ) : |
public class MaClasse {
private String description;
private String nom;
private int longueur;
public MaClasse() {
}
public MaClasse(String description, String nom, int longueur) {
this.description = description;
this.nom = nom;
this.longueur = longueur;
}
}
Il faut définir une classe qui implémente l'interface PropertyVisibilityStrategy. Cette interface définit deux méthodes :
Méthode |
Rôle |
boolean isVisible(Field field) |
Renvoyer un booléen qui précise si le champ passé en paramètre doit être pris en compte comme étant une JsonbProperty |
boolean isVisible(Method method) |
Renvoyer un booléen qui précise si la méthode passée en paramètre doit être prise en compte comme étant une JsonbProperty |
Exemple ( code Java 8 ) : |
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.json.bind.config.PropertyVisibilityStrategy;
public class MonPropertyVisibilityStrategy implements PropertyVisibilityStrategy {
@Override
public boolean isVisible(Field field) {
return true;
}
@Override
public boolean isVisible(Method method) {
return true;
}
}
L'implémentation ci-dessus est très basique car elle permet d'accéder à toutes les propriétés.
Pour pouvoir utiliser la stratégie de manière globale, il faut utiliser la méthode withPropertyVisibilityStrategy() de la classe JsonbConfig utilisée pour obtenir l'instance du moteur JSON-B. Elle attend en paramètre une instance de la classe qui implémente l'interface PropertyVisibilityStrategy.
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
MaClasse obj = new MaClasse("la description", "le nom", 250);
JsonbConfig config = new JsonbConfig()
.withPropertyVisibilityStrategy(new MonPropertyVisibilityStrategy());
Jsonb jsonb = JsonbBuilder.create(config);
String result = jsonb.toJson(obj);
System.out.println(result);
}
}
Résultat : |
{"description":"la description","longueur":250,"nom":"le nom"}
Pour demander l'application de cette stratégie sur une seule classe, il faut lui appliquer l'annotation @JsonbVisibility en lui passant comme valeur de son attribut par le défaut la classe d'implémentation de l'interface PropertyVisibilityStrategy.
Exemple ( code Java 8 ) : |
import javax.json.bind.annotation.JsonbVisibility;
@JsonbVisibility(MonPropertyVisibilityStrategy.class)
public class MaClasse {
private String description;
private String nom;
private int longueur;
// ...
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
MaClasse obj = new MaClasse("la description", "le nom", 250);
Jsonb jsonb = JsonbBuilder.create();
String result = jsonb.toJson(obj);
System.out.println(result);
}
}
Résultat : |
{"description":"la description","longueur":250,"nom":"le nom"}
La configuration par défaut du moteur JSON-B ne sérialise pas les champs dont la valeur est null.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import java.time.Month;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
Personne pers = new Personne();
pers.setNom(null);
pers.setPrenom(null);
pers.setTaille(175);
pers.setAdulte(true);
pers.setDateNaissance(LocalDate.of(1985, Month.AUGUST, 11));
Jsonb jsonb = JsonbBuilder.create();
String result = jsonb.toJson(pers);
System.out.println(result);
}
}
Résultat : |
{"adulte":true,"dateNaissance":"1985-08-11","taille":175}
Il y a trois possibilités pour modifier ce comportement par défaut :
Il est possible d'utiliser l'annotation @JsonbNillable sur une classe ou un package pour demander la sérialisation des valeurs des propriétés de la ou des classes concernées.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import javax.json.bind.annotation.JsonbNillable;
@JsonbNillable
public class Personne {
// ...
}
Résultat : |
{"adulte":true,"dateNaissance":"1985-08-11","nom":null,"prenom":null,"taille":175}
Il est possible d'utiliser l'annotation @JsonbProperty avec son attribut nillable=true sur un champ pour demander de sérialiser sa valeur si elle est null.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import javax.json.bind.annotation.JsonbProperty;
public class Personne {
private String nom;
@JsonbProperty(nillable = true)
private String prenom;
// ...
}
Résultat : |
{"adulte":true,"dateNaissance":"1985-08-11","prenom":null,"taille":175}
Il est possible de modifier globalement la configuration pour que toutes les valeurs null soient sérialisées en invoquant la méthode withNullValues(true) de l'instance de JsonbConfig utilisée pour obtenir l'instance du moteur.
Exemple ( code Java 8 ) : |
JsonbConfig config = new JsonbConfig().withNullValues(true);
Jsonb jsonb = JsonbBuilder.create(config);
String result = jsonb.toJson(pers);
System.out.println(result);
Résultat : |
{"adulte":true,"dateNaissance":"1985-08-11","nom":null,"prenom":null,"taille":175}
Par défaut, les classes utilisées lors de la désérialisation doivent avoir un constructeur par défaut qui sera invoqué par le moteur JSON-B pour créer une instance. Cette contrainte est parfois trop contraignante : c'est par exemple le cas pour un objet immuable.
L'annotation @javax.json.bind.annotation.JsonbCreator peut être utilisée sur un constructeur ou une fabrique statique pour indiquer au moteur JSON comment créer une instance.
L'annotation @JsonbCreator ne possède aucun attribut et ne peut être utilisée que sur une seule méthode statique qui est une fabrique ou un seul constructeur avec paramètre(s) dans la classe. Si ce n'est pas le cas alors une exception de type JsonbException est levée.
Pour assurer la bonne liaison entre les données lues du document JSON et les paramètres du constructeur ou de la fabrique, il faut annoter chaque paramètre avec l'annotation @JsonbProperty() en lui précisant comme valeur le nom de l'attribut. Le nom de l'attribut précisé doit exister dans le document JSON sinon une exception de type JsonbException est levée.
Si l'annotation @JsonbProperty n'est pas utilisée sur les paramètres, le moteur sa tenter de faire une correspondance avec le nom du paramètre, sous réserve que celui-ci soit accessible.
Il est possible d'utiliser l'annotation @JsonbCreator sur un constructeur.
Exemple ( code Java 8 ) : |
import javax.json.bind.annotation.JsonbCreator;
import javax.json.bind.annotation.JsonbProperty;
public class Produit {
private long id;
private String libelle;
private String reference;
@JsonbCreator
public Produit(@JsonbProperty("id") long id,
@JsonbProperty("libelle") String lib,
@JsonbProperty("reference") String ref) {
this.id = id;
libelle = lib;
reference = ref;
System.out.println("Invocation constructeur Produit");
}
public long getId() {
return id;
}
public String getLibelle() {
return libelle;
}
public String getReference() {
return reference;
}
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = new JsonbConfig().withStrictIJSON(true);
Jsonb jsonb = JsonbBuilder.create(config);
Produit produit = new Produit(1, "test", "ref1");
String result = jsonb.toJson(produit);
System.out.println(result);
Produit prod = jsonb.fromJson(result, Produit.class);
System.out.println("id =" + prod.getId());
System.out.println("libelle =" + prod.getLibelle());
System.out.println("reference=" + prod.getReference());
}
}
Résultat : |
Invocation constructeur Produit
{"id":1,"libelle":"test","reference":"ref1"}
Invocation constructeur Produit
id =1
libelle =test
reference=ref1
Il est possible d'utiliser l'annotation @JsonbCreator sur une méthode statique qui est une fabrique pour obtenir une instance : elle doit donc renvoyer une instance du type de la classe sinon une exception de type JsonbException est levée.
Exemple ( code Java 8 ) : |
import javax.json.bind.annotation.JsonbCreator;
import javax.json.bind.annotation.JsonbProperty;
public class Produit {
private long id;
private String libelle;
private String reference;
@JsonbCreator
public static Produit creerInstance(@JsonbProperty("id") long id,
@JsonbProperty("libelle") String lib,
@JsonbProperty("reference") String ref) {
Produit result = new Produit();
result.id = id;
result.libelle = lib;
result.reference = ref;
System.out.println("Invocation fabrique Produit");
return result;
}
public long getId() {
return id;
}
public String getLibelle() {
return libelle;
}
public String getReference() {
return reference;
}
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = new JsonbConfig().withStrictIJSON(true);
Jsonb jsonb = JsonbBuilder.create(config);
Produit produit = Produit.creerInstance(1, "test", "ref1");
String result = jsonb.toJson(produit);
System.out.println(result);
Produit prod = jsonb.fromJson(result, Produit.class);
System.out.println("id =" + prod.getId());
System.out.println("libelle =" + prod.getLibelle());
System.out.println("reference=" + prod.getReference());
}
}
Résultat : |
Invocation fabrique Produit
{"id":1,"libelle":"test","reference":"ref1"}
Invocation fabrique Produit
id =1
libelle =test
reference=ref1
Par défaut, JSON-B utilise les formats ISO pour sérialiser et désérialiser des données temporelles et numériques.
Exemple ( code Java 8 ) : |
import java.math.BigDecimal;
import java.util.Date;
public class ResultatEpreuve {
public long idEpreuve;
public long idCandidat;
public Date date;
public BigDecimal note;
}
Exemple ( code Java 8 ) : |
import java.math.BigDecimal;
import java.util.Date;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = (new JsonbConfig()).withFormatting(true);
Jsonb jsonb = JsonbBuilder.create(config);
ResultatEpreuve re = new ResultatEpreuve();
re.date = new Date();
re.idCandidat = 123;
re.idEpreuve = 456;
re.note = new BigDecimal("15.5");
String result = jsonb.toJson(re);
System.out.println(result);
}
}
Résultat : |
{
"date": "2017-08-31T07:53:37.753Z[UTC]",
"idCandidat": 123,
"idEpreuve": 456,
"note": 15.5
}
Pour utiliser un format particulier pour un champ, il est possible d'utiliser les annotations @JsonbDateFormat et @JsonbNumberFormat.
Exemple ( code Java 8 ) : |
import java.math.BigDecimal;
import java.util.Date;
import javax.json.bind.annotation.JsonbDateFormat;
import javax.json.bind.annotation.JsonbNumberFormat;
public class ResultatEpreuve {
public long idEpreuve;
public long idCandidat;
@JsonbDateFormat("dd/MMM/yyyy")
public Date date;
@JsonbNumberFormat("#0.00")
public BigDecimal note;
}
Résultat : |
{
"date": "31/Aug/2017",
"idCandidat": 123,
"idEpreuve": 456,
"note": "15,50"
}
Les annotations @JsonbDateFormat et @JsonbNumberFormat peuvent s'utiliser sur un champ, un getter/setter, un type, un paramètre ou un package.
L'annotation @JsonbDateFormat possède deux attributs optionnels :
Attribut |
Rôle |
String locale |
La Locale à utiliser |
String value |
Le motif de formatage à utiliser exprimé avec le format supporté par la classe DateTimeFormatter |
Exemple ( code Java 8 ) : |
// ...
@JsonbDateFormat(value = "dd/MMM/yyyy", locale = "FR")
public Date date;
// ...
Résultat : |
{
"date": "31/août/2017",
"idCandidat": 123,
"idEpreuve": 456,
"note": "15,50"
}
L'annotation @JsonbNumberFormat possède deux attributs optionnels :
Attribut |
Rôle |
String locale |
La Locale à utiliser |
String value |
Le motif de formatage à utiliser en utilisant le format supporté par la classe DecimalFormat |
Il est aussi possible de configurer globalement le format des dates utilisant une instance de type JsonbConfig qui propose deux méthodes :
Méthode |
Rôle |
JsonbConfig withDateFormat(String dateFormat, Locale locale) |
Préciser le format de date et la Locale à utiliser |
JsonbConfig withLocale(Locale locale) |
Préciser la Locale à utiliser |
Exemple ( code Java 8 ) : |
import java.math.BigDecimal;
import java.util.Date;
import java.util.Locale;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = (new JsonbConfig()).withFormatting(true)
.withDateFormat("dd/MMM/yyyy", Locale.ITALIAN);
Jsonb jsonb = JsonbBuilder.create(config);
ResultatEpreuve re = new ResultatEpreuve();
re.date = new Date();
re.idCandidat = 123;
re.idEpreuve = 456;
re.note = new BigDecimal("15.5");
String result = jsonb.toJson(re);
System.out.println(result);
}
}
Résultat : |
{
"date": "31/ago/2017",
"idCandidat": 123,
"idEpreuve": 456,
"note": 15.5
}
JSON-B supporte les données binaires. Les trois types d'encodage supportés sont définis sous la forme de constantes dans la classe BinaryDataStrategy:
Pour définir la stratégie globale de binding des données binaires, il faut passer une de ces constantes à la méthode withBinaryDataStrategy() de la classe JsonbConfig.
Exemple ( code Java 8 ) : |
import java.util.Random;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
import javax.json.bind.config.BinaryDataStrategy;
public class TestJsonB {
public static void main(String[] args) {
byte[] donnees = new byte[10];
new Random().nextBytes(donnees);
System.out.println("BYTE " + serialiserBinaire(donnees,
BinaryDataStrategy.BYTE));
System.out.println("BASE_64 " + serialiserBinaire(donnees,
BinaryDataStrategy.BASE_64));
System.out.println("BASE_64_URL " + serialiserBinaire(donnees,
BinaryDataStrategy.BASE_64_URL));
}
private static String serialiserBinaire(byte[] donnees, String strategie) {
JsonbConfig config = new JsonbConfig().withBinaryDataStrategy(strategie);
Jsonb jsonb = JsonbBuilder.create(config);
String result = jsonb.toJson(donnees);
return result;
}
}
Résultat : |
BYTE [108,47,87,-83,77,-1,3,-90,-111,95]
BASE_64 "bC9XrU3/A6aRXw=="
BASE_64_URL "bC9XrU3_A6aRXw=="
Internet JSON ou I-JSON est une spécification pour définir un profile sur l'utilisation de JSON afin de maximiser l'interopérabilité de l'exploitation des documents par des applications.
JSON-B propose un support de I-JSON par défaut à l'exception de trois recommandations :
Pour activer le support complet, il faut utiliser la méthode withStrictIJSON() avec la valeur true en paramètre de l'instance de type JsonbConfig utilisée pour configurer le moteur.
Exemple ( code Java 8 ) : |
// ...
JsonbConfig config = new JsonbConfig().withStrictIJSON(true);
Jsonb jsonb = JsonbBuilder.create(config);
// ...
Parfois, il n'est pas toujours possible d'utiliser des annotations pour personnaliser le binding, par exemple parce que le code source n'est pas disponible ou parce que les annotations proposées ne permettent pas de répondre aux besoins. Dans ces cas, il est possible d'utiliser un adaptateur pour tenter de répondre aux besoins.
Les adaptateurs de JSON-B fonctionnent de manière similaire à ceux proposés par JAX-B.
Un adaptateur est une classe qui implémente l'interface javax.json.bind.adapter.JsonbAdapter. L'interface JsonbAdapter<Original, Adapted> possède deux types génériques :
Elle définit deux méthodes :
Méthode |
Rôle |
Original adaptFromJson(Adapted obj) |
Cette méthode est invoquée uniquement lors de la désérialisation |
Adapted adaptToJson(Original obj) |
Cette méthode est invoquée uniquement lors de la sérialisation |
L'implémentation doit contenir les traitements pour créer une instance de type Adapted à partir d'une instance de type Original et vice versa. Cela permettra au moteur JSON-B de sérialiser/désérialiser le type Adapted à la place du type Original.
Exemple ( code Java 8 ) : |
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.bind.adapter.JsonbAdapter;
public class PersonneAdapter implements JsonbAdapter<Personne, JsonObject> {
@Override
public JsonObject adaptToJson(Personne pers) throws Exception {
return Json.createObjectBuilder()
.add("n", pers.getNom())
.add("p", pers.getPrenom())
.build();
}
@Override
public Personne adaptFromJson(JsonObject obj) throws Exception {
Personne p = new Personne();
p.setNom(obj.getString("n"));
p.setPrenom(obj.getString("p"));
return p;
}
}
Lors d'une sérialisation d'un objet de type Original, le moteur JSON-B invoque la méthode adaptToJson() de l'adaptateur pour obtenir une instance de type Adapted et la sérialiser.
Lors d'une désérialisation d'un objet de type Adapted, le moteur JSON-B invoque la méthode adaptFromJson() de l'adaptateur pour obtenir une instance de type Original et la retourner.
Il y a deux manières d'enregistrer un adaptateur pour qu'il soit pris en compte par le moteur :
Il est possible d'enregistrer globalement un adaptateur en utilisant la méthode withAdapters() de la classe JsonbConfig en lui passant une nouvelle instance de l'adaptateur en paramètre. L'adaptateur sera alors utilisé à chaque sérialisation/désérialisation d'un objet de type Original.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import java.time.Month;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = new JsonbConfig().withAdapters(new PersonneAdapter());
Jsonb jsonb = JsonbBuilder.create(config);
Personne pers = new Personne();
pers.setNom("nom");
pers.setPrenom("prenom");
pers.setTaille(175);
pers.setAdulte(true);
pers.setDateNaissance(LocalDate.of(1985, Month.AUGUST, 11));
String result = jsonb.toJson(pers);
System.out.println("result=" + result);
pers = jsonb.fromJson(result, Personne.class);
System.out.println("nom=" + pers.getNom());
System.out.println("dateNaissance=" + pers.getDateNaissance());
}
}
Pour utiliser l'adaptateur uniquement pour un champ, il est possible de l'annoter avec @JsonbTypeAdapter en lui précisant comme attribut le type de l'adaptateur.
Exemple ( code Java 8 ) : |
import javax.json.bind.annotation.JsonbTypeAdapter;
public class MonBean {
public String id = "1";
@JsonbTypeAdapter(PersonneAdapter.class)
public Personne personne;
}
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import java.time.Month;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
Personne pers = new Personne();
pers.setNom("nom");
pers.setPrenom("prenom");
pers.setTaille(175);
pers.setAdulte(true);
pers.setDateNaissance(LocalDate.of(1985, Month.AUGUST, 11));
MonBean monBean = new MonBean();
monBean.personne = pers;
String result = jsonb.toJson(monBean);
System.out.println("result=" + result);
monBean = jsonb.fromJson(result, MonBean.class);
System.out.println("nom=" + monBean.personne.getNom());
System.out.println("dateNaissance=" + monBean.personne.getDateNaissance());
}
}
Résultat : |
{
"date": "31/ago/2017",
"idCandidat": 123,
"idEpreuve": 456,
"note": 15.5
}
Les Serializers/Deserializers permettent d'avoir un contrôle de bas niveau sur les opérations de sérialisation/désérialisation grâce à une utilisation de JSON-P. Ils sont par exemple utiles lorsque les adaptateurs ne suffisent pas.
Un Serializer est une classe qui implémente l'interface javax.json.bind.serializers.JsonbSerializer.
Un Deserializer est une classe qui implémente l'interface javax.json.bind.serializers.JsonbDeserializer.
Il y a deux possibilités pour enregistrer un Serializer ou Deserializer :
L'interface JsonbSerializer<T> permet de personnaliser la sérialisation d'un objet de type T. Elle permet un contrôle très précis de la sérialisation en utilisant un objet de type JsonGenerator de l'API de type Stream de JSON-P.
L'interface JsonbSerializer<T> définit une seule méthode :
Méthode |
Rôle |
void serialize(T obj, javax.json.stream.JsonGenerator generator, SerializationContext ctx) |
Sérialiser l'objet passé en paramètre en utilisant l'API Stream de JSON-P |
L'implémentation de la méthode serialize() doit utiliser l'objet de type JsonGenerator pour créer le document JSON à partir de l'objet passé en paramètre.
Exemple ( code Java 8 ) : |
import javax.json.bind.serializer.JsonbSerializer;
import javax.json.bind.serializer.SerializationContext;
import javax.json.stream.JsonGenerator;
public class PersonneSerializer implements JsonbSerializer<Personne> {
@Override
public void serialize(Personne personne, JsonGenerator generator,
SerializationContext ctx) {
generator.writeStartObject();
generator.write("nom_s", personne.getNom());
generator.write("prenom_s", personne.getPrenom());
generator.writeEnd();
}
}
Dans les traitements de l'implémentation de la méthode serialize(), il est possible d'utiliser l'instance de type SerializationContext pour sérialiser un objet.
L'interface SerialisationContext propose deux méthodes pour faciliter la sérialisation d'un objet :
Méthode |
Rôle |
<T> void serialize(String key, T object, javax.json.stream.JsonGenerator generator) |
Sérialiser l'objet passé en paramètre en utilisant l'instance de type JsonGenerator sous la forme d'un attribut dont le nom est passé en paramètre |
<T> void serialize(T object, javax.json.stream.JsonGenerator generator) |
Sérialiser l'objet passé en paramètre en utilisant l'instance de type JsonGenerator sous la forme d'un tableau |
Pour utiliser le Serializer de manière globale, il faut en passer une instance en paramètre de la méthode withSerializer() de la classe JsonbConfig.
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import java.time.Month;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = new JsonbConfig()
.withSerializers(new PersonneSerializer());
Jsonb jsonb = JsonbBuilder.create(config);
Personne pers = new Personne();
pers.setNom("nom");
pers.setPrenom("prenom");
pers.setTaille(175);
pers.setAdulte(true);
pers.setDateNaissance(LocalDate.of(1985, Month.AUGUST, 11));
String result = jsonb.toJson(pers);
System.out.println(result);
}
}
Résultat : |
{"nom_s":"nom","prenom_s":"prenom"}
Il est aussi possible d'utiliser l'annotation @JsonbTypeSerializer en lui passant comme valeur la classe de l'implémentation du JsonbSerializer.
Exemple ( code Java 8 ) : |
import javax.json.bind.annotation.JsonbTypeSerializer;
public class MonBean {
public String id = "1";
@JsonbTypeSerializer(PersonneSerializer.class)
public Personne personne;
}
Exemple ( code Java 8 ) : |
import java.time.LocalDate;
import java.time.Month;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
MonBean monBean = new MonBean();
Personne pers = new Personne();
pers.setNom("nom");
pers.setPrenom("prenom");
pers.setTaille(175);
pers.setAdulte(true);
pers.setDateNaissance(LocalDate.of(1985, Month.AUGUST, 11));
monBean.id = "1";
monBean.personne = pers;
String result = jsonb.toJson(monBean);
System.out.println(result);
}
}
Résultat : |
{"id":"1","personne":{"nom_s":"nom","prenom_s":"prenom"}}
L'interface JsonbDeserializer<T> permet de personnaliser la désérialisation d'un objet de type T. Elle permet un contrôle très précis de la désérialisation en utilisant un objet de type JsonParser de l'API de type Stream de JSON-P.
L'interface JsonbDeserializer<T> définit une seule méthode :
Méthode |
Rôle |
T deserialize(javax.json.stream.JsonParser parser, DeserializationContext ctx, Type rtType) |
Désérialiser l'objet passé en paramètre en utilisant l'API Stream de JSON-P |
L'implémentation de la méthode deserialize() doit utiliser l'objet de type JsonParser pour extraire les données du document JSON et créer l'instance à retourner.
Exemple ( code Java 8 ) : |
import java.lang.reflect.Type;
import javax.json.bind.serializer.DeserializationContext;
import javax.json.bind.serializer.JsonbDeserializer;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
public class PersonneDeserializer implements JsonbDeserializer<Personne> {
@Override
public Personne deserialize(JsonParser parser, DeserializationContext ctx,
Type rtType) {
Personne result = new Personne();
while (parser.hasNext()) {
Event event = parser.next();
if (event == JsonParser.Event.KEY_NAME) {
String nomAttr = parser.getString();
parser.next();
if (nomAttr.equals("nom_s")) {
result.setNom(parser.getString());
} else if (nomAttr.equals("prenom_s")) {
result.setPrenom(parser.getString());
}
}
}
return result;
}
}
Dans les traitements de l'implémentation de la méthode deserialize(), il est possible d'utiliser l'instance de type DeserializationContext pour désérialiser un objet.
L'interface DeserializationContext propose deux méthodes pour faciliter la désérialisation d'un objet :
Méthode |
Rôle |
<T> T deserialize(Class<T> clazz, javax.json.stream.JsonParser parser) |
Désérialiser l'objet passé en paramètre en utilisant l'instance de type JsonParser |
<T> T deserialize(Type type, javax.json.stream.JsonParser parser) |
Désérialiser l'objet passé en paramètre en utilisant l'instance de type JsonParser |
Pour utiliser le Deserializer de manière globale, il faut en passer une instance en paramètre de la méthode withDeserializer() de la classe JsonbConfig.
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class TestJsonB {
public static void main(String[] args) {
JsonbConfig config = new JsonbConfig()
.withSerializers(new PersonneSerializer())
.withDeserializers(new PersonneDeserializer());
Jsonb jsonb = JsonbBuilder.create(config);
Personne pers = jsonb.fromJson("{\"nom_s\":\"nom1\",\"prenom_s\":\"prenom1\"}",
Personne.class);
System.out.println("nom =" + pers.getNom());
System.out.println("prenom=" + pers.getPrenom());
}
}
Résultat : |
nom =nom1
prenom=prenom1
Il est aussi possible d'utiliser l'annotation @JsonbTypeDeserializer en lui passant comme valeur la classe de l'implémentation du JsonbDeserializer.
Exemple ( code Java 8 ) : |
import javax.json.bind.annotation.JsonbTypeDeserializer;
import javax.json.bind.annotation.JsonbTypeSerializer;
public class MonBean {
public String id = "1";
@JsonbTypeSerializer(PersonneSerializer.class)
@JsonbTypeDeserializer(PersonneDeserializer.class)
public Personne personne;
}
Exemple ( code Java 8 ) : |
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class TestJsonB {
public static void main(String[] args) {
Jsonb jsonb = JsonbBuilder.create();
MonBean monBean = jsonb.fromJson(
"{\"id\":\"1\",\"personne\":{\"nom_s\":\"nom\",\"prenom_s\":\"prenom\"}}",
MonBean.class);
System.out.println("nom =" + monBean.personne.getNom());
System.out.println("prenom=" + monBean.personne.getPrenom());
}
}
Résultat : |
nom =nom
prenom=prenom