View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.oapi;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.httppart.HttpPartSchema.*;
21  import static org.apache.juneau.internal.DateUtils.*;
22  import static org.junit.jupiter.api.Assertions.*;
23  
24  import java.util.*;
25  
26  import org.apache.juneau.*;
27  import org.apache.juneau.collections.*;
28  import org.apache.juneau.httppart.*;
29  import org.apache.juneau.serializer.*;
30  import org.junit.jupiter.api.*;
31  
32  import jakarta.xml.bind.*;
33  
34  /**
35   * Tests the OpenApiSerializer and OpenApiParser classes.
36   */
37  public class OpenApi_Test extends TestBase {
38  
39  	public static final OpenApiSerializer DS = OpenApiSerializer.DEFAULT;
40  	public static final OpenApiParser DP = OpenApiParser.DEFAULT;
41  
42  	private String serialize(HttpPartSchema schema, Object in) throws Exception {
43  		return DS.serialize(null, schema, in);
44  	}
45  
46  	private <T> T parse(HttpPartSchema schema, String in, Class<T> c, Class<?>...args) throws Exception {
47  		return DP.parse(null, schema, in, DP.getClassMeta(c, args));
48  	}
49  
50  	@BeforeEach void before() {
51  		setTimeZone("GMT");
52  	}
53  
54  	@AfterEach void after() {
55  		unsetTimeZone();
56  	}
57  
58  	//------------------------------------------------------------------------------------------------------------------
59  	// Type == NO_TYPE
60  	//------------------------------------------------------------------------------------------------------------------
61  
62  	@Test void a01a_noType_formatDefault() throws Exception {
63  		var in = "foo";
64  		var ps = T_NONE;
65  		var s = serialize(ps, in);
66  		assertEquals("foo", s);
67  		var r = parse(ps, s, String.class);
68  		assertEquals(in, r);
69  	}
70  
71  	@Test void a01b_noType_formatDefault_null() throws Exception {
72  		var in = n(String.class);
73  		var ps = T_NONE;
74  		var s = serialize(ps, in);
75  		assertEquals("null", s);
76  	}
77  
78  	@Test void a02a_noType_formatByte() throws Exception {
79  		var in = "foo";
80  		var ps = tNone().fByte().build();
81  		var s = serialize(ps, in);
82  		assertEquals("Zm9v", s);
83  		var r = parse(ps, s, String.class);
84  		assertEquals(in, r);
85  	}
86  
87  	@Test void a02b_noType_formatByte_null() throws Exception {
88  		var in = n(String.class);
89  		var ps = tNone().fByte().build();
90  		var s = serialize(ps, in);
91  		assertEquals("null", s);
92  	}
93  
94  	@Test void a03a_noType_formatBinary() throws Exception {
95  		var in = "foo";
96  		var ps = tNone().fBinary().build();
97  		var s = serialize(ps, in);
98  		assertEquals("666F6F", s);
99  		var r = parse(ps, s, String.class);
100 		assertEquals(in, r);
101 	}
102 
103 	@Test void a03b_noType_formatBinary_null() throws Exception {
104 		var in = n(String.class);
105 		var ps = tNone().fBinary().build();
106 		var s = serialize(ps, in);
107 		assertEquals("null", s);
108 		var r = parse(ps, s, String.class);
109 		assertEquals(in, r);
110 	}
111 
112 	@Test void a04a_noType_formatBinarySpaced() throws Exception {
113 		var in = "foo";
114 		var ps = tNone().fBinarySpaced().build();
115 		var s = serialize(ps, in);
116 		assertEquals("66 6F 6F", s);
117 		var r = parse(ps, s, String.class);
118 		assertEquals(in, r);
119 	}
120 
121 	@Test void a04b_noType_formatBinarySpaced_null() throws Exception {
122 		var in = n(String.class);
123 		var ps = tNone().fBinarySpaced().build();
124 		var s = serialize(ps, in);
125 		assertEquals("null", s);
126 		var r = parse(ps, s, String.class);
127 		assertEquals(in, r);
128 	}
129 
130 	@Test void a05_noType_formatDate_String() throws Exception {
131 		var in = "2012-12-21";
132 		var ps = tNone().fDate().build();
133 		var s = serialize(ps, in);
134 		assertEquals("2012-12-21", s);
135 		var r = parse(ps, s, String.class);
136 		assertEquals(in, r);
137 	}
138 
139 	@Test void a06_noType_formatDate_Calendar() throws Exception {
140 		var in = cal("2012-12-21");
141 		var ps = tNone().fDate().build();
142 		var s = serialize(ps, in);
143 		assertEquals("2012-12-21Z", s);
144 		var r = parse(ps, s, Calendar.class);
145 		s = serialize(ps, r);
146 		assertEquals("2012-12-21Z", s);
147 	}
148 
149 	@Test void a07_noType_formatDate_Date() throws Exception {
150 		var in = cal("2012-12-21").getTime();
151 		var ps = tNone().fDate().build();
152 		var s = serialize(ps, in);
153 		assertEquals("2012-12-21Z", s);
154 		var r = parse(ps, s, Calendar.class);
155 		s = serialize(ps, r);
156 		assertEquals("2012-12-21Z", s);
157 	}
158 
159 	@Test void a08_noType_formatDate_Temporal() throws Exception {
160 		var in = cal("2012-12-21").toInstant();
161 		var ps = tNone().fDate().build();
162 		var s = serialize(ps, in);
163 		assertEquals("2012-12-21Z", s);
164 		var r = parse(ps, s, Calendar.class);
165 		s = serialize(ps, r);
166 		assertEquals("2012-12-21Z", s);
167 	}
168 
169 	@Test void a09_noType_formatDate_Other() throws Exception {
170 		var in = new StringBuilder("2012-12-21");
171 		var ps = tNone().fDate().build();
172 		var s = serialize(ps, in);
173 		assertEquals("2012-12-21", s);
174 		var r = parse(ps, s, String.class);
175 		assertEquals(in.toString(), r);
176 	}
177 
178 	@Test void a10_noType_formatDate_null() throws Exception {
179 		var in = n(String.class);
180 		var ps = tNone().fDate().build();
181 		var s = serialize(ps, in);
182 		assertEquals("null", s);
183 		var r = parse(ps, s, String.class);
184 		assertEquals(null, r);
185 	}
186 
187 	@Test void a11_noType_formatDateTime_String() throws Exception {
188 		var in = "2012-12-21T00:00:00";
189 		var ps = tNone().fDateTime().build();
190 		var s = serialize(ps, in);
191 		assertEquals("2012-12-21T00:00:00", s);
192 		var r = parse(ps, s, String.class);
193 		assertEquals(in, r);
194 	}
195 
196 	@Test void a12_noType_formatDateTime_Calendar() throws Exception {
197 		var in = cal("2012-12-21");
198 		var ps = tNone().fDateTime().build();
199 		var s = serialize(ps, in);
200 		assertEquals("2012-12-21T00:00:00Z", s);
201 		var r = parse(ps, s, Calendar.class);
202 		s = serialize(ps, r);
203 		assertEquals("2012-12-21T00:00:00Z", s);
204 	}
205 
206 	@Test void a13_noType_formatDateTime_Date() throws Exception {
207 		var in = cal("2012-12-21").getTime();
208 		var ps = tNone().fDateTime().build();
209 		var s = serialize(ps, in);
210 		assertEquals("2012-12-21T00:00:00Z", s);
211 		var r = parse(ps, s, Calendar.class);
212 		s = serialize(ps, r);
213 		assertEquals("2012-12-21T00:00:00Z", s);
214 	}
215 
216 	@Test void a14_noType_formatDateTime_Temporal() throws Exception {
217 		var in = cal("2012-12-21").toInstant();
218 		var ps = tNone().fDateTime().build();
219 		var s = serialize(ps, in);
220 		assertEquals("2012-12-21T00:00:00Z", s);
221 		var r = parse(ps, s, Calendar.class);
222 		s = serialize(ps, r);
223 		assertEquals("2012-12-21T00:00:00Z", s);
224 	}
225 
226 	@Test void a15_noType_formatDate_Other() throws Exception {
227 		var in = new StringBuilder("2012-12-21T00:00:00");
228 		var ps = tNone().fDateTime().build();
229 		var s = serialize(ps, in);
230 		assertEquals("2012-12-21T00:00:00", s);
231 		var r = parse(ps, s, String.class);
232 		assertEquals(in.toString(), r);
233 	}
234 
235 	@Test void a16_noType_formatDate_null() throws Exception {
236 		var in = n(String.class);
237 		var ps = tNone().fDateTime().build();
238 		var s = serialize(ps, in);
239 		assertEquals("null", s);
240 		var r = parse(ps, s, String.class);
241 		assertEquals(null, r);
242 	}
243 
244 	@Test void a17_noType_formatUon() throws Exception {
245 		var in = "foo,bar";
246 		var ps = tNone().fUon().build();
247 		var s = serialize(ps, in);
248 		assertEquals("'foo,bar'", s);
249 		var r = parse(ps, s, String.class);
250 		assertEquals(in, r);
251 	}
252 
253 	//------------------------------------------------------------------------------------------------------------------
254 	// Type == STRING
255 	//------------------------------------------------------------------------------------------------------------------
256 
257 	@Test void b01_typeString_formatDefault() throws Exception {
258 		var in = "foo";
259 		var ps = T_STRING;
260 		var s = serialize(ps, in);
261 		assertEquals("foo", s);
262 		var r = parse(ps, s, String.class);
263 		assertEquals(in, r);
264 	}
265 
266 	@Test void b02_typeString_formatByte() throws Exception {
267 		var in = "foo";
268 		var ps = T_BYTE;
269 		var s = serialize(ps, in);
270 		assertEquals("Zm9v", s);
271 		var r = parse(ps, s, String.class);
272 		assertEquals(in, r);
273 	}
274 
275 	@Test void b03_typeString_formatBinary() throws Exception {
276 		var in = "foo";
277 		var ps = T_BINARY;
278 		var s = serialize(ps, in);
279 		assertEquals("666F6F", s);
280 		var r = parse(ps, s, String.class);
281 		assertEquals(in, r);
282 	}
283 
284 	@Test void b04_typeString_formatBinarySpaced() throws Exception {
285 		var in = "foo";
286 		var ps = T_BINARY_SPACED;
287 		var s = serialize(ps, in);
288 		assertEquals("66 6F 6F", s);
289 		var r = parse(ps, s, String.class);
290 		assertEquals(in, r);
291 	}
292 
293 	@Test void b05_typeString_formatDate_String() throws Exception {
294 		var in = "2012-12-21";
295 		var ps = T_DATE;
296 		var s = serialize(ps, in);
297 		assertEquals("2012-12-21", s);
298 		var r = parse(ps, s, String.class);
299 		assertEquals(in, r);
300 	}
301 
302 	@Test void b06_typeString_formatDate_Calendar() throws Exception {
303 		var in = cal("2012-12-21");
304 		var ps = T_DATE;
305 		var s = serialize(ps, in);
306 		assertEquals("2012-12-21Z", s);
307 		var r = parse(ps, s, Calendar.class);
308 		s = serialize(ps, r);
309 		assertEquals("2012-12-21Z", s);
310 	}
311 
312 	@Test void b07_typeString_formatDate_Date() throws Exception {
313 		var in = cal("2012-12-21").getTime();
314 		var ps = T_DATE;
315 		var s = serialize(ps, in);
316 		assertEquals("2012-12-21Z", s);
317 		var r = parse(ps, s, Calendar.class);
318 		s = serialize(ps, r);
319 		assertEquals("2012-12-21Z", s);
320 	}
321 
322 	@Test void b08_typeString_formatDate_Temporal() throws Exception {
323 		var in = cal("2012-12-21").toInstant();
324 		var ps = T_DATE;
325 		var s = serialize(ps, in);
326 		assertEquals("2012-12-21Z", s);
327 		var r = parse(ps, s, Calendar.class);
328 		s = serialize(ps, r);
329 		assertEquals("2012-12-21Z", s);
330 	}
331 
332 	@Test void b09_typeString_formatDate_Other() throws Exception {
333 		var in = new StringBuilder("2012-12-21");
334 		var ps = T_DATE;
335 		var s = serialize(ps, in);
336 		assertEquals("2012-12-21", s);
337 		var r = parse(ps, s, String.class);
338 		assertEquals(in.toString(), r);
339 	}
340 
341 	@Test void b10_typeString_formatDate_null() throws Exception {
342 		var in = n(String.class);
343 		var ps = T_DATE;
344 		var s = serialize(ps, in);
345 		assertEquals("null", s);
346 		var r = parse(ps, s, String.class);
347 		assertEquals(null, r);
348 	}
349 
350 	@Test void b11_typeString_formatDateTime_String() throws Exception {
351 		var in = "2012-12-21T00:00:00";
352 		var ps = T_DATETIME;
353 		var s = serialize(ps, in);
354 		assertEquals("2012-12-21T00:00:00", s);
355 		var r = parse(ps, s, String.class);
356 		assertEquals(in, r);
357 	}
358 
359 	@Test void b12_typeString_formatDateTime_Calendar() throws Exception {
360 		var in = cal("2012-12-21");
361 		var ps = T_DATETIME;
362 		var s = serialize(ps, in);
363 		assertEquals("2012-12-21T00:00:00Z", s);
364 		var r = parse(ps, s, Calendar.class);
365 		s = serialize(ps, r);
366 		assertEquals("2012-12-21T00:00:00Z", s);
367 	}
368 
369 	@Test void b13_typeString_formatDateTime_Date() throws Exception {
370 		var in = cal("2012-12-21").getTime();
371 		var ps = T_DATETIME;
372 		var s = serialize(ps, in);
373 		assertEquals("2012-12-21T00:00:00Z", s);
374 		var r = parse(ps, s, Calendar.class);
375 		s = serialize(ps, r);
376 		assertEquals("2012-12-21T00:00:00Z", s);
377 	}
378 
379 	@Test void b14_typeString_formatDateTime_Temporal() throws Exception {
380 		var in = cal("2012-12-21").toInstant();
381 		var ps = T_DATETIME;
382 		var s = serialize(ps, in);
383 		assertEquals("2012-12-21T00:00:00Z", s);
384 		var r = parse(ps, s, Calendar.class);
385 		s = serialize(ps, r);
386 		assertEquals("2012-12-21T00:00:00Z", s);
387 	}
388 
389 	@Test void b15_typeString_formatDate_Other() throws Exception {
390 		var in = new StringBuilder("2012-12-21T00:00:00");
391 		var ps = T_DATETIME;
392 		var s = serialize(ps, in);
393 		assertEquals("2012-12-21T00:00:00", s);
394 		var r = parse(ps, s, String.class);
395 		assertEquals(in.toString(), r);
396 	}
397 
398 	@Test void b16_typeString_formatDate_null() throws Exception {
399 		var in = n(String.class);
400 		var ps = T_DATETIME;
401 		var s = serialize(ps, in);
402 		assertEquals("null", s);
403 		var r = parse(ps, s, String.class);
404 		assertEquals(null, r);
405 	}
406 
407 	//------------------------------------------------------------------------------------------------------------------
408 	// Type == BOOLEAN
409 	//------------------------------------------------------------------------------------------------------------------
410 
411 	@Test void c01_typeBoolean_formatDefault_String() throws Exception {
412 		var in = "true";
413 		var ps = T_BOOLEAN;
414 		var s = serialize(ps, in);
415 		assertEquals("true", s);
416 		var r = parse(ps, s, String.class);
417 		assertEquals(in, r);
418 	}
419 
420 	@Test void c02_typeBoolean_formatDefault_Boolean() throws Exception {
421 		var in = true;
422 		var ps = T_BOOLEAN;
423 		var s = serialize(ps, in);
424 		assertEquals("true", s);
425 		var r = parse(ps, s, Boolean.class);
426 		assertEquals(in, r);
427 	}
428 
429 	//------------------------------------------------------------------------------------------------------------------
430 	// Type == INTEGER
431 	//------------------------------------------------------------------------------------------------------------------
432 
433 	@Test void d01_typeInteger_formatDefault_String() throws Exception {
434 		var in = "123";
435 		var ps = T_INTEGER;
436 		var s = serialize(ps, in);
437 		assertEquals("123", s);
438 		var r = parse(ps, s, String.class);
439 		assertEquals(in, r);
440 	}
441 
442 	@Test void d02_typeInteger_formatDefault_Integer() throws Exception {
443 		var in = (Integer)123;
444 		var ps = T_INTEGER;
445 		var s = serialize(ps, in);
446 		assertEquals("123", s);
447 		var r = parse(ps, s, Integer.class);
448 		assertEquals(in, r);
449 	}
450 
451 	@Test void d03_typeInteger_formatInt32_String() throws Exception {
452 		var in = "123";
453 		var ps = T_INT32;
454 		var s = serialize(ps, in);
455 		assertEquals("123", s);
456 		var r = parse(ps, s, String.class);
457 		assertEquals(in, r);
458 	}
459 
460 	@Test void d04_typeInteger_formatInt32_Integer() throws Exception {
461 		var in = (Integer)123;
462 		var ps = T_INT32;
463 		var s = serialize(ps, in);
464 		assertEquals("123", s);
465 		var r = parse(ps, s, Integer.class);
466 		assertEquals(in, r);
467 	}
468 
469 	@Test void d05_typeInteger_formatInt64_String() throws Exception {
470 		var in = "123";
471 		var ps = T_INT64;
472 		var s = serialize(ps, in);
473 		assertEquals("123", s);
474 		var r = parse(ps, s, String.class);
475 		assertEquals(in, r);
476 	}
477 
478 	@Test void d06_typeInteger_formatInt64_Long() throws Exception {
479 		var in = (Long)123L;
480 		var ps = T_INT64;
481 		var s = serialize(ps, in);
482 		assertEquals("123", s);
483 		var r = parse(ps, s, Long.class);
484 		assertEquals(in, r);
485 	}
486 
487 	//------------------------------------------------------------------------------------------------------------------
488 	// Type == NUMBER
489 	//------------------------------------------------------------------------------------------------------------------
490 
491 	@Test void e01_tNumberDefault_String() throws Exception {
492 		var in = "123";
493 		var ps = T_NUMBER;
494 		var s = serialize(ps, in);
495 		assertEquals("123.0", s);
496 		var r = parse(ps, s, String.class);
497 		assertEquals("123.0", r);
498 	}
499 
500 	@Test void e02_tNumberDefault_Float() throws Exception {
501 		var in = (Float)123f;
502 		var ps = T_NUMBER;
503 		var s = serialize(ps, in);
504 		assertEquals("123.0", s);
505 		var r = parse(ps, s, Float.class);
506 		assertEquals(in, r);
507 	}
508 
509 	@Test void e03_tNumberFloat_String() throws Exception {
510 		var in = "123";
511 		var ps = T_FLOAT;
512 		var s = serialize(ps, in);
513 		assertEquals("123.0", s);
514 		var r = parse(ps, s, String.class);
515 		assertEquals("123.0", r);
516 	}
517 
518 	@Test void e04_tNumberFloat_Integer() throws Exception {
519 		var in = (Float)123f;
520 		var ps = T_FLOAT;
521 		var s = serialize(ps, in);
522 		assertEquals("123.0", s);
523 		var r = parse(ps, s, Float.class);
524 		assertEquals(in, r);
525 	}
526 
527 	@Test void e05_tNumberDouble_String() throws Exception {
528 		var in = "123";
529 		var ps = T_DOUBLE;
530 		var s = serialize(ps, in);
531 		assertEquals("123.0", s);
532 		var r = parse(ps, s, String.class);
533 		assertEquals("123.0", r);
534 	}
535 
536 	@Test void e06_tNumberDouble_Double() throws Exception {
537 		var in = (Double)123d;
538 		var ps = T_DOUBLE;
539 		var s = serialize(ps, in);
540 		assertEquals("123.0", s);
541 		var r = parse(ps, s, Double.class);
542 		assertEquals(in, r);
543 	}
544 
545 	//------------------------------------------------------------------------------------------------------------------
546 	// Type == ARRAY
547 	//------------------------------------------------------------------------------------------------------------------
548 
549 	@Test void f01_tArray_String() {
550 		var in = "123";
551 		var ps = T_ARRAY;
552 		assertThrowsWithMessage(SerializeException.class, "Input is not a valid array type: java.lang.String", ()->serialize(ps, in));
553 	}
554 
555 	@Test void f02a_tArray_StringList() throws Exception {
556 		var in = list("a1");
557 		var ps = T_ARRAY;
558 		var s = serialize(ps, in);
559 		assertEquals("a1", s);
560 		var r = parse(ps, s, List.class, String.class);
561 		assertBean(r, "0", "a1");
562 
563 		in = list("a1","a2");
564 		s = serialize(ps, in);
565 		assertEquals("a1,a2", s);
566 		r = parse(ps, s, List.class, String.class);
567 		assertBean(r, "0,1", "a1,a2");
568 	}
569 
570 	@Test void f02b_tArray_3dStringList() throws Exception {
571 		var in = list(list(list("a")));
572 		var ps = tArray().items(
573 			tArray().items(
574 				tArray()
575 			)
576 		).build();
577 		var s = serialize(ps, in);
578 		assertEquals("a", s);
579 		var r = parse(ps, s, List.class, List.class, List.class, String.class);
580 		assertEquals(in, r);
581 
582 		in =  list(list(list("a","b"),list("c","d")),list(list("e","f"),list("g","h")));
583 		s = serialize(ps, in);
584 		assertEquals("a\\\\\\,b\\,c\\\\\\,d,e\\\\\\,f\\,g\\\\\\,h", s);
585 		r = parse(ps, s, List.class, List.class, List.class, String.class);
586 		assertEquals(in, r);
587 	}
588 
589 	@Test void f03a_tArray_IntArray() throws Exception {
590 		int[] in = {123};
591 		var ps = T_ARRAY;
592 		var s = serialize(ps, in);
593 		assertEquals("123", s);
594 		var r = parse(ps, s, int[].class);
595 		assertJson(json(in), r);
596 
597 		in = new int[]{123,456};
598 		s = serialize(ps, in);
599 		assertEquals("123,456", s);
600 		r = parse(ps, s, int[].class);
601 		assertJson(json(in), r);
602 	}
603 
604 	@Test void f03b_tArray_3dIntArray() throws Exception {
605 		int[][][] in = {{{123}}};
606 		var ps = tArray().items(
607 			tArray().items(
608 				tArray()
609 			)
610 		).build();
611 		var s = serialize(ps, in);
612 		assertEquals("123", s);
613 		int[][][] r = parse(ps, s, int[][][].class);
614 		assertJson(json(in), r);
615 
616 		int[][][] in2 = {{{1,2},{3,4}},{{5,6},{7,8}}};
617 		in = in2;
618 		s = serialize(ps, in);
619 		assertEquals("1\\\\\\,2\\,3\\\\\\,4,5\\\\\\,6\\,7\\\\\\,8", s);
620 		r = parse(ps, s, int[][][].class);
621 		assertJson(json(in), r);
622 	}
623 
624 
625 	public static class F04 {
626 		private String[] args;
627 
628 		public F04(String...args) {
629 			this.args = args;
630 		}
631 
632 		public String[] toStringArray() {
633 			return args;
634 		}
635 	}
636 
637 	@Test void f04_tArray_StringArrayMutator() throws Exception {
638 		var in = new F04("a1");
639 		var ps = T_ARRAY;
640 		var s = serialize(ps, in);
641 		assertEquals("a1", s);
642 		var r = parse(ps, s, F04.class);
643 		assertJson(json(in.toStringArray()), r.toStringArray());
644 
645 		in = new F04("a1","a2");
646 		s = serialize(ps, in);
647 		assertEquals("a1,a2", s);
648 		r = parse(ps, s, F04.class);
649 		assertJson(json(in.toStringArray()), r.toStringArray());
650 	}
651 
652 	@Test void f05a_tArrayUon_IntArray() throws Exception {
653 		int[] in = {123};
654 		var ps = T_ARRAY_UON;
655 		var s = serialize(ps, in);
656 		assertEquals("@(123)", s);
657 		int[] r = parse(ps, s, int[].class);
658 		assertJson(json(in), r);
659 
660 		in = new int[]{123,456};
661 		s = serialize(ps, in);
662 		assertEquals("@(123,456)", s);
663 		r = parse(ps, s, int[].class);
664 		assertJson(json(in), r);
665 	}
666 
667 	@Test void f05b_tArrayUon_3dIntArray() throws Exception {
668 		int[][][] in = {{{123}}};
669 		var ps = T_ARRAY_UON;
670 		var s = serialize(ps, in);
671 		assertEquals("@(@(@(123)))", s);
672 		int[][][] r = parse(ps, s, int[][][].class);
673 		assertJson(json(in), r);
674 
675 		int[][][] in2 = {{{1,2},{3,4}},{{5,6},{7,8}}};
676 		in = in2;
677 		s = serialize(ps, in);
678 		assertEquals("@(@(@(1,2),@(3,4)),@(@(5,6),@(7,8)))", s);
679 		r = parse(ps, s, int[][][].class);
680 		assertJson(json(in), r);
681 	}
682 
683 	@Test void f06a_tArrayPipes_IntArray() throws Exception {
684 		int[] in = {123};
685 		var ps = T_ARRAY_PIPES;
686 		var s = serialize(ps, in);
687 		assertEquals("123", s);
688 		int[] r = parse(ps, s, int[].class);
689 		assertJson(json(in), r);
690 
691 		in = new int[]{123,456};
692 		s = serialize(ps, in);
693 		assertEquals("123|456", s);
694 		r = parse(ps, s, int[].class);
695 		assertJson(json(in), r);
696 	}
697 
698 	@Test void f06b_tArrayPipes_3dIntArray() throws Exception {
699 		int[][][] in = {{{123}}};
700 		var ps = T_ARRAY_PIPES;
701 		var s = serialize(ps, in);
702 		assertEquals("123", s);
703 		int[][][] r = parse(ps, s, int[][][].class);
704 		assertJson(json(in), r);
705 
706 		int[][][] in2 = {{{1,2},{3,4}},{{5,6},{7,8}}};
707 		in = in2;
708 		s = serialize(ps, in);
709 		assertEquals("1\\\\,2,3\\\\,4|5\\\\,6,7\\\\,8", s);
710 		r = parse(ps, s, int[][][].class);
711 		assertJson(json(in), r);
712 	}
713 
714 	@Test void f07a_tArraySsv_IntArray() throws Exception {
715 		int[] in = {123};
716 		var ps = T_ARRAY_SSV;
717 		var s = serialize(ps, in);
718 		assertEquals("123", s);
719 		int[] r = parse(ps, s, int[].class);
720 		assertJson(json(in), r);
721 
722 		in = new int[]{123,456};
723 		s = serialize(ps, in);
724 		assertEquals("123 456", s);
725 		r = parse(ps, s, int[].class);
726 		assertJson(json(in), r);
727 	}
728 
729 	@Test void f07b_tArraySsv_3dIntArray() throws Exception {
730 		int[][][] in = {{{123}}};
731 		var ps = T_ARRAY_SSV;
732 		var s = serialize(ps, in);
733 		assertEquals("123", s);
734 		int[][][] r = parse(ps, s, int[][][].class);
735 		assertJson(json(in), r);
736 
737 		int[][][] in2 = {{{1,2},{3,4}},{{5,6},{7,8}}};
738 		in = in2;
739 		s = serialize(ps, in);
740 		assertEquals("1\\,2,3\\,4 5\\,6,7\\,8", s);
741 		r = parse(ps, s, int[][][].class);
742 		assertJson(json(in), r);
743 	}
744 
745 	@Test void f08a_tArrayTsv_IntArray() throws Exception {
746 		int[] in = {123};
747 		var ps = T_ARRAY_TSV;
748 		var s = serialize(ps, in);
749 		assertEquals("123", s);
750 		int[] r = parse(ps, s, int[].class);
751 		assertJson(json(in), r);
752 
753 		in = new int[]{123,456};
754 		s = serialize(ps, in);
755 		assertEquals("123\t456", s);
756 		r = parse(ps, s, int[].class);
757 		assertJson(json(in), r);
758 	}
759 
760 	@Test void f08b_tArrayTsv_3dIntArray() throws Exception {
761 		int[][][] in = {{{123}}};
762 		var ps = T_ARRAY_TSV;
763 		var s = serialize(ps, in);
764 		assertEquals("123", s);
765 		int[][][] r = parse(ps, s, int[][][].class);
766 		assertJson(json(in), r);
767 
768 		int[][][] in2 = {{{1,2},{3,4}},{{5,6},{7,8}}};
769 		in = in2;
770 		s = serialize(ps, in);
771 		assertEquals("1\\,2,3\\,4\t5\\,6,7\\,8", s);
772 		r = parse(ps, s, int[][][].class);
773 		assertJson(json(in), r);
774 	}
775 
776 	@Test void f09a_tArrayCsv_IntArray() throws Exception {
777 		int[] in = {123};
778 		var ps = T_ARRAY_CSV;
779 		var s = serialize(ps, in);
780 		assertEquals("123", s);
781 		int[] r = parse(ps, s, int[].class);
782 		assertJson(json(in), r);
783 
784 		in = new int[]{123,456};
785 		s = serialize(ps, in);
786 		assertEquals("123,456", s);
787 		r = parse(ps, s, int[].class);
788 		assertJson(json(in), r);
789 	}
790 
791 	@Test void f09b_tArrayCsv_3dIntArray() throws Exception {
792 		int[][][] in = {{{123}}};
793 		var ps = T_ARRAY_CSV;
794 		var s = serialize(ps, in);
795 		assertEquals("123", s);
796 		int[][][] r = parse(ps, s, int[][][].class);
797 		assertJson(json(in), r);
798 
799 		int[][][] in2 = {{{1,2},{3,4}},{{5,6},{7,8}}};
800 		in = in2;
801 		s = serialize(ps, in);
802 		assertEquals("1\\\\\\,2\\,3\\\\\\,4,5\\\\\\,6\\,7\\\\\\,8", s);
803 		r = parse(ps, s, int[][][].class);
804 		assertJson(json(in), r);
805 	}
806 
807 
808 	@Test void f10_tArray_complexTypes() throws Exception {
809 		int[][][] in =  {{{1,2},{3,4}},{{5,6},{7,8}}};
810 		var ps = tArrayCsv().items(
811 			tArrayPipes().items(
812 				tArraySsv()
813 			)
814 		).build();
815 		var s = serialize(ps, in);
816 		assertEquals("1 2|3 4,5 6|7 8", s);
817 		int[][][] r = parse(ps, s, int[][][].class);
818 		assertJson(json(in), r);
819 	}
820 
821 	//------------------------------------------------------------------------------------------------------------------
822 	// Type == OBJECT, Map
823 	//------------------------------------------------------------------------------------------------------------------
824 
825 	@Test void g01a_objectType_formatDefault_Map() throws Exception {
826 		var in = JsonMap.of("a","b");
827 		var ps = T_OBJECT;
828 		var s = serialize(ps, in);
829 		assertEquals("a=b", s);
830 		var r = parse(ps, s, JsonMap.class);
831 		assertJson(json(in), r);
832 
833 		in = JsonMap.of("a","b","c","d");
834 		s = serialize(ps, in);
835 		assertEquals("a=b,c=d", s);
836 		r = parse(ps, s, JsonMap.class);
837 		assertJson(json(in), r);
838 	}
839 
840 	@Test void g01b_objectType_formatDefault_Map_3d() throws Exception {
841 		var in = JsonMap.of("a",JsonMap.of("b",JsonMap.of("c","d")));
842 		var ps = tObject()
843 			.p("a", tObject()
844 				.p("b", tObject())
845 				.p("e", tObject())
846 			)
847 			.build();
848 		var s = serialize(ps, in);
849 		assertEquals("a=b\\=c\\\\\\=d", s);
850 		var r = parse(ps, s, JsonMap.class);
851 		assertJson(json(in), r);
852 
853 		in = JsonMap.of("a",JsonMap.of("b",JsonMap.of("c","d"),"e",JsonMap.of("f","g")));
854 		s = serialize(ps, in);
855 		assertEquals("a=b\\=c\\\\\\=d\\,e\\=f\\\\\\=g", s);
856 		r = parse(ps, s, JsonMap.class);
857 		assertJson(json(in), r);
858 	}
859 
860 	//---------------------------------------------------------------------------------------------
861 	// Helpers
862 	//---------------------------------------------------------------------------------------------
863 
864 	private Calendar cal(String in) {
865 		return DatatypeConverter.parseDateTime(toValidISO8601DT(in));
866 	}
867 }