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.httppart;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.commons.utils.IoUtils.*;
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.io.*;
27  import java.lang.reflect.*;
28  import java.util.*;
29  
30  import org.apache.juneau.*;
31  import org.apache.juneau.collections.*;
32  import org.apache.juneau.json.*;
33  import org.apache.juneau.oapi.*;
34  import org.apache.juneau.parser.*;
35  import org.junit.jupiter.api.*;
36  
37  class OpenApiPartParser_Test extends TestBase {
38  
39  	static OpenApiParserSession p = OpenApiParser.DEFAULT.getSession();
40  
41  	private static <T> T parse(HttpPartSchema schema, String input, Class<T> type) throws SchemaValidationException, ParseException {
42  		return p.parse(null, schema, input, p.getClassMeta(type));
43  	}
44  
45  	private static <T> T parse(HttpPartSchema schema, String input, Class<T> type, Type...args) throws SchemaValidationException, ParseException {
46  		return p.parse(null, schema, input, p.getClassMeta(type, args));
47  	}
48  
49  	//-----------------------------------------------------------------------------------------------------------------
50  	// Input validations
51  	//-----------------------------------------------------------------------------------------------------------------
52  
53  	@Test void a01_inputValidations_nullInput() throws Exception {
54  		assertNull(parse(T_NONE, null, String.class));
55  		assertNull(parse(tNone().required(false).build(), null, String.class));
56  		assertThrowsWithMessage(SchemaValidationException.class, "No value specified.", ()->parse(tNone().required().build(), null, String.class));
57  		assertThrowsWithMessage(SchemaValidationException.class, "No value specified.", ()->parse(tNone().required(true).build(), null, String.class));
58  	}
59  
60  	@Test void a02_inputValidations_emptyInput() throws Exception {
61  
62  		var s = tNone().allowEmptyValue().build();
63  		assertEquals("", parse(s, "", String.class));
64  
65  		s = tNone().allowEmptyValue().build();
66  		assertEquals("", parse(s, "", String.class));
67  
68  		assertThrowsWithMessage(SchemaValidationException.class, "Empty value not allowed.", ()->parse(tNone().allowEmptyValue(false).build(), "", String.class));
69  
70  		assertEquals(" ", parse(s, " ", String.class));
71  	}
72  
73  	@Test void a03_inputValidations_pattern() throws Exception {
74  		final HttpPartSchema s = tNone().pattern("x.*").allowEmptyValue().build();
75  		assertEquals("x", parse(s, "x", String.class));
76  		assertEquals("xx", parse(s, "xx", String.class));
77  		assertEquals(null, parse(s, null, String.class));
78  
79  		assertThrowsWithMessage(SchemaValidationException.class, "Value does not match expected pattern.  Must match pattern: x.*", ()->parse(s, "y", String.class));
80  		assertThrowsWithMessage(SchemaValidationException.class, "Value does not match expected pattern.  Must match pattern: x.*", ()->parse(s, "", String.class));
81  
82  		// Blank/null patterns are ignored.
83  		assertEquals("x", parse(tNone().pattern("").allowEmptyValue().build(), "x", String.class));
84  		assertEquals("x", parse(tNone().pattern(null).allowEmptyValue().build(), "x", String.class));
85  	}
86  
87  	@Test void a04_inputValidations_enum() throws Exception {
88  		var s = tNone().enum_("foo").allowEmptyValue().build();
89  
90  		assertEquals("foo", parse(s, "foo", String.class));
91  		assertEquals(null, parse(s, null, String.class));
92  
93  		assertThrowsWithMessage(SchemaValidationException.class, "Value does not match one of the expected values.  Must be one of the following:  foo", ()->parse(s, "bar", String.class));
94  		assertThrowsWithMessage(SchemaValidationException.class, "Value does not match one of the expected values.  Must be one of the following:  foo", ()->parse(s, "", String.class));
95  
96  		assertEquals("foo", parse(tNone().enum_((Set<String>)null).build(), "foo", String.class));
97  		assertEquals("foo", parse(tNone().enum_((Set<String>)null).allowEmptyValue().build(), "foo", String.class));
98  		assertEquals("foo", parse(tNone().enum_("foo","foo").build(), "foo", String.class));
99  	}
100 
101 	@Test void a05_inputValidations_minMaxLength() throws Exception {
102 		var s = tNone().minLength(1L).maxLength(2L).allowEmptyValue().build();
103 
104 		assertEquals(null, parse(s, null, String.class));
105 		assertEquals("1", parse(s, "1", String.class));
106 		assertEquals("12", parse(s, "12", String.class));
107 
108 		assertThrowsWithMessage(SchemaValidationException.class, "Minimum length of value not met.", ()->parse(s, "", String.class));
109 		assertThrowsWithMessage(SchemaValidationException.class, "Maximum length of value exceeded.", ()->parse(s, "123", String.class));
110 		assertThrowsWithMessage(Exception.class, "maxLength cannot be less than minLength.", ()->tNone().minLength(2L).maxLength(1L).build());
111 		assertThrowsWithMessage(Exception.class, "minLength cannot be less than zero.", ()->tNone().minLength(-2L).build());
112 		assertThrowsWithMessage(Exception.class, "maxLength cannot be less than zero.", ()->tNone().maxLength(-2L).build());
113 	}
114 
115 	//-----------------------------------------------------------------------------------------------------------------
116 	// Primitive defaults
117 	//-----------------------------------------------------------------------------------------------------------------
118 
119 	@Test void b01_primitiveDefaults() throws Exception {
120 		assertEquals(null, parse(null, null, Boolean.class));
121 		assertEquals(false, parse(null, null, boolean.class));
122 		assertEquals(null, parse(null, null, Character.class));
123 		assertEquals("\0", parse(null, null, char.class).toString());
124 		assertEquals(null, parse(null, null, Short.class));
125 		assertEquals(0, parse(null, null, short.class).intValue());
126 		assertEquals(null, parse(null, null, Integer.class));
127 		assertEquals(0, parse(null, null, int.class).intValue());
128 		assertEquals(null, parse(null, null, Long.class));
129 		assertEquals(0, parse(null, null, long.class).intValue());
130 		assertEquals(null, parse(null, null, Float.class));
131 		assertEquals(0, parse(null, null, float.class).intValue());
132 		assertEquals(null, parse(null, null, Double.class));
133 		assertEquals(0, parse(null, null, double.class).intValue());
134 		assertEquals(null, parse(null, null, Byte.class));
135 		assertEquals(0, parse(null, null, byte.class).intValue());
136 	}
137 
138 	@Test void b02_primitiveDefaults_nullKeyword() throws Exception {
139 		assertEquals(null, parse(null, "null", Boolean.class));
140 		assertEquals(false, parse(null, "null", boolean.class));
141 		assertEquals(null, parse(null, "null", Character.class));
142 		assertEquals("\0", parse(null, "null", char.class).toString());
143 		assertEquals(null, parse(null, "null", Short.class));
144 		assertEquals(0, parse(null, "null", short.class).intValue());
145 		assertEquals(null, parse(null, "null", Integer.class));
146 		assertEquals(0, parse(null, "null", int.class).intValue());
147 		assertEquals(null, parse(null, "null", Long.class));
148 		assertEquals(0, parse(null, "null", long.class).intValue());
149 		assertEquals(null, parse(null, "null", Float.class));
150 		assertEquals(0, parse(null, "null", float.class).intValue());
151 		assertEquals(null, parse(null, "null", Double.class));
152 		assertEquals(0, parse(null, "null", double.class).intValue());
153 		assertEquals(null, parse(null, "null", Byte.class));
154 		assertEquals(0, parse(null, "null", byte.class).intValue());
155 	}
156 
157 	//-----------------------------------------------------------------------------------------------------------------
158 	// type = string
159 	//-----------------------------------------------------------------------------------------------------------------
160 
161 	public static class C1 {
162 		private String f;
163 		public C1(byte[] b) {
164 			f = "C1-" + new String(b);
165 		}
166 		@Override
167 		public String toString() {
168 			return f;
169 		}
170 	}
171 
172 	public static class C2 {
173 		private String f;
174 		public C2(String s) {
175 			f = "C2-" + s;
176 		}
177 		@Override
178 		public String toString() {
179 			return f;
180 		}
181 	}
182 
183 	public static class C3 {
184 		private String f;
185 		public C3(String[] in) {
186 			f = "C3-" + Json5Serializer.DEFAULT.toString(in);
187 		}
188 		@Override
189 		public String toString() {
190 			return f;
191 		}
192 	}
193 
194 	@Test void c01_stringType_simple() throws Exception {
195 		var s = T_STRING;
196 		assertEquals("foo", parse(s, "foo", String.class));
197 	}
198 
199 	@Test void c02_stringType_default() throws Exception {
200 		var s = tString().default_("x").build();
201 		assertEquals("foo", parse(s, "foo", String.class));
202 		assertEquals("x", parse(s, null, String.class));
203 	}
204 
205 	@Test void c03_stringType_byteFormat() throws Exception {
206 		var s = T_BYTE;
207 		var in = base64Encode("foo".getBytes());
208 		assertEquals("foo", parse(s, in, String.class));
209 		assertEquals("foo", read(parse(s, in, InputStream.class)));
210 		assertEquals("foo", read(parse(s, in, Reader.class)));
211 		assertEquals("C1-foo", parse(s, in, C1.class).toString());
212 	}
213 
214 	@Test void c04_stringType_binaryFormat() throws Exception {
215 		var s = T_BINARY;
216 		var in = toHex("foo".getBytes());
217 		assertEquals("foo", parse(s, in, String.class));
218 		assertEquals("foo", read(parse(s, in, InputStream.class)));
219 		assertEquals("foo", read(parse(s, in, Reader.class)));
220 		assertEquals("C1-foo", parse(s, in, C1.class).toString());
221 	}
222 
223 	@Test void c05_stringType_binarySpacedFormat() throws Exception {
224 		var s = T_BINARY_SPACED;
225 		var in = toSpacedHex("foo".getBytes());
226 		assertEquals("foo", parse(s, in, String.class));
227 		assertEquals("foo", read(parse(s, in, InputStream.class)));
228 		assertEquals("foo", read(parse(s, in, Reader.class)));
229 		assertEquals("C1-foo", parse(s, in, C1.class).toString());
230 	}
231 
232 	@Test void c06_stringType_dateFormat() throws Exception {
233 		var s = T_DATE;
234 		var in = "2012-12-21";
235 		assertTrue(parse(s, in, String.class).contains("2012"));
236 		assertTrue(parse(s, in, Date.class).toString().contains("2012"));
237 		assertEquals(2012, parse(s, in, Calendar.class).get(Calendar.YEAR));
238 		assertEquals(2012, parse(s, in, GregorianCalendar.class).get(Calendar.YEAR));
239 	}
240 
241 	@Test void c07_stringType_dateTimeFormat() throws Exception {
242 		var s = T_DATETIME;
243 		var in = "2012-12-21T12:34:56.789";
244 		assertTrue(parse(s, in, String.class).contains("2012"));
245 		assertTrue(parse(s, in, Date.class).toString().contains("2012"));
246 		assertEquals(2012, parse(s, in, Calendar.class).get(Calendar.YEAR));
247 		assertEquals(2012, parse(s, in, GregorianCalendar.class).get(Calendar.YEAR));
248 	}
249 
250 	@Test void c08_stringType_uonFormat() throws Exception {
251 		var s = T_UON;
252 		assertEquals("foo", parse(s, "foo", String.class));
253 		assertEquals("foo", parse(s, "'foo'", String.class));
254 		assertEquals("C2-foo", parse(s, "'foo'", C2.class).toString());
255 		// UonPartParserTest should handle all other cases.
256 	}
257 
258 	@Test void c09_stringType_noneFormat() throws Exception {
259 		// If no format is specified, then we should transform directly from a string.
260 		var s = T_STRING;
261 		assertEquals("foo", parse(s, "foo", String.class));
262 		assertEquals("'foo'", parse(s, "'foo'", String.class));
263 		assertEquals("C2-foo", parse(s, "foo", C2.class).toString());
264 	}
265 
266 	@Test void c10_stringType_noneFormat_2d() throws Exception {
267 		var s = tArray(tString()).build();
268 		assertList(parse(s, "foo,bar", String[].class), "foo", "bar");
269 		assertList(parse(s, "foo,bar", List.class, String.class), "foo", "bar");
270 		assertList(parse(s, "foo,bar", Object[].class), "foo", "bar");
271 		assertList(parse(s, "foo,bar", List.class, Object.class), "foo", "bar");
272 		var o = parse(s, "foo,bar", Object.class);
273 		assertList(o, "foo", "bar");
274 		assertInstanceOf(JsonList.class, o);
275 		assertList(parse(s, "foo,bar", C2[].class), "C2-foo", "C2-bar");
276 		assertList(parse(s, "foo,bar", List.class, C2.class), "C2-foo", "C2-bar");
277 		assertEquals("C3-['foo','bar']", parse(s, "foo,bar", C3.class).toString());
278 	}
279 
280 	@Test void c11_stringType_noneFormat_3d() throws Exception {
281 		var s = tArrayPipes(tArray(tString())).build();
282 		assertList(parse(s, "foo,bar|baz", String[][].class), "[foo,bar]", "[baz]");
283 		assertList(parse(s, "foo,bar|baz", List.class, String[].class), "[foo,bar]", "[baz]");
284 		assertList(parse(s, "foo,bar|baz", List.class, List.class, String.class), "[foo,bar]", "[baz]");
285 		assertList(parse(s, "foo,bar|baz", Object[][].class), "[foo,bar]", "[baz]");
286 		assertList(parse(s, "foo,bar|baz", List.class, Object[].class), "[foo,bar]", "[baz]");
287 		assertList(parse(s, "foo,bar|baz", List.class, List.class, Object.class), "[foo,bar]", "[baz]");
288 		var o = parse(s, "foo,bar|baz", Object.class);
289 		assertList(o, "[foo,bar]", "[baz]");
290 		assertInstanceOf(JsonList.class, o);
291 		assertList(parse(s, "foo,bar|baz", C2[][].class), "[C2-foo,C2-bar]", "[C2-baz]");
292 		assertList(parse(s, "foo,bar|baz", List.class, C2[].class), "[C2-foo,C2-bar]", "[C2-baz]");
293 		assertList(parse(s, "foo,bar|baz", List.class, List.class, C2.class), "[C2-foo,C2-bar]", "[C2-baz]");
294 		assertList(parse(s, "foo,bar|baz", C3[].class), "C3-['foo','bar']", "C3-['baz']");
295 		assertList(parse(s, "foo,bar|baz", List.class, C3.class), "C3-['foo','bar']", "C3-['baz']");
296 	}
297 
298 	@Test void c12a_stringType_nullKeyword_plain() throws Exception {
299 		var s = T_STRING;
300 		assertEquals(null, parse(s, "null", String.class));
301 	}
302 
303 	@Test void c12b_stringType_nullKeyword_plain_2d() throws Exception {
304 		var s = tArray(tString()).build();
305 		assertNull(parse(s, "null", String[].class));
306 		assertList(parse(s, "@(null)", String[].class), (String) null);
307 	}
308 
309 	@Test void c12c_stringType_nullKeyword_uon() throws Exception {
310 		var s = T_UON;
311 		assertNull(parse(s, "null", String.class));
312 		assertEquals("null", parse(s, "'null'", String.class));
313 	}
314 
315 	@Test void c12d_stringType_nullKeyword_uon_2d() throws Exception {
316 		var s = tArray(tUon()).build();
317 		assertList(parse(s, "null,x", String[].class), null, "x");
318 		assertNull(parse(s, "null", String[].class));
319 		assertList(parse(s, "@(null)", String[].class), (String) null);
320 		assertList(parse(s, "'null'", String[].class), "null");
321 		assertList(parse(s, "@('null')", String[].class), "null");
322 	}
323 
324 	//-----------------------------------------------------------------------------------------------------------------
325 	// type = array
326 	//-----------------------------------------------------------------------------------------------------------------
327 
328 	public static class D {
329 		private String f;
330 		public D(String in) {
331 			this.f = "D-" + in;
332 		}
333 		@Override
334 		public String toString() {
335 			return f;
336 		}
337 	}
338 
339 	@Test void d01_arrayType_collectionFormatCsv() throws Exception {
340 		var s = T_ARRAY_CSV;
341 		assertList(parse(s, "foo,bar", String[].class), "foo", "bar");
342 		assertList(parse(s, "foo,bar", Object[].class), "foo", "bar");
343 		assertList(parse(s, "foo,bar", D[].class), "D-foo", "D-bar");
344 		assertList(parse(s, "foo,bar", List.class, String.class), "foo", "bar");
345 		assertList(parse(s, "foo,bar", List.class, Object.class), "foo", "bar");
346 		assertList(parse(s, "foo,bar", List.class, D.class), "D-foo", "D-bar");
347 		assertList(parse(s, "foo,bar", Object.class), "foo", "bar");
348 		assertList(parse(s, "foo,bar", JsonList.class), "foo", "bar");
349 	}
350 
351 	@Test void d02_arrayType_collectionFormatPipes() throws Exception {
352 		var s = T_ARRAY_PIPES;
353 		assertList(parse(s, "foo|bar", String[].class), "foo", "bar");
354 		assertList(parse(s, "foo|bar", Object[].class), "foo", "bar");
355 		assertList(parse(s, "foo|bar", D[].class), "D-foo", "D-bar");
356 		assertList(parse(s, "foo|bar", List.class, String.class), "foo", "bar");
357 		assertList(parse(s, "foo|bar", List.class, Object.class), "foo", "bar");
358 		assertList(parse(s, "foo|bar", List.class, D.class), "D-foo", "D-bar");
359 		assertList(parse(s, "foo|bar", Object.class), "foo", "bar");
360 		assertList(parse(s, "foo|bar", JsonList.class), "foo", "bar");
361 	}
362 
363 	@Test void d03_arrayType_collectionFormatSsv() throws Exception {
364 		var s = T_ARRAY_SSV;
365 		assertList(parse(s, "foo bar", String[].class), "foo", "bar");
366 		assertList(parse(s, "foo bar", Object[].class), "foo", "bar");
367 		assertList(parse(s, "foo bar", D[].class), "D-foo", "D-bar");
368 		assertList(parse(s, "foo bar", List.class, String.class), "foo", "bar");
369 		assertList(parse(s, "foo bar", List.class, Object.class), "foo", "bar");
370 		assertList(parse(s, "foo bar", List.class, D.class), "D-foo", "D-bar");
371 		assertList(parse(s, "foo bar", Object.class), "foo", "bar");
372 		assertList(parse(s, "foo bar", JsonList.class), "foo", "bar");
373 	}
374 
375 	@Test void d04_arrayType_collectionFormatTsv() throws Exception {
376 		var s = T_ARRAY_TSV;
377 		assertList(parse(s, "foo\tbar", String[].class), "foo", "bar");
378 		assertList(parse(s, "foo\tbar", Object[].class), "foo", "bar");
379 		assertList(parse(s, "foo\tbar", D[].class), "D-foo", "D-bar");
380 		assertList(parse(s, "foo\tbar", List.class, String.class), "foo", "bar");
381 		assertList(parse(s, "foo\tbar", List.class, Object.class), "foo", "bar");
382 		assertList(parse(s, "foo\tbar", List.class, D.class), "D-foo", "D-bar");
383 		assertList(parse(s, "foo\tbar", Object.class), "foo", "bar");
384 		assertList(parse(s, "foo\tbar", JsonList.class), "foo", "bar");
385 	}
386 
387 	@Test void d05_arrayType_collectionFormatUon() throws Exception {
388 		var s = T_ARRAY_UON;
389 		assertList(parse(s, "@(foo,bar)", String[].class), "foo", "bar");
390 		assertList(parse(s, "@(foo,bar)", Object[].class), "foo", "bar");
391 		assertList(parse(s, "@(foo,bar)", D[].class), "D-foo", "D-bar");
392 		assertList(parse(s, "@(foo,bar)", List.class, String.class), "foo", "bar");
393 		assertList(parse(s, "@(foo,bar)", List.class, Object.class), "foo", "bar");
394 		assertList(parse(s, "@(foo,bar)", List.class, D.class), "D-foo", "D-bar");
395 		assertList(parse(s, "@(foo,bar)", Object.class), "foo", "bar");
396 		assertList(parse(s, "@(foo,bar)", JsonList.class), "foo", "bar");
397 	}
398 
399 	@Test void d06a_arrayType_collectionFormatNone() throws Exception {
400 		var s = T_ARRAY;
401 		assertList(parse(s, "foo,bar", String[].class), "foo", "bar");
402 		assertList(parse(s, "foo,bar", Object[].class), "foo", "bar");
403 		assertList(parse(s, "foo,bar", D[].class), "D-foo", "D-bar");
404 		assertList(parse(s, "foo,bar", List.class, String.class), "foo", "bar");
405 		assertList(parse(s, "foo,bar", List.class, Object.class), "foo", "bar");
406 		assertList(parse(s, "foo,bar", List.class, D.class), "D-foo", "D-bar");
407 		assertList(parse(s, "foo,bar", Object.class), "foo", "bar");
408 	}
409 
410 	@Test void d06b_arrayType_collectionFormatNone_autoDetectUon() throws Exception {
411 		var s = T_ARRAY;
412 		assertJson("['foo','bar']", parse(s, "@(foo,bar)", String[].class));
413 		assertJson("['foo','bar']", parse(s, "@(foo,bar)", Object[].class));
414 		assertJson("['D-foo','D-bar']", parse(s, "@(foo,bar)", D[].class));
415 		assertJson("['foo','bar']", parse(s, "@(foo,bar)", List.class, String.class));
416 		assertJson("['foo','bar']", parse(s, "@(foo,bar)", List.class, Object.class));
417 		assertJson("['D-foo','D-bar']", parse(s, "@(foo,bar)", List.class, D.class));
418 		assertJson("['foo','bar']", parse(s, "@(foo,bar)", Object.class));
419 	}
420 
421 	@Test void d07_arrayType_collectionFormatMulti() throws Exception {
422 		// collectionFormat=multi should not do any sort of splitting.
423 		var s = T_ARRAY_MULTI;
424 		assertList(parse(s, "foo,bar", String[].class), "foo,bar");
425 		assertList(parse(s, "foo,bar", Object[].class), "foo,bar");
426 		assertList(parse(s, "foo,bar", D[].class), "D-foo,bar");
427 		assertList(parse(s, "foo,bar", List.class, String.class), "foo,bar");
428 		assertList(parse(s, "foo,bar", List.class, Object.class), "foo,bar");
429 		assertList(parse(s, "foo,bar", List.class, D.class), "D-foo,bar");
430 		assertList(parse(s, "foo,bar", Object.class), "foo,bar");
431 	}
432 
433 	@Test void d08_arrayType_collectionFormatCsvAndPipes() throws Exception {
434 		var s = tArrayPipes(tArrayCsv()).build();
435 		assertJson("[['foo','bar'],['baz','qux']]", parse(s, "foo,bar|baz,qux", String[][].class));
436 		assertJson("[['foo','bar'],['baz','qux']]", parse(s, "foo,bar|baz,qux", Object[][].class));
437 		assertJson("[['D-foo','D-bar'],['D-baz','D-qux']]", parse(s, "foo,bar|baz,qux", D[][].class));
438 		assertJson("[['foo','bar'],['baz','qux']]", parse(s, "foo,bar|baz,qux", List.class, List.class, String.class));
439 		assertJson("[['foo','bar'],['baz','qux']]", parse(s, "foo,bar|baz,qux", List.class, List.class, Object.class));
440 		assertJson("[['D-foo','D-bar'],['D-baz','D-qux']]", parse(s, "foo,bar|baz,qux", List.class, List.class, D.class));
441 		assertJson("[['foo','bar'],['baz','qux']]", parse(s, "foo,bar|baz,qux", Object.class));
442 	}
443 
444 	@Test void d09_arrayType_itemsBoolean() throws Exception {
445 		var s = tArrayCsv(tBoolean()).build();
446 		assertList(parse(s, "true,false", boolean[].class), true, false);
447 		assertList(parse(s, "true,false,null", Boolean[].class), true, false, null);
448 		assertList(parse(s, "true,false,null", Object[].class), true, false, null);
449 		assertList(parse(s, "true,false,null", List.class, Boolean.class), true, false, null);
450 		assertList(parse(s, "true,false,null", List.class, Object.class), true, false, null);
451 		assertList(parse(s, "true,false,null", Object.class), true, false, null);
452 	}
453 
454 	@Test void d10_arrayType_itemsInteger() throws Exception {
455 		var s = tArrayCsv(tInteger()).build();
456 		assertList(parse(s, "1,2", int[].class), 1, 2);
457 		assertList(parse(s, "1,2,null", Integer[].class), 1, 2, null);
458 		assertList(parse(s, "1,2,null", Object[].class), 1, 2, null);
459 		assertList(parse(s, "1,2,null", List.class, Integer.class), 1, 2, null);
460 		assertList(parse(s, "1,2,null", List.class, Object.class), 1, 2, null);
461 		assertList(parse(s, "1,2,null", Object.class), 1, 2, null);
462 	}
463 
464 	@Test void d11_arrayType_itemsFloat() throws Exception {
465 		var s = tArrayCsv(tNumber()).build();
466 		assertList(parse(s, "1.0,2.0", float[].class), 1.0f, 2.0f);
467 		assertList(parse(s, "1.0,2.0,null", Float[].class), 1.0f, 2.0f, null);
468 		assertList(parse(s, "1.0,2.0,null", Object[].class), 1.0f, 2.0f, null);
469 		assertList(parse(s, "1.0,2.0,null", List.class, Float.class), 1.0f, 2.0f, null);
470 		assertList(parse(s, "1.0,2.0,null", List.class, Object.class), 1.0f, 2.0f, null);
471 		assertList(parse(s, "1.0,2.0,null", Object.class), 1.0f, 2.0f, null);
472 	}
473 
474 	//-----------------------------------------------------------------------------------------------------------------
475 	// type = boolean
476 	//-----------------------------------------------------------------------------------------------------------------
477 
478 	public static class E1 {
479 		private String f;
480 		public E1(Boolean in) {
481 			this.f = "E1-" + in.toString();
482 		}
483 		@Override
484 		public String toString() {
485 			return f;
486 		}
487 	}
488 
489 	public static class E2 {
490 		private String f;
491 		public E2(Boolean[] in) {
492 			this.f = "E2-" + Json5Serializer.DEFAULT.toString(in);
493 		}
494 		@Override
495 		public String toString() {
496 			return f;
497 		}
498 	}
499 
500 	@Test void e01_booleanType() throws Exception {
501 		var s = T_BOOLEAN;
502 		assertEquals(true, parse(s, "true", boolean.class));
503 		assertEquals(true, parse(s, "true", Boolean.class));
504 		assertNull(parse(s, "null", Boolean.class));
505 		assertEquals(true, parse(s, "True", boolean.class));
506 		assertEquals(true, parse(s, "TRUE", boolean.class));
507 		assertEquals("true", parse(s, "true", String.class));
508 		assertNull(parse(s, "null", String.class));
509 		assertEquals(true, parse(s, "true", Object.class));
510 		assertNull(parse(s, "null", Object.class));
511 		assertJson("'E1-true'", parse(s, "true", E1.class));
512 		assertNull(parse(s, "null", E1.class));
513 	}
514 
515 	@Test void e02_booleanType_2d() throws Exception {
516 		var s = tArray(tBoolean()).build();
517 		assertList(parse(s, "true,true", boolean[].class), true, true);
518 		assertList(parse(s, "true,true,null", Boolean[].class), true, true, null);
519 		assertList(parse(s, "true,true,null", List.class, Boolean.class), true, true, null);
520 		assertList(parse(s, "true,true,null", String[].class), "true", "true", null);
521 		assertList(parse(s, "true,true,null", List.class, String.class), "true", "true", null);
522 		assertList(parse(s, "true,true,null", Object[].class), true, true, null);
523 		assertList(parse(s, "true,true,null", List.class, Object.class), true, true, null);
524 		assertList(parse(s, "true,true,null", E1[].class), "E1-true", "E1-true", null);
525 		assertList(parse(s, "true,true,null", List.class, E1.class), "E1-true", "E1-true", null);
526 		assertJson("'E2-[true,true,null]'", parse(s, "true,true,null", E2.class));
527 
528 		assertList(parse(s, "True,true", boolean[].class), true, true);
529 		assertList(parse(s, "TRUE,true", boolean[].class), true, true);
530 	}
531 
532 	@Test void e03_booleanType_3d() throws Exception {
533 		var s = tArrayPipes(tArray(tBoolean())).build();
534 		assertJson("[[true,true],[false]]", parse(s, "true,true|false", boolean[][].class));
535 		assertJson("[[true,true],[false]]", parse(s, "true,true|false", List.class, boolean[].class));
536 		assertJson("[[true,true],[false,null]]", parse(s, "true,true|false,null", Boolean[][].class));
537 		assertJson("[[true,true],[false,null]]", parse(s, "true,true|false,null", List.class, Boolean[].class));
538 		assertJson("[[true,true],[false,null]]", parse(s, "true,true|false,null", List.class, List.class, Boolean.class));
539 		assertJson("[['true','true'],['false',null]]", parse(s, "true,true|false,null", String[][].class));
540 		assertJson("[['true','true'],['false',null]]", parse(s, "true,true|false,null", List.class, List.class, String.class));
541 		assertJson("[['true','true'],['false',null]]", parse(s, "true,true|false,null", List.class, String[].class));
542 		assertJson("[[true,true],[false,null]]", parse(s, "true,true|false,null", Object[][].class));
543 		assertJson("[[true,true],[false,null]]", parse(s, "true,true|false,null", List.class, List.class, Object.class));
544 		assertJson("[[true,true],[false,null]]", parse(s, "true,true|false,null", List.class, Object[].class));
545 		assertJson("[['E1-true','E1-true'],['E1-false',null]]", parse(s, "true,true|false,null", E1[][].class));
546 		assertJson("[['E1-true','E1-true'],['E1-false',null]]", parse(s, "true,true|false,null", List.class, List.class, E1.class));
547 		assertJson("[['E1-true','E1-true'],['E1-false',null]]", parse(s, "true,true|false,null", List.class, E1[].class));
548 		assertJson("['E2-[true,true]','E2-[false,null]']", parse(s, "true,true|false,null", E2[].class));
549 		assertJson("['E2-[true,true]','E2-[false,null]']", parse(s, "true,true|false,null", List.class, E2.class));
550 
551 		assertJson("[[true,true],[false]]", parse(s, "True,true|false", boolean[][].class));
552 		assertJson("[[true,true],[false]]", parse(s, "TRUE,true|false", boolean[][].class));
553 	}
554 
555 	//-----------------------------------------------------------------------------------------------------------------
556 	// type = integer
557 	//-----------------------------------------------------------------------------------------------------------------
558 
559 	public static class F1 {
560 		private String f;
561 		public F1(Integer in) {
562 			this.f = "F1-" + in.toString();
563 		}
564 		@Override
565 		public String toString() {
566 			return f;
567 		}
568 	}
569 
570 	public static class F2 {
571 		private String f;
572 		public F2(Integer[] in) {
573 			this.f = "F2-" + Json5Serializer.DEFAULT.toString(in);
574 		}
575 		@Override
576 		public String toString() {
577 			return f;
578 		}
579 	}
580 
581 	public static class F3 {
582 		private Long f;
583 		public F3(Long in) {
584 			this.f = in;
585 		}
586 		public Long toLong() {
587 			return f;
588 		}
589 	}
590 
591 	public static class F4 {
592 		private String f;
593 		public F4(Long[] in) {
594 			this.f = "F4-" + Json5Serializer.DEFAULT.toString(in);
595 		}
596 		@Override
597 		public String toString() {
598 			return f;
599 		}
600 	}
601 
602 	@Test void f01_integerType_int32() throws Exception {
603 		var s = T_INT32;
604 		assertJson("1", parse(s, "1", int.class));
605 		assertJson("1", parse(s, "1", Integer.class));
606 		assertJson("1", parse(s, "1", short.class));
607 		assertJson("1", parse(s, "1", Short.class));
608 		assertJson("1", parse(s, "1", long.class));
609 		assertJson("1", parse(s, "1", Long.class));
610 		assertJson("'1'", parse(s, "1", String.class));
611 		var o = parse(s, "1", Object.class);
612 		assertEquals(1, o);
613 		assertInstanceOf(Integer.class, o);
614 		assertJson("'F1-1'", parse(s,  "1", F1.class));
615 	}
616 
617 	@Test void f02_integerType_int32_2d() throws Exception {
618 		var s = tArray(tInt32()).build();
619 		assertList(parse(s, "1,2", int[].class), 1, 2);
620 		assertList(parse(s, "1,2", Integer[].class), 1, 2);
621 		assertList(parse(s, "1,2", List.class, Integer.class), 1, 2);
622 		assertList(parse(s, "1,2", short[].class), (short)1, (short)2);
623 		assertList(parse(s, "1,2", Short[].class), (short)1, (short)2);
624 		assertList(parse(s, "1,2", List.class, Short.class), (short)1, (short)2);
625 		assertList(parse(s, "1,2", long[].class), 1l, 2l);
626 		assertList(parse(s, "1,2", Long[].class), 1l, 2l);
627 		assertList(parse(s, "1,2", List.class, Long.class), 1l, 2l);
628 		assertList(parse(s, "1,2", String[].class), "1", "2");
629 		assertList(parse(s, "1,2", List.class, String.class), "1", "2");
630 		assertList(parse(s, "1,2", Object[].class), 1, 2);
631 		assertList(parse(s, "1,2", List.class, Object.class), 1, 2);
632 		assertList(parse(s,  "1,2", F1[].class), "F1-1", "F1-2");
633 		assertList(parse(s,  "1,2", List.class, F1.class), "F1-1", "F1-2");
634 		assertJson("'F2-[1,2]'", parse(s,  "1,2", F2.class));
635 	}
636 
637 	@Test void f03_integerType_int32_3d() throws Exception {
638 		var s = tArrayPipes(tArray(tInt32())).build();
639 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", int[][].class));
640 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, int[].class));
641 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Integer[][].class));
642 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Integer[].class));
643 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Integer.class));
644 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", short[][].class));
645 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, short[].class));
646 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Short[][].class));
647 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Short[].class));
648 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Short.class));
649 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", long[][].class));
650 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, long[].class));
651 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Long[][].class));
652 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Long[].class));
653 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Long.class));
654 		assertJson("[['1','2'],['3']]", parse(s, "1,2|3", String[][].class));
655 		assertJson("[['1','2'],['3']]", parse(s, "1,2|3", List.class, String[].class));
656 		assertJson("[['1','2'],['3']]", parse(s, "1,2|3", List.class, List.class, String.class));
657 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Object[][].class));
658 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Object[].class));
659 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Object.class));
660 		assertJson("[['F1-1','F1-2'],['F1-3']]", parse(s,  "1,2|3", F1[][].class));
661 		assertJson("[['F1-1','F1-2'],['F1-3']]", parse(s,  "1,2|3", List.class, F1[].class));
662 		assertJson("[['F1-1','F1-2'],['F1-3']]", parse(s,  "1,2|3", List.class, List.class, F1.class));
663 		assertJson("['F2-[1,2]','F2-[3]']", parse(s, "1,2|3", F2[].class));
664 		assertJson("['F2-[1,2]','F2-[3]']", parse(s, "1,2|3", List.class, F2.class));
665 	}
666 
667 	@Test void f04_integerType_int64() throws Exception {
668 		var s = T_INT64;
669 		assertJson("1", parse(s, "1", int.class));
670 		assertJson("1", parse(s, "1", Integer.class));
671 		assertJson("1", parse(s, "1", short.class));
672 		assertJson("1", parse(s, "1", Short.class));
673 		assertJson("1", parse(s, "1", long.class));
674 		assertJson("1", parse(s, "1", Long.class));
675 		assertJson("'1'", parse(s, "1", String.class));
676 		var o = parse(s, "1", Object.class);
677 		assertString("1", o);
678 		assertInstanceOf(Long.class, o);
679 		assertJson("1", parse(s,  "1", F3.class));
680 	}
681 
682 	@Test void f05_integerType_int64_2d() throws Exception {
683 		var s = tArray(tInt64()).build();
684 		assertList(parse(s, "1,2", int[].class), 1, 2);
685 		assertList(parse(s, "1,2", Integer[].class), 1, 2);
686 		assertList(parse(s, "1,2", List.class, Integer.class), 1, 2);
687 		assertList(parse(s, "1,2", short[].class), (short)1, (short)2);
688 		assertList(parse(s, "1,2", Short[].class), (short)1, (short)2);
689 		assertList(parse(s, "1,2", List.class, Short.class), (short)1, (short)2);
690 		assertList(parse(s, "1,2", long[].class), 1l, 2l);
691 		assertList(parse(s, "1,2", Long[].class), 1l, 2l);
692 		assertList(parse(s, "1,2", List.class, Long.class), 1l, 2l);
693 		assertList(parse(s, "1,2", String[].class), "1", "2");
694 		assertList(parse(s, "1,2", List.class, String.class), "1", "2");
695 		assertList(parse(s, "1,2", Object[].class), "1", "2");
696 		assertList(parse(s, "1,2", List.class, Object.class), "1", "2");
697 		assertBeans(parse(s,  "1,2", F3[].class), "f", "1", "2");
698 		assertBeans(parse(s,  "1,2", List.class, F3.class), "f", "1", "2");
699 		assertJson("'F4-[1,2]'", parse(s,  "1,2", F4.class));
700 	}
701 
702 	@Test void f06_integerType_int64_3d() throws Exception {
703 		var s = tArrayPipes(tArray(tInt64())).build();
704 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", int[][].class));
705 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, int[].class));
706 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Integer[][].class));
707 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Integer[].class));
708 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Integer.class));
709 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", short[][].class));
710 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, short[].class));
711 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Short[][].class));
712 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Short[].class));
713 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Short.class));
714 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", long[][].class));
715 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, long[].class));
716 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Long[][].class));
717 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Long[].class));
718 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Long.class));
719 		assertJson("[['1','2'],['3']]", parse(s, "1,2|3", String[][].class));
720 		assertJson("[['1','2'],['3']]", parse(s, "1,2|3", List.class, String[].class));
721 		assertJson("[['1','2'],['3']]", parse(s, "1,2|3", List.class, List.class, String.class));
722 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", Object[][].class));
723 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, Object[].class));
724 		assertJson("[[1,2],[3]]", parse(s, "1,2|3", List.class, List.class, Object.class));
725 		assertJson("[[1,2],[3]]", parse(s,  "1,2|3", F3[][].class));
726 		assertJson("[[1,2],[3]]", parse(s,  "1,2|3", List.class, F3[].class));
727 		assertJson("[[1,2],[3]]", parse(s,  "1,2|3", List.class, List.class, F3.class));
728 		assertJson("['F4-[1,2]','F4-[3]']", parse(s, "1,2|3", F4[].class));
729 		assertJson("['F4-[1,2]','F4-[3]']", parse(s, "1,2|3", List.class, F4.class));
730 	}
731 
732 	//-----------------------------------------------------------------------------------------------------------------
733 	// type = number
734 	//-----------------------------------------------------------------------------------------------------------------
735 
736 	public static class G1 {
737 		private float f;
738 		public G1(float in) {
739 			this.f = in;
740 		}
741 		public float toFloat() {
742 			return f;
743 		}
744 	}
745 
746 	public static class G2 {
747 		private String f;
748 		public G2(Float[] in) {
749 			this.f = "G2-" + Json5Serializer.DEFAULT.toString(in);
750 		}
751 		@Override
752 		public String toString() {
753 			return f;
754 		}
755 	}
756 
757 	public static class G3 {
758 		private Double f;
759 		public G3(double in) {
760 			this.f = in;
761 		}
762 		public double toDouble() {
763 			return f;
764 		}
765 	}
766 
767 	public static class G4 {
768 		private String f;
769 		public G4(Double[] in) {
770 			this.f = "G4-" + Json5Serializer.DEFAULT.toString(in);
771 		}
772 		@Override
773 		public String toString() {
774 			return f;
775 		}
776 	}
777 
778 	@Test void g01_numberType_float() throws Exception {
779 		var s = T_FLOAT;
780 		assertJson("1.0", parse(s, "1", float.class));
781 		assertJson("1.0", parse(s, "1", Float.class));
782 		assertJson("1.0", parse(s, "1", double.class));
783 		assertJson("1.0", parse(s, "1", Double.class));
784 		assertJson("'1.0'", parse(s, "1", String.class));
785 		var o = parse(s, "1", Object.class);
786 		assertEquals(1.0f, o);
787 		assertInstanceOf(Float.class, o);
788 		assertJson("1.0", parse(s,  "1", G1.class));
789 	}
790 
791 	@Test void g02_numberType_float_2d() throws Exception {
792 		var s = tArray(tFloat()).build();
793 		assertList(parse(s, "1,2", float[].class), 1.0f, 2.0f);
794 		assertList(parse(s, "1,2", Float[].class), 1.0f, 2.0f);
795 		assertList(parse(s, "1,2", List.class, Float.class), 1.0f, 2.0f);
796 		assertList(parse(s, "1,2", double[].class), 1.0, 2.0);
797 		assertList(parse(s, "1,2", Double[].class), 1.0, 2.0);
798 		assertList(parse(s, "1,2", List.class, Double.class), 1.0, 2.0);
799 		assertList(parse(s, "1,2", String[].class), "1.0", "2.0");
800 		assertList(parse(s, "1,2", List.class, String.class), "1.0", "2.0");
801 		assertList(parse(s, "1,2", Object[].class), 1.0f, 2.0f);
802 		assertList(parse(s, "1,2", List.class, Object.class), 1.0f, 2.0f);
803 		assertBeans(parse(s,  "1,2", G1[].class), "f", "1.0", "2.0");
804 		assertBeans(parse(s,  "1,2", List.class, G1.class), "f", "1.0", "2.0");
805 		assertJson("'G2-[1.0,2.0]'", parse(s,  "1,2", G2.class));
806 	}
807 
808 	@Test void g03_numberType_float_3d() throws Exception {
809 		var s = tArrayPipes(tArray(tFloat())).build();
810 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", float[][].class));
811 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, float[].class));
812 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", Float[][].class));
813 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, Float[].class));
814 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, List.class, Float.class));
815 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", double[][].class));
816 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, double[].class));
817 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", Double[][].class));
818 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, Double[].class));
819 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, List.class, Double.class));
820 		assertJson("[['1.0','2.0'],['3.0']]", parse(s, "1,2|3", String[][].class));
821 		assertJson("[['1.0','2.0'],['3.0']]", parse(s, "1,2|3", List.class, String[].class));
822 		assertJson("[['1.0','2.0'],['3.0']]", parse(s, "1,2|3", List.class, List.class, String.class));
823 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", Object[][].class));
824 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, Object[].class));
825 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, List.class, Object.class));
826 		assertJson("[[1.0,2.0],[3.0]]", parse(s,  "1,2|3", G1[][].class));
827 		assertJson("[[1.0,2.0],[3.0]]", parse(s,  "1,2|3", List.class, G1[].class));
828 		assertJson("[[1.0,2.0],[3.0]]", parse(s,  "1,2|3", List.class, List.class, G1.class));
829 		assertJson("['G2-[1.0,2.0]','G2-[3.0]']", parse(s, "1,2|3", G2[].class));
830 		assertJson("['G2-[1.0,2.0]','G2-[3.0]']", parse(s, "1,2|3", List.class, G2.class));
831 	}
832 
833 	@Test void g04_numberType_double() throws Exception {
834 		var s = T_DOUBLE;
835 		assertJson("1.0", parse(s, "1", float.class));
836 		assertJson("1.0", parse(s, "1", Float.class));
837 		assertJson("1.0", parse(s, "1", double.class));
838 		assertJson("1.0", parse(s, "1", Double.class));
839 		assertJson("'1.0'", parse(s, "1", String.class));
840 		var o = parse(s, "1", Object.class);
841 		assertString("1.0", o);
842 		assertInstanceOf(Double.class, o);
843 		assertJson("1.0", parse(s,  "1", G3.class));
844 	}
845 
846 	@Test void g05_numberType_double_2d() throws Exception {
847 		var s = tArray(tDouble()).build();
848 		assertList(parse(s, "1,2", float[].class), 1.0f, 2.0f);
849 		assertList(parse(s, "1,2", Float[].class), 1.0f, 2.0f);
850 		assertList(parse(s, "1,2", List.class, Float.class), 1.0f, 2.0f);
851 		assertList(parse(s, "1,2", double[].class), 1.0, 2.0);
852 		assertList(parse(s, "1,2", Double[].class), 1.0, 2.0);
853 		assertList(parse(s, "1,2", List.class, Double.class), 1.0, 2.0);
854 		assertList(parse(s, "1,2", String[].class), "1.0", "2.0");
855 		assertList(parse(s, "1,2", List.class, String.class), "1.0", "2.0");
856 		assertList(parse(s, "1,2", Object[].class), 1.0, 2.0);
857 		assertList(parse(s, "1,2", List.class, Object.class), 1.0, 2.0);
858 		assertBeans(parse(s,  "1,2", G3[].class), "f", "1.0", "2.0");
859 		assertBeans(parse(s,  "1,2", List.class, G3.class), "f", "1.0", "2.0");
860 		assertJson("'G4-[1.0,2.0]'", parse(s,  "1,2", G4.class));
861 	}
862 
863 	@Test void g06_numberType_double_3d() throws Exception {
864 		var s = tArrayPipes(tArray(tDouble())).build();
865 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", float[][].class));
866 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, float[].class));
867 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", Float[][].class));
868 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, Float[].class));
869 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, List.class, Float.class));
870 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", double[][].class));
871 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, double[].class));
872 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", Double[][].class));
873 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, Double[].class));
874 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, List.class, Double.class));
875 		assertJson("[['1.0','2.0'],['3.0']]", parse(s, "1,2|3", String[][].class));
876 		assertJson("[['1.0','2.0'],['3.0']]", parse(s, "1,2|3", List.class, String[].class));
877 		assertJson("[['1.0','2.0'],['3.0']]", parse(s, "1,2|3", List.class, List.class, String.class));
878 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", Object[][].class));
879 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, Object[].class));
880 		assertJson("[[1.0,2.0],[3.0]]", parse(s, "1,2|3", List.class, List.class, Object.class));
881 		assertJson("[[1.0,2.0],[3.0]]", parse(s,  "1,2|3", G3[][].class));
882 		assertJson("[[1.0,2.0],[3.0]]", parse(s,  "1,2|3", List.class, G3[].class));
883 		assertJson("[[1.0,2.0],[3.0]]", parse(s,  "1,2|3", List.class, List.class, G3.class));
884 		assertJson("['G4-[1.0,2.0]','G4-[3.0]']", parse(s, "1,2|3", G4[].class));
885 		assertJson("['G4-[1.0,2.0]','G4-[3.0]']", parse(s, "1,2|3", List.class, G4.class));
886 	}
887 
888 	//-----------------------------------------------------------------------------------------------------------------
889 	// type = object
890 	//-----------------------------------------------------------------------------------------------------------------
891 
892 	public static class H1 {
893 		public int f;
894 	}
895 
896 	@Test void h01_objectType() throws Exception {
897 		var s = HttpPartSchema.create().type("object").build();
898 		assertJson("{f:1}", parse(s, "f=1", H1.class));
899 		assertJson("{f:'1'}", parse(s, "f=1", JsonMap.class));
900 		var o = parse(s, "f=1", Object.class);
901 		assertBean(o, "f", "1");
902 		assertInstanceOf(JsonMap.class, o);
903 	}
904 
905 	@Test void h02_objectType_2d() throws Exception {
906 		var s = tArrayUon(tObject()).build();
907 		assertJson("[{f:1},{f:2}]", parse(s, "@((f=1),(f=2))", H1[].class));
908 		assertJson("[{f:1},{f:2}]", parse(s, "@((f=1),(f=2))", List.class, H1.class));
909 		assertJson("[{f:1},{f:2}]", parse(s, "@((f=1),(f=2))", JsonMap[].class));
910 		assertJson("[{f:1},{f:2}]", parse(s, "@((f=1),(f=2))", List.class, JsonMap.class));
911 		assertJson("[{f:1},{f:2}]", parse(s, "@((f=1),(f=2))", Object[].class));
912 		assertJson("[{f:1},{f:2}]", parse(s, "@((f=1),(f=2))", List.class, Object.class));
913 		var o = parse(s, "@((f=1),(f=2))", Object.class);
914 		assertBeans(o, "f", "1", "2");
915 		assertInstanceOf(JsonList.class, o);
916 	}
917 
918 	@Test void h03_objectType_3d() throws Exception {
919 		var s = tArrayUon(tArray(tObject())).build();
920 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", H1[][].class));
921 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", List.class, H1[].class));
922 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", List.class, List.class, H1.class));
923 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", JsonMap[][].class));
924 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", List.class, JsonMap[].class));
925 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", List.class, List.class, JsonMap.class));
926 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", Object[][].class));
927 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", List.class, Object[].class));
928 		assertJson("[[{f:1},{f:2}],[{f:3}]]", parse(s, "@(@((f=1),(f=2)),@((f=3)))", List.class, List.class, Object.class));
929 		var o = parse(s, "@(@((f=1),(f=2)),@((f=3)))", Object.class);
930 		assertBeans(o, "#{f}", "[{1},{2}]", "[{3}]");
931 		assertInstanceOf(JsonList.class, o);
932 	}
933 
934 	public static class H2 {
935 		public Object f01, f02, f03, f04, f05, f06, f07, f08, f09, f10, f11, f12, f99;
936 	}
937 
938 	@Test void h04_objectType_simpleProperties() throws Exception {
939 		var s = tObject()
940 			.p("f01", tString())
941 			.p("f02", tByte())
942 			.p("f04", tDateTime())
943 			.p("f05", tBinary())
944 			.p("f06", tBinarySpaced())
945 			.p("f07", tUon())
946 			.p("f08", tInteger())
947 			.p("f09", tInt64())
948 			.p("f10", tNumber())
949 			.p("f11", tDouble())
950 			.p("f12", tBoolean())
951 			.ap(tInteger())
952 			.build();
953 
954 		var foob = "foo".getBytes();
955 		var in = "f01=foo,f02="+base64Encode(foob)+",f04=2012-12-21T12:34:56Z,f05="+toHex(foob)+",f06="+toSpacedHex(foob)+",f07=foo,f08=1,f09=1,f10=1,f11=1,f12=true,f99=1";
956 
957 		var h2 = parse(s, in, H2.class);
958 		assertBean(h2, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "foo,666F6F,2012-12-21T12:34:56Z,666F6F,666F6F,foo,1,1,1.0,1.0,true,1");
959 		assertInstanceOf(String.class, h2.f01);
960 		assertInstanceOf(byte[].class, h2.f02);
961 		assertInstanceOf(GregorianCalendar.class, h2.f04);
962 		assertInstanceOf(byte[].class, h2.f05);
963 		assertInstanceOf(byte[].class, h2.f06);
964 		assertInstanceOf(String.class, h2.f07);
965 		assertInstanceOf(Integer.class, h2.f08);
966 		assertInstanceOf(Long.class, h2.f09);
967 		assertInstanceOf(Float.class, h2.f10);
968 		assertInstanceOf(Double.class, h2.f11);
969 		assertInstanceOf(Boolean.class, h2.f12);
970 		assertInstanceOf(Integer.class, h2.f99);
971 
972 		var om = parse(s, in, JsonMap.class);
973 		assertBean(om, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "foo,666F6F,2012-12-21T12:34:56Z,666F6F,666F6F,foo,1,1,1.0,1.0,true,1");
974 		assertInstanceOf(String.class, om.get("f01"));
975 		assertInstanceOf(byte[].class, om.get("f02"));
976 		assertInstanceOf(GregorianCalendar.class, om.get("f04"));
977 		assertInstanceOf(byte[].class, om.get("f05"));
978 		assertInstanceOf(byte[].class, om.get("f06"));
979 		assertInstanceOf(String.class, om.get("f07"));
980 		assertInstanceOf(Integer.class, om.get("f08"));
981 		assertInstanceOf(Long.class, om.get("f09"));
982 		assertInstanceOf(Float.class, om.get("f10"));
983 		assertInstanceOf(Double.class, om.get("f11"));
984 		assertInstanceOf(Boolean.class, om.get("f12"));
985 		assertInstanceOf(Integer.class, om.get("f99"));
986 
987 		om = (JsonMap)parse(s, in, Object.class);
988 		assertBean(om, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "foo,666F6F,2012-12-21T12:34:56Z,666F6F,666F6F,foo,1,1,1.0,1.0,true,1");
989 		assertInstanceOf(String.class, om.get("f01"));
990 		assertInstanceOf(byte[].class, om.get("f02"));
991 		assertInstanceOf(GregorianCalendar.class, om.get("f04"));
992 		assertInstanceOf(byte[].class, om.get("f05"));
993 		assertInstanceOf(byte[].class, om.get("f06"));
994 		assertInstanceOf(String.class, om.get("f07"));
995 		assertInstanceOf(Integer.class, om.get("f08"));
996 		assertInstanceOf(Long.class, om.get("f09"));
997 		assertInstanceOf(Float.class, om.get("f10"));
998 		assertInstanceOf(Double.class, om.get("f11"));
999 		assertInstanceOf(Boolean.class, om.get("f12"));
1000 		assertInstanceOf(Integer.class, om.get("f99"));
1001 	}
1002 
1003 	@Test void h05_objectType_arrayProperties() throws Exception {
1004 		var s = tObject()
1005 			.p("f01", tArray(tString()))
1006 			.p("f02", tArray(tByte()))
1007 			.p("f04", tArray(tDateTime()))
1008 			.p("f05", tArray(tBinary()))
1009 			.p("f06", tArray(tBinarySpaced()))
1010 			.p("f07", tArray(tUon()))
1011 			.p("f08", tArray(tInteger()))
1012 			.p("f09", tArray(tInt64()))
1013 			.p("f10", tArray(tNumber()))
1014 			.p("f11", tArray(tDouble()))
1015 			.p("f12", tArray(tBoolean()))
1016 			.ap(tArray(tInteger()))
1017 			.build();
1018 
1019 		var foob = "foo".getBytes();
1020 		var in = "f01=foo,f02="+base64Encode(foob)+",f04=2012-12-21T12:34:56Z,f05="+toHex(foob)+",f06="+toSpacedHex(foob)+",f07=foo,f08=1,f09=1,f10=1,f11=1,f12=true,f99=1";
1021 
1022 		var h2 = parse(s, in, H2.class);
1023 		assertBean(h2, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "[foo],[666F6F],[2012-12-21T12:34:56Z],[666F6F],[666F6F],[foo],[1],[1],[1.0],[1.0],[true],[1]");
1024 
1025 		var om = parse(s, in, JsonMap.class);
1026 		assertBean(om, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "[foo],[666F6F],[2012-12-21T12:34:56Z],[666F6F],[666F6F],[foo],[1],[1],[1.0],[1.0],[true],[1]");
1027 
1028 		om = (JsonMap)parse(s, in, Object.class);
1029 		assertBean(om, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "[foo],[666F6F],[2012-12-21T12:34:56Z],[666F6F],[666F6F],[foo],[1],[1],[1.0],[1.0],[true],[1]");
1030 	}
1031 
1032 	@Test void h06_objectType_arrayProperties_pipes() throws Exception {
1033 		var s = tObject()
1034 			.p("f01", tArrayPipes(tString()))
1035 			.p("f02", tArrayPipes(tByte()))
1036 			.p("f04", tArrayPipes(tDateTime()))
1037 			.p("f05", tArrayPipes(tBinary()))
1038 			.p("f06", tArrayPipes(tBinarySpaced()))
1039 			.p("f07", tArrayPipes(tUon()))
1040 			.p("f08", tArrayPipes(tInteger()))
1041 			.p("f09", tArrayPipes(tInt64()))
1042 			.p("f10", tArrayPipes(tNumber()))
1043 			.p("f11", tArrayPipes(tDouble()))
1044 			.p("f12", tArrayPipes(tBoolean()))
1045 			.ap(tArrayPipes(tInteger()))
1046 			.build();
1047 
1048 		var foob = "foo".getBytes();
1049 		var barb = "bar".getBytes();
1050 		var in = "f01=foo|bar,f02="+base64Encode(foob)+"|"+base64Encode(barb)+",f04=2012-12-21T12:34:56Z|2012-12-21T12:34:56Z,f05="+toHex(foob)+"|"+toHex(barb)+",f06="+toSpacedHex(foob)+"|"+toSpacedHex(barb)+",f07=foo|bar,f08=1|2,f09=1|2,f10=1|2,f11=1|2,f12=true|true,f99=1|2";
1051 
1052 		var h2 = parse(s, in, H2.class);
1053 		assertBean(h2, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "[foo,bar],[666F6F,626172],[2012-12-21T12:34:56Z,2012-12-21T12:34:56Z],[666F6F,626172],[666F6F,626172],[foo,bar],[1,2],[1,2],[1.0,2.0],[1.0,2.0],[true,true],[1,2]");
1054 
1055 		var om = parse(s, in, JsonMap.class);
1056 		assertBean(om, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "[foo,bar],[666F6F,626172],[2012-12-21T12:34:56Z,2012-12-21T12:34:56Z],[666F6F,626172],[666F6F,626172],[foo,bar],[1,2],[1,2],[1.0,2.0],[1.0,2.0],[true,true],[1,2]");
1057 
1058 		om = (JsonMap)parse(s, in, Object.class);
1059 		assertBean(om, "f01,f02,f04,f05,f06,f07,f08,f09,f10,f11,f12,f99", "[foo,bar],[666F6F,626172],[2012-12-21T12:34:56Z,2012-12-21T12:34:56Z],[666F6F,626172],[666F6F,626172],[foo,bar],[1,2],[1,2],[1.0,2.0],[1.0,2.0],[true,true],[1,2]");
1060 	}
1061 }