Afficher les derniers auteurs
1
2
3 {{code language="none"}}
4 {Sérialisation / desérialisation JSON}
5 {{/code}}
6
7 (((
8 = [[A. JSONProvider [jettison]>>doc:||anchor=jettison]]
9 [[B. JSONProvider [jackson>>doc:||anchor=jackson]]]
10 [[C. Possibilité de modifier certains attributs de sérialisation dans le code Adélia d'une classe>>doc:||anchor=directives_adelia]] ((% style="color: rgb(255,0,0);letter-spacing: -0.01em;" %)V13 PTF7 Fix01(%%)) =
11 )))
12 (((
13 =
14 {{id ="jettison" name="jettison"/}}A.JSONProvider [jettison] =
15 )))
16
17
18 Il est possible de paramétrer la sérialisation JSON des services REST à l'aide du fichier de configuration Spring "///WEB-INF/beans.xml//" en déclarant un //bean// Spring faisant référence à la classe (% style="color: rgb(0,0,255);" %)org.apache.cxf.jaxrs.provider.json.JSONProvider(%%) (//provider// fourni et utilisé par défaut par le framework CXF, ce provider s'appuie sur la librairie //Jettison// pour la sérialisation/desérialisation des classes java).
19
20 **Détail des propriétés du bean Spring :**
21 1. Par défaut, //jettison// sérialise les collections (tableaux) d'un seul élément non pas sous la forme d'un tableau JSON d'un seul élément mais sous la forme d'un élément seul.
22 Les propriétés **serializeAsArray** et **arraysKeys** permettent de sérialiser une collection d'un seul élément sous forme d'un tableau. Il est cependant nécessaire de préciser explicitement les noms des collections concernées.
23
24 Exemple : L'exemple ci-dessous présente la sérialisation d'une classe nommée "**STRUCTURE**" contenant 2 collections, l'une nommée "**(% style="color: rgb(0,51,102);" %)dimensions_lst(%%)**" et l'autre nommée "**measures_lst**".
25 La collection "**dimensions_lst**" contient 2 éléments et est sérialisée par défaut comme un tableau.
26 La collection "**measures_lst**" ne contient qu'un seul élément et est sérialisée comme un simple élément.
27
28
29 {{code language="none"}}
30 {
31 "STRUCTURE": {
32 "dimensions_lst": [{
33 "dimensionId": 1,
34 "description": "d1"
35 }, {
36 "dimensionId": 2,
37 "description": "d2"
38 }],
39 "measures_lst": {
40 "measureId": 1,
41 "description": "d1"
42 }
43 }
44 }
45 {{/code}}
46
47
48
49 Paramétrage du bean JSONProvider pour changer la sérialisation de la collection nommée "**measures_lst**"
50
51
52 {{code language="none"}}
53 <bean class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
54 <property name="serializeAsArray" value="true"/>
55 <property name="arrayKeys">
56 <list>
57 <value>measures_lst</value>
58 </list>
59 </property>
60 </bean>
61 {{/code}}
62
63
64
65 L'application de la configuration présentée ci-dessus permet de sérialiser la collection "**(% style="color: rgb(0,51,102);" %)measures_lst(%%)**" sous la forme d'un tableau JSON (utilisatiion des 'brackets' []).
66
67
68 {{code language="none"}}
69 {
70 "STRUCTURE": {
71 "dimensions_lst": [{
72 "dimensionId": 1,
73 "description": "d1"
74 }, {
75 "dimensionId": 2,
76 "description": "d2"
77 }],
78 "measures_lst": [{
79 "measureId": 1,
80 "description": "d1"
81 }]
82 }
83 }
84 {{/code}}
85
86
87
88 1. La propriété **dropRootElement** permet de supprimer l'élément racine.
89 Par défaut, l'élément racine (nom de la classe "STRUCTURE") est présent dans la sérialisation JSON.
90
91 Paramétrage du bean JSONProvider pour supprimer l'élément racine de la sérialisation de la classe.
92
93
94 {{code language="none"}}
95 <bean class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
96 <property name="dropRootElement" value="true"/>
97 </bean>
98 {{/code}}
99
100
101
102 L'application de la configuration présentée ci-dessus permet de supprimer l'élément racine "**STRUCTURE**" de la sérialisation.
103
104
105 {{code language="none"}}
106 {
107 "dimensions_lst": [{
108 "dimensionId": 1,
109 "description": "d1"
110 }, {
111 "dimensionId": 2,
112 "description": "d2"
113 }],
114 "measures_lst": [{
115 "measureId": 1,
116 "description": "d1"
117 }]
118 }
119 {{/code}}
120
121
122
123 Dans le même ordre d'idée, mais dans le cadre de la desérialisation JSON en entrée du service, il est possible de d'accepter des objets JSON sans élément racine, à l'aide de la propriété :
124
125 <property name~="**supportUnwrapped**" value~="true" />
126
127
128 1. Convention //badgerfish//
129
130
131
132 {{code language="none"}}
133 <property name="convention" value="badgerfish" />
134 {{/code}}
135
136
137
138 Exemple:
139
140
141 {{code language="none"}}
142 {
143 "STRUCTURE": {
144 "dimensions_lst": [{
145 "dimensionId": {
146 "$": "1"
147 },
148 "description": {
149 "$": "d1"
150 }
151 }, {
152 "dimensionId": {
153 "$": "2"
154 },
155 "description": {
156 "$": "d2"
157 }
158 }],
159 "measures_lst": {
160 "measureId": {
161 "$": "1"
162 },
163 "description": {
164 "$": "d1"
165 }
166 }
167 }
168 }
169 {{/code}}
170
171
172
173 1. Autres propriétés
174 - ignoreNamespaces
175 - writeXsiType / readXsiType
176 - ignoreMixedContent
177 - ignoreEmptyArrayValues
178 - writeNullAsString
179
180
181
182 {{hardis-info type="tip" icon="true"}}
183 Ce paramétrage peut-être externalisé grâce à une ressource JNDI désignant un fichier de propriétés : [[Services web REST - Externalisation de la configuration>>doc:ADELIAWIKI.111149831.112525754.113311769.165680011.193956367.WebHome]]
184 {{/hardis-info}}
185
186
187 {{id ="jackson" name="jackson"/}}(((
188 = B. JSONProvider [jackson : JacksonJaxbJsonProvider] =
189 )))
190
191 Il est possible de changer le JSONProvider par défaut par un provider s'appuyant non plus sur la librairie //Jettison// mais sur la librairie J//ackson//.
192 Le comportement par défaut de la librairie //Jackson// diffère de celle de //Jettison// en plusieurs points.
193 * droptRootElement est actif par défaut.
194 * les collections contenant un seul élément sont sérialisées par défaut en un 1 tableau JSON et non comme un élément seul
195 * le type IMAGE n'est pas sérialisé de façon identique avant la PTF 07 FIX 01. A partir de la PTF 07 Fix 01 Jackson et Jettison sérialisent le type IMAGE de la même façon.
196
197
198
199 Pour utiliser un JSONProvider s'appuyant sur la librairie //Jackson// et sur les annotations JAXB et Jackson générées dans les classes, il faut modifier le fichier //WEB-INF/beans.xml// de la sorte :
200
201
202 {{code language="none"}}
203 <bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
204 {{/code}}
205
206
207 et déployer les librairies //jackson-jaxrs-1.9.x.jar//, //jackson-core-asl-1.9.x.jar, //jackson-xc-1.9.x.jar et jackson-mapper-asl-1.9.x.jar. //Ces bibliothèques sont fournies directement à partir de la V13 PTF08 FIX01.
208 Ces librairies peuvent éventuellement être tirées par la dépendance Maven suivante// ://
209
210
211 {{code language="none"}}
212 <dependency>
213 <groupId>org.codehaus.jackson</groupId>
214 <artifactId>jackson-jaxrs</artifactId>
215 <version>1.9.x</version>
216 </dependency>
217
218 <dependency>
219 <groupId>org.codehaus.jackson</groupId>
220 <artifactId>jackson-xc</artifactId>
221 <version>1.9.x</version>
222 </dependency>
223
224 {{/code}}
225
226 (((
227 = ((% style="color: rgb(255,0,0);" %)V14(%%)) =
228 )))
229
230 A partir de cette version, la librairie Jackson devient la librairie utilisée par défaut. Le fichier //beans.xml//// //de référence a été modifié afin que les sites web Adélia nouvellement créés utilisent la librairie Jackson en standard.
231 (((
232 = ((% style="color: rgb(255,0,0);" %)V14.2.0(%%)) =
233 )))
234
235 La librairie Jackson utilisée par défaut est désormais **com.fasterxml.jackson.jaxrs.JacksonJaxbJsonProvider. **Cette librairie assure d'une part une sérialisation optimale des attributs de classe de type table dynamique (application du TRIM) et d'autre part une homogénéité (sérialisation et desérialisation) avec l'ordre CONV_DONNEES.**
236
237 **Pour utiliser le nouveau JacksonJaxbJsonProvider il faut déclarer - dans le fichier //beans.xml// - les 2 entrées suivantes :
238
239
240 {{code language="none"}}
241 <cxf:bus>
242 <cxf:properties>
243 <entry key="skip.default.json.provider.registration" value="true"/>
244 </cxf:properties>
245 </cxf:bus>
246
247
248 <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider"/>
249 {{/code}}
250
251 (((
252 = ((% style="color: rgb(255,0,0);" %)V14.3.2(%%)) Modification du httpStatus par défaut lié à une erreur de parsage en entrée d'un document JSON =
253 )))
254
255
256 Par défaut, une erreur de parsage d'un document JSON retourne un **httpStatus** égal à **500** (internal server error).
257 Il est possible de modifier ce **httpStatus** en déclararant des '**//ExceptionMappe//r**' dans le fichier //beans.xml.
258 //Pour ce faire 2 //'ExceptionMapper'// disctincts sont disponibles :
259 * //JsonUnrecognizedPropertyExceptionMapper : cas d'un attribut non reconnu dans le modèle.
260 //
261 * //JsonParseExceptionMapper : cas d'un document json non valide.
262 //
263 **Pré-requis** : utilisation du provider Json "//com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider//". Cf. Paragraphe précédent.
264
265
266
267
268
269 {{code language="none"}}
270 /* La simple déclaration du bean JsonUnrecognizedPropertyExceptionMapper permet de
271 fixer un httpStatus à 400 (bad request) dans le cas d'un attribut json non reconnu.
272 Le format par défaut de la réponse est du 'text/plain'.*/
273 <bean class="com.hardis.adelia.webservice.exception.JsonUnrecognizedPropertyExceptionMapper"/>
274
275 /* Possibilité de choisir la valeur du httpStatus (parmi les valeurs valides) et du
276 format de la réponse à l'aide, respectivement, des propriétés 'httpStatus' et 'mediaType'.
277 Exemple :
278 - httpStatus retourné = 417
279 - format de la réponse : application/json */
280 <bean class="com.hardis.adelia.webservice.exception.JsonUnrecognizedPropertyExceptionMapper">
281 <property name="httpStatus" value="417" />
282 <property name="mediaType" value="application/json" />
283 </bean>
284
285
286 /* La simple déclaration du bean JsonParseExceptionMapper permet de
287 fixer un httpStatus à 400 (bad request) dans le cas d'une erreur de parsage
288 du document json.
289 Le format par défaut de la réponse est du 'text/plain'.*/
290 <bean class="com.hardis.adelia.webservice.exception.JsonParseExceptionMapper"/>
291
292 /* Possibilité de choisir la valeur du httpStatus (parmi les valeurs valides) et du
293 format de la réponse à l'aide, respectivement, des propriétés 'httpStatus' et 'mediaType'.
294 Exemple :
295 - httpStatus retourné = 417
296 - format de la réponse : application/json */
297 <bean class="com.hardis.adelia.webservice.exception.JsonParseExceptionMapper">
298 <property name="httpStatus" value="417" />
299 <property name="mediaType" value="application/json" />
300 </bean>
301 {{/code}}
302
303
304
305
306 (((
307 = ((% style="color: rgb(255,0,0);" %)V14.4.0(%%)) Paramétrage de la sérialisation/desérialisation JSON [**com.fasterxml.jackson.jaxrs.JacksonJaxbJsonProvider**] =
308 )))
309
310 Possibilité de paramétrer la sérialisation/desérialisation JSON basées sur la librairie Jackson pour le provider com.fasterxml.jackson.jaxrs.JacksonJaxbJsonProvider
311
312
313 * La liste des propriétés (description et valeur par défaut) liées à la sérialisation est disponible ici : [[https://github.com/FasterXML/jackson-databind/wiki/Serialization-features>>url:https://github.com/FasterXML/jackson-databind/wiki/Serialization-features]]
314 * La liste des propriétés (description et valeur par défaut) liées à la desérialisation est disponible ici : [[https://github.com/FasterXML/jackson-databind/wiki/Deserialization-features>>url:https://github.com/FasterXML/jackson-databind/wiki/Deserialization-features]]
315
316
317 Il faut déclarer un bean de type //com.hardis.adelia.webservice.CustomObjectMapper// avec les propriétés à fixer.
318 Il faut ensuite passer ce bean en paramètre du constructeur du //JacksonJaxbJsonProvider//.
319
320 Remarque : d'une part les noms des propriétés suivent une notation de style "camel case". D'autre part,
321 * les propriétés 'SerializationFeature' sont préfixées par **Ser.**
322 * les propriétés 'DeserializationFeature' sont préfixées par **Deser.
323 **
324
325
326 Exemple : //DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES// devient //DeserFailOnUnknownProperties//
327
328
329 L'exemple ci-dessous permet d'éviter les erreurs de desérialisation liées aux propriétés Json non reconnues. [Propriété //DeserFailOnUnknownProperties//]
330
331
332 {{code title="Beans.xml" language="none"}}
333 <bean id="customJacksonMapper" class="com.hardis.adelia.webservice.CustomObjectMapper" init-method="init">
334 <property name="DeserFailOnUnknownProperties" value="false" />
335 </bean>
336
337 <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider">
338 <constructor-arg index="0" ref="customJacksonMapper" />
339 <constructor-arg index="1"><null /></constructor-arg>
340 </bean>
341 {{/code}}
342
343 (((
344 = ((% style="color: rgb(255,0,0);" %)V14.6.0(%%)) Ajout de la propriété de sérialisation //SerInclusion// =
345 )))
346
347 Cette propriété joue sur l'inclusion des éléments à sérialiser en fonction des valeurs suivantes :
348 * (% style="color: rgb(36,36,36);" %)**Always** (default) : Value that indicates that property is to be always included, independent of value of the property.(%%)
349 * (% style="color: rgb(36,36,36);" %)**NonAbsent** : Value that indicates that properties are included unless their value is: null "absent" value of a referential type (like Java 8 `Optional`, or {link java.utl.concurrent.atomic.AtomicReference}); that is, something that would not deference to a non-null value.
350 (%%)
351 * (% style="color: rgb(36,36,36);" %)**NonDefault** : Meaning of this setting depends on context: whether annotation is specified for POJO type (class), or not.
352 (%%)
353 * (% style="color: rgb(36,36,36);" %)**NonEmpty** : Value that indicates that only properties with null value, or what is considered empty, are not to be included.
354 (%%)
355 * (% style="color: rgb(36,36,36);" %)**NonNull** : Value that indicates that only properties with non-null values are to be included.
356 (%%)
357 * (% style="color: rgb(36,36,36);" %)**UseDefaults** : Pseudo-value used to indicate that the higher-level defaults make sense, to avoid overriding inclusion value.
358 (%%)
359 (% style="color: rgb(36,36,36);" %)La valeur //NonNull// permet notamment de revenir au comportement par défaut de l'ancienne implémentation //org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider//
360 (%%)
361
362
363 Exemple :
364
365
366 {{code title="Beans.xml" language="none"}}
367 <bean id="customJacksonMapper" class="com.hardis.adelia.webservice.CustomObjectMapper" init-method="init">
368 <property name="SerInclusion" value="NonNull" />
369 </bean>
370
371 <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider">
372 <constructor-arg index="0" ref="customJacksonMapper" />
373 <constructor-arg index="1"><null /></constructor-arg>
374 </bean>
375 {{/code}}
376
377
378 {{id ="directives_adelia" name="directives_adelia"/}}
379 (((
380 = C. Possibilité de modifier certains attributs de sérialisation dans le code Adélia d'une classe =
381 )))
382
383 Des directives de sérialisation sont disponibles dans le source Adélia d'une classe.
384 (((
385 = ((% style="color: rgb(255,0,0);" %)V13 PTF7 Fix01(%%)) =
386 )))
387
388 ***SER_NOM**('nom') : définition d'un nom externe pour le membre d'une classe.
389 ***SER_FACULTATIF**[('ValeurDef')] : Par défaut, un membre est exposé comme obligatoire. La directive qualifie le membre comme optionnel. La valeur par défaut (si précisée) est utilisée pour la désérialisation.
390 ***SER_MODE(***VERBEUX) : S'applique à un membre de type IMAGE. La sérialisation (à partir du Fix01) du type IMAGE est réduit à une simple chaine encodée en base64, le mode *VERBEUX restitue la sérialisation à ce qu'elle était avant le fix01 de la PTF07.
391
392 Exemple :
393
394
395 {{code language="none"}}
396 *ATTRIBUTS
397 {
398 NUM_BIN_2 Name *SER_NOM('Nom');
399 ALPHA(50) Address *SER_NOM('Adresse') *SER_FACULTATIF('75000 Paris');
400 IMAGE Picture *SER_MODE(*VERBEUX);
401 }
402 {{/code}}
403
404
405 (((
406 = ((% style="color: rgb(255,0,0);" %)V13 PTF9(%%)) =
407 )))
408
409 ***SER_NOM**('nom') : définition d'un nom externe pour la classe.
410 ***SER_DESC**('description') : définition d'une description pour la classe ou un membre de la classe. Dans l'optique d'une présentation via swagger.
411 ***SER_EXEMPLE**('ValeurExemple') : définition d'une valeur exemple pour un membre de la classe. Dans l'optique d'une présentation via swagger.
412
413 Exemple :
414
415
416 {{code language="none"}}
417 *ATTRIBUTS *SER_NOM('Personne') *SER_DESC('Définition d''une personne')
418 {
419 ALPHA(32) Name *SER_NOM('Nom') *SER_EXEMPLE('DUPONT') *SER_DESC('Nom de la personne');
420 ALPHA(50) Address *SER_NOM('Adresse') *SER_EXEMPLE('Rue des Martyrs - 75000 Paris') *SER_DESC('Adresse postale de la personne');
421 IMAGE Picture *SER_MODE(*VERBEUX) *SER_DESC('Photo d''identité');
422 }
423 {{/code}}
424
425
426
427 **Exemple de présentation d'un modèle (classe) dans swagger-ui
428 [[image:image2018-3-30 16:22:35.png||height="250"]]**
429
430
431
432
433