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