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.xml;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import java.util.*;
24  
25  import org.apache.juneau.*;
26  import org.apache.juneau.annotation.*;
27  import org.apache.juneau.collections.*;
28  import org.apache.juneau.xml.annotation.*;
29  import org.junit.jupiter.params.*;
30  import org.junit.jupiter.params.provider.*;
31  
32  /**
33   * Validates that comments in XML files are ignored.
34   */
35  @SuppressWarnings("serial")
36  class XmlIgnoreComments_Test extends TestBase {
37  
38  	private static final Input[] INPUT = {
39  		input( 	/* 0 */
40  			"SimpleTypes-1",
41  			String.class,
42  			"foo",
43  			"|<string>|foo|</string>|",
44  			false
45  		),
46  		input( 	/* 1 */
47  			"SimpleTypes-2",
48  			Boolean.class,
49  			true,
50  			"|<boolean>|true|</boolean>|",
51  			false
52  		),
53  		input( 	/* 2 */
54  			"SimpleTypes-3",
55  			int.class,
56  			123,
57  			"|<number>|123|</number>|",
58  			false
59  		),
60  		input( 	/* 3 */
61  			"SimpleTypes-4",
62  			float.class,
63  			1.23f,
64  			"|<number>|1.23|</number>|",
65  			false
66  		),
67  		input( 	/* 4 */
68  			"SimpleTypes-5",
69  			String.class,
70  			null,
71  			"|<null/>|",
72  			false
73  		),
74  		input( 	/* 5 */
75  			"Arrays-1",
76  			String[].class,
77  			a("foo"),
78  			"|<array>|<string>|foo|</string>|</array>|",
79  			false
80  		),
81  		input( 	/* 6 */
82  			"Arrays-2",
83  			String[].class,
84  			a((String)null),
85  			"|<array>|<null/>|</array>|",
86  			false
87  		),
88  		input( 	/* 7 */
89  			"Arrays-3",
90  			Object[].class,
91  			a("foo"),
92  			"|<array>|<string>|foo|</string>|</array>|",
93  			false
94  		),
95  		input( 	/* 8 */
96  			"Arrays-4",
97  			int[].class,
98  			ints(123),
99  			"|<array>|<number>|123|</number>|</array>|",
100 			false
101 		),
102 		input( 	/* 9 */
103 			"Arrays-5",
104 			boolean[].class,
105 			booleans(true),
106 			"|<array>|<boolean>|true|</boolean>|</array>|",
107 			false
108 		),
109 		input( 	/* 10 */
110 			"Arrays-6",
111 			String[][].class,
112 			a2(a("foo")),
113 			"|<array>|<array>|<string>|foo|</string>|</array>|</array>|",
114 			false
115 		),
116 		input( 	/* 11 */
117 			"MapWithStrings",
118 			MapWithStrings.class,
119 			new MapWithStrings().append("k1", "v1").append("k2", null),
120 			"|<object>|<k1>|v1|</k1>|<k2 _type='null'/>|</object>|",
121 			false
122 		),
123 		input( 	/* 12 */
124 			"MapsWithNumbers",
125 			MapWithNumbers.class,
126 			new MapWithNumbers().append("k1", 123).append("k2", 1.23).append("k3", null),
127 			"|<object>|<k1>|123|</k1>|<k2>|1.23|</k2>|<k3 _type='null'/>|</object>|",
128 			false
129 		),
130 		input( 	/* 13 */
131 			"MapWithObjects",
132 			MapWithObjects.class,
133 			new MapWithObjects().append("k1", "v1").append("k2", 123).append("k3", 1.23).append("k4", true).append("k5", null),
134 			"|<object>|<k1>|v1|</k1>|<k2 _type='number'>|123|</k2>|<k3 _type='number'>|1.23|</k3>|<k4 _type='boolean'>|true|</k4>|<k5 _type='null'/>|</object>|",
135 			false
136 		),
137 		input( 	/* 14 */
138 			"ListWithStrings",
139 			ListWithStrings.class,
140 			new ListWithStrings().append("foo").append(null),
141 			"|<array>|<string>|foo|</string>|<null/>|</array>|",
142 			false
143 		),
144 		input( 	/* 15 */
145 			"ListWithNumbers",
146 			ListWithNumbers.class,
147 			new ListWithNumbers().append(123).append(1.23).append(null),
148 			"|<array>|<number>|123|</number>|<number>|1.23|</number>|<null/>|</array>|",
149 			false
150 		),
151 		input( 	/* 16 */
152 			"ListWithObjects",
153 			ListWithObjects.class,
154 			new ListWithObjects().append("foo").append(123).append(1.23).append(true).append(null),
155 			"|<array>|<string>|foo|</string>|<number>|123|</number>|<number>|1.23|</number>|<boolean>|true|</boolean>|<null/>|</array>|",
156 			false
157 		),
158 		input( 	/* 17 */
159 			"BeanWithNormalProperties",
160 			BeanWithNormalProperties.class,
161 			new BeanWithNormalProperties().init(),
162 			"|<object>"
163 				+"|<a>|foo|</a>"
164 				+"|<b>|123|</b>"
165 				+"|<c>|bar|</c>"
166 				+"|<d _type='number'>|456|</d>"
167 				+"|<e>"
168 					+"|<h>|qux|</h>"
169 				+"|</e>"
170 				+"|<f>"
171 					+"|<string>|baz|</string>"
172 				+"|</f>"
173 				+"|<g>"
174 					+"|<number>|789|</number>"
175 				+"|</g>"
176 			+"|</object>|",
177 			false
178 		),
179 		input( 	/* 18 */
180 			"BeanWithMapProperties",
181 			BeanWithMapProperties.class,
182 			new BeanWithMapProperties().init(),
183 			"|<object>"
184 				+"|<a>"
185 					+"|<k1>|foo|</k1>"
186 				+"|</a>"
187 				+"|<b>"
188 					+"|<k2>|123|</k2>"
189 				+"|</b>"
190 				+"|<c>"
191 					+"|<k3>|bar|</k3>"
192 					+"|<k4 _type='number'>|456|</k4>"
193 					+"|<k5 _type='boolean'>|true|</k5>"
194 					+"|<k6 _type='null'/>"
195 				+"|</c>"
196 			+"|</object>|",
197 			false
198 		),
199 		input( 	/* 19 */
200 			"BeanWithTypeName",
201 			BeanWithTypeName.class,
202 			new BeanWithTypeName().init(),
203 			"|<X>|<a>|123|</a>|<b>|foo|</b>|</X>|",
204 			false
205 		),
206 		input( 	/* 20 */
207 			"BeanWithPropertiesWithTypeNames",
208 			BeanWithPropertiesWithTypeNames.class,
209 			new BeanWithPropertiesWithTypeNames().init(),
210 			"|<object>|<b1>|<b>|foo|</b>|</b1>|<b2 _type='B'>|<b>|foo|</b>|</b2>|</object>|",
211 			false
212 		),
213 		input( 	/* 21 */
214 			"BeanWithPropertiesWithArrayTypeNames",
215 			BeanWithPropertiesWithArrayTypeNames.class,
216 			new BeanWithPropertiesWithArrayTypeNames().init(),
217 			"|<object>"
218 				+"|<b1>"
219 					+"|<B>"
220 						+"|<b>|foo|</b>"
221 					+"|</B>"
222 				+"|</b1>"
223 				+"|<b2>"
224 					+"|<B>"
225 						+"|<b>|foo|</b>"
226 					+"|</B>"
227 				+"|</b2>"
228 				+"|<b3>"
229 					+"|<B>"
230 						+"|<b>|foo|</b>"
231 					+"|</B>"
232 				+"|</b3>"
233 			+"|</object>|",
234 			false
235 		),
236 		input( 	/* 22 */
237 			"BeanWithPropertiesWithArray2dTypeNames",
238 			BeanWithPropertiesWith2dArrayTypeNames.class,
239 			new BeanWithPropertiesWith2dArrayTypeNames().init(),
240 			"|<object>"
241 				+"|<b1>"
242 					+"|<array>"
243 						+"|<B>"
244 							+"|<b>|foo|</b>"
245 						+"|</B>"
246 					+"|</array>"
247 				+"|</b1>"
248 				+"|<b2>"
249 					+"|<array>"
250 						+"|<B>"
251 							+"|<b>|foo|</b>"
252 						+"|</B>"
253 					+"|</array>"
254 				+"|</b2>"
255 				+"|<b3>"
256 					+"|<array>"
257 						+"|<B>"
258 							+"|<b>|foo|</b>"
259 						+"|</B>"
260 					+"|</array>"
261 				+"|</b3>"
262 			+"|</object>|",
263 			false
264 		),
265 		input( 	/* 23 */
266 			"BeanWithPropertiesWithMapTypeNames",
267 			BeanWithPropertiesWithMapTypeNames.class,
268 			new BeanWithPropertiesWithMapTypeNames().init(),
269 			"|<object>"
270 				+"|<b1>"
271 					+"|<k1>"
272 						+"|<b>|foo|</b>"
273 					+"|</k1>"
274 				+"|</b1>"
275 				+"|<b2>"
276 					+"|<k2 _type='B'>"
277 						+"|<b>|foo|</b>"
278 					+"|</k2>"
279 				+"|</b2>"
280 			+"|</object>|",
281 			false
282 		),
283 		input( 	/* 24 */
284 			"BeanWithChildTypeNames",
285 			BeanWithChildTypeNames.class,
286 			new BeanWithChildTypeNames().init(),
287 			"|<object>"
288 				+"|<a>"
289 					+"|<fx>|fx1|</fx>"
290 				+"|</a>"
291 				+"|<b _type='X'>"
292 					+"|<fx>|fx1|</fx>"
293 				+"|</b>"
294 				+"|<c>"
295 					+"|<X>"
296 						+"|<fx>|fx1|</fx>"
297 					+"|</X>"
298 				+"|</c>"
299 				+"|<d>"
300 					+"|<X>"
301 						+"|<fx>|fx1|</fx>"
302 					+"|</X>"
303 				+"|</d>"
304 			+"|</object>|",
305 			false
306 		),
307 		input( 	/* 25 */
308 			"BeanWithChildName",
309 			BeanWithChildName.class,
310 			new BeanWithChildName().init(),
311 			"|<object>|<a>|<X>|foo|</X>|<X>|bar|</X>|</a>|<b>|<Y>|123|</Y>|<Y>|456|</Y>|</b>|</object>|",
312 			false
313 		),
314 		input( 	/* 26 */
315 			"BeanWithXmlFormatAttrProperty",
316 			BeanWithXmlFormatAttrProperty.class,
317 			new BeanWithXmlFormatAttrProperty().init(),
318 			"|<object a='foo' b='123'/>|",
319 			false
320 		),
321 		input( 	/* 27 */
322 			"BeanWithXmlFormatAttrs",
323 			BeanWithXmlFormatAttrs.class,
324 			new BeanWithXmlFormatAttrs().init(),
325 			"|<object a='foo' b='123'/>|",
326 			false
327 		),
328 		input( 	/* 28 */
329 			"BeanWithXmlFormatElementProperty",
330 			BeanWithXmlFormatElementProperty.class,
331 			new BeanWithXmlFormatElementProperty().init(),
332 			"|<object a='foo'><b>123</b></object>|",
333 			false
334 		),
335 		input( 	/* 29 */
336 			"BeanWithXmlFormatAttrsProperty",
337 			BeanWithXmlFormatAttrsProperty.class,
338 			new BeanWithXmlFormatAttrsProperty().init(),
339 			"|<object k1='foo' k2='123' b='456'/>|",
340 			false
341 		),
342 		input( 	/* 30 */
343 			"BeanWithXmlFormatCollapsedProperty",
344 			BeanWithXmlFormatCollapsedProperty.class,
345 			new BeanWithXmlFormatCollapsedProperty().init(),
346 			"|<object>|<A>|foo|</A>|<A>|bar|</A>|<B>|123|</B>|<B>|456|</B>|</object>|",
347 			false
348 		),
349 		input( 	/* 31 */
350 			"BeanWithXmlFormatTextProperty",
351 			BeanWithXmlFormatTextProperty.class,
352 			new BeanWithXmlFormatTextProperty().init(),
353 			"|<object a='foo'>|bar|</object>|",
354 			false
355 		),
356 		input( 	/* 32 */
357 			"BeanWithXmlFormatXmlTextProperty",
358 			BeanWithXmlFormatXmlTextProperty.class,
359 			new BeanWithXmlFormatXmlTextProperty().init(),
360 			"|<object a='foo'>|bar|<b>|baz|</b>|qux|</object>|",
361 			false
362 		),
363 		input( 	/* 33 */
364 			"BeanWithXmlFormatElementsPropertyCollection",
365 			BeanWithXmlFormatElementsPropertyCollection.class,
366 			new BeanWithXmlFormatElementsPropertyCollection().init(),
367 			"|<object a='foo'>|<string>|bar|</string>|<string>|baz|</string>|<number>|123|</number>|<boolean>|true|</boolean>|<null/>|</object>|",
368 			false
369 		),
370 		input( 	/* 34 */
371 			"BeanWithMixedContent",
372 			BeanWithMixedContent.class,
373 			new BeanWithMixedContent().init(),
374 			"|<object>|foo|<X fx='fx1'/>|bar|<Y fy='fy1'/>|baz|</object>|",
375 			true
376 		),
377 		input( 	/* 35 */
378 			"BeanWithSpecialCharacters",
379 			BeanWithSpecialCharacters.class,
380 			new BeanWithSpecialCharacters().init(),
381 			"|<object>|<a>|_x0020_ _x0008__x000C_&#x000a;&#x0009;&#x000d; _x0020_|</a>|</object>|",
382 			false
383 		),
384 		input( 	/* 36 */
385 			"BeanWithSpecialCharacters2",
386 			BeanWithSpecialCharacters2.class,
387 			new BeanWithSpecialCharacters2().init(),
388 			"|<_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>|<_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>|_x0020_ _x0008__x000C_&#x000a;&#x0009;&#x000d; _x0020_|</_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>|</_x0020__x0020__x0008__x000C__x000A__x0009__x000D__x0020__x0020_>|",
389 			false
390 		),
391 		input( 	/* 37 */
392 			"BeanWithNullProperties",
393 			BeanWithNullProperties.class,
394 			new BeanWithNullProperties(),
395 			"|<object/>|",
396 			false
397 		),
398 		input( 	/* 38 */
399 			"BeanWithAbstractFields",
400 			BeanWithAbstractFields.class,
401 			new BeanWithAbstractFields().init(),
402 			"|<object>"
403 				+"|<a>"
404 					+"|<a>|foo|</a>"
405 				+"|</a>"
406 				+"|<ia _type='A'>"
407 					+"|<a>|foo|</a>"
408 				+"|</ia>"
409 				+"|<aa _type='A'>"
410 					+"|<a>|foo|</a>"
411 				+"|</aa>"
412 				+"|<o _type='A'>"
413 					+"|<a>|foo|</a>"
414 				+"|</o>"
415 			+"|</object>|",
416 			false
417 		),
418 		input( 	/* 39 */
419 			"BeanWithAbstractArrayFields",
420 			BeanWithAbstractArrayFields.class,
421 			new BeanWithAbstractArrayFields().init(),
422 			"|<object>"
423 				+"|<a>"
424 					+"|<A>"
425 						+"|<a>|foo|</a>"
426 					+"|</A>"
427 				+"|</a>"
428 				+"|<ia1>"
429 					+"|<A>"
430 						+"|<a>|foo|</a>"
431 					+"|</A>"
432 				+"|</ia1>"
433 				+"|<ia2>"
434 					+"|<A>"
435 						+"|<a>|foo|</a>"
436 					+"|</A>"
437 				+"|</ia2>"
438 				+"|<aa1>"
439 					+"|<A>"
440 						+"|<a>|foo|</a>"
441 					+"|</A>"
442 				+"|</aa1>"
443 				+"|<aa2>"
444 					+"|<A>"
445 						+"|<a>|foo|</a>"
446 					+"|</A>"
447 				+"|</aa2>"
448 				+"|<o1>"
449 					+"|<A>"
450 						+"|<a>|foo|</a>"
451 					+"|</A>"
452 				+"|</o1>"
453 				+"|<o2>"
454 					+"|<A>"
455 						+"|<a>|foo|</a>"
456 					+"|</A>"
457 				+"|</o2>"
458 			+"|</object>",
459 			false
460 		),
461 		input( 	/* 40 */
462 			"BeanWithAbstractMapFields",
463 			BeanWithAbstractMapFields.class,
464 			new BeanWithAbstractMapFields().init(),
465 			"|<object>"
466 				+"|<a>"
467 					+"|<k1>"
468 						+"|<a>|foo|</a>"
469 					+"|</k1>"
470 				+"|</a>"
471 				+"|<b>"
472 					+"|<k2 _type='A'>"
473 						+"|<a>|foo|</a>"
474 					+"|</k2>"
475 				+"|</b>"
476 				+"|<c>"
477 					+"|<k3 _type='A'>"
478 						+"|<a>|foo|</a>"
479 					+"|</k3>"
480 				+"|</c>"
481 			+"|</object>",
482 			false
483 		),
484 		input( 	/* 41 */
485 			"BeanWithAbstractMapArrayFields",
486 			BeanWithAbstractMapArrayFields.class,
487 			new BeanWithAbstractMapArrayFields().init(),
488 			"|<object>"
489 				+"|<a>"
490 					+"|<a1>"
491 						+"|<A>"
492 							+"|<a>|foo|</a>"
493 						+"|</A>"
494 					+"|</a1>"
495 				+"|</a>"
496 				+"|<ia>"
497 					+"|<ia1>"
498 						+"|<A>"
499 							+"|<a>|foo|</a>"
500 						+"|</A>"
501 					+"|</ia1>"
502 					+"|<ia2>"
503 						+"|<A>"
504 							+"|<a>|foo|</a>"
505 						+"|</A>"
506 					+"|</ia2>"
507 				+"|</ia>"
508 				+"|<aa>"
509 					+"|<aa1>"
510 						+"|<A>"
511 							+"|<a>|foo|</a>"
512 						+"|</A>"
513 					+"|</aa1>"
514 					+"|<aa2>"
515 						+"|<A>"
516 							+"|<a>|foo|</a>"
517 						+"|</A>"
518 					+"|</aa2>"
519 				+"|</aa>"
520 				+"|<o>"
521 					+"|<o1>"
522 						+"|<A>"
523 							+"|<a>|foo|</a>"
524 						+"|</A>"
525 					+"|</o1>"
526 					+"|<o2>"
527 						+"|<A>"
528 							+"|<a>|foo|</a>"
529 						+"|</A>"
530 					+"|</o2>"
531 				+"|</o>"
532 			+"|</object>",
533 			false
534 		),
535 		input( 	/* 42 */
536 			"BeanWithWhitespaceTextFields-1",
537 			BeanWithWhitespaceTextFields.class,
538 			new BeanWithWhitespaceTextFields().init(null),
539 			"|<object/>|",
540 			false
541 		),
542 		input( 	/* 43 */
543 			"BeanWithWhitespaceTextFields-2",
544 			BeanWithWhitespaceTextFields.class,
545 			new BeanWithWhitespaceTextFields().init(""),
546 			"|<object>|_xE000_|</object>|",
547 			false
548 		),
549 		input( 	/* 44 */
550 			"BeanWithWhitespaceTextFields-3",
551 			BeanWithWhitespaceTextFields.class,
552 			new BeanWithWhitespaceTextFields().init(" "),
553 			"|<object>|_x0020_|</object>|",
554 			false
555 		),
556 		input( 	/* 45 */
557 			"BeanWithWhitespaceTextFields-4",
558 			BeanWithWhitespaceTextFields.class,
559 			new BeanWithWhitespaceTextFields().init("  "),
560 			"|<object>|_x0020__x0020_|</object>|",
561 			false
562 		),
563 		input( 	/* 46 */
564 			"BeanWithWhitespaceTextFields-5",
565 			BeanWithWhitespaceTextFields.class,
566 			new BeanWithWhitespaceTextFields().init(" foo\n\tbar "),
567 			"|<object>|_x0020_foo&#x000a;&#x0009;bar_x0020_|</object>|",
568 			false
569 		),
570 		input( 	/* 47 */
571 			"BeanWithWhitespaceTextPwsFields-1",
572 			BeanWithWhitespaceTextPwsFields.class,
573 			new BeanWithWhitespaceTextPwsFields().init(null),
574 			"|<object/>|",
575 			false
576 		),
577 		input( 	/* 48 */
578 			"BeanWithWhitespaceTextPwsFields-2",
579 			BeanWithWhitespaceTextPwsFields.class,
580 			new BeanWithWhitespaceTextPwsFields().init(""),
581 			"|<object>|_xE000_|</object>|",
582 			true
583 		),
584 		input( 	/* 49 */
585 			"BeanWithWhitespaceTextPwsFields-3",
586 			BeanWithWhitespaceTextPwsFields.class,
587 			new BeanWithWhitespaceTextPwsFields().init(" "),
588 			"|<object>| |</object>|",
589 			true
590 		),
591 		input( 	/* 50 */
592 			"BeanWithWhitespaceTextPwsFields-4",
593 			BeanWithWhitespaceTextPwsFields.class,
594 			new BeanWithWhitespaceTextPwsFields().init("  "),
595 			"|<object>|  |</object>|",
596 			true
597 		),
598 		input( 	/* 51 */
599 			"BeanWithWhitespaceTextPwsFields-5",
600 			BeanWithWhitespaceTextPwsFields.class,
601 			new BeanWithWhitespaceTextPwsFields().init("  foobar  "),
602 			"|<object>|  foobar  |</object>|",
603 			true
604 		),
605 		input( 	/* 52 */
606 			"BeanWithWhitespaceMixedFields-1",
607 			BeanWithWhitespaceMixedFields.class,
608 			new BeanWithWhitespaceMixedFields().init(null),
609 			"|<object nil='true'></object>|",
610 			false
611 		),
612 		input( 	/* 53 */
613 			"BeanWithWhitespaceMixedFields-3",
614 			BeanWithWhitespaceMixedFields.class,
615 			new BeanWithWhitespaceMixedFields().init(a("")),
616 			"|<object>|_xE000_|</object>|",
617 			true
618 		),
619 		input( 	/* 54 */
620 			"BeanWithWhitespaceMixedFields-4",
621 			BeanWithWhitespaceMixedFields.class,
622 			new BeanWithWhitespaceMixedFields().init(a(" ")),
623 			"|<object>|_x0020_|</object>|",
624 			true
625 		),
626 		input( 	/* 55 */
627 			"BeanWithWhitespaceMixedFields-5",
628 			BeanWithWhitespaceMixedFields.class,
629 			new BeanWithWhitespaceMixedFields().init(a("  ")),
630 			"|<object>|_x0020__x0020_|</object>|",
631 			true
632 		),
633 		input( 	/* 56 */
634 			"BeanWithWhitespaceMixedFields-6",
635 			BeanWithWhitespaceMixedFields.class,
636 			new BeanWithWhitespaceMixedFields().init(a("  foobar  ")),
637 			"|<object>|_x0020_ foobar _x0020_|</object>|",
638 			true
639 		),
640 		input( 	/* 57 */
641 			"BeanWithWhitespaceMixedPwsFields-1",
642 			BeanWithWhitespaceMixedPwsFields.class,
643 			new BeanWithWhitespaceMixedPwsFields().init(null),
644 			"|<object nil='true'></object>|",
645 			false
646 		),
647 		input( 	/* 58 */
648 			"BeanWithWhitespaceMixedPwsFields-3",
649 			BeanWithWhitespaceMixedPwsFields.class,
650 			new BeanWithWhitespaceMixedPwsFields().init(a("")),
651 			"|<object>|_xE000_|</object>|",
652 			true
653 		),
654 		input( 	/* 59 */
655 			"BeanWithWhitespaceMixedPwsFields-4",
656 			BeanWithWhitespaceMixedPwsFields.class,
657 			new BeanWithWhitespaceMixedPwsFields().init(a(" ")),
658 			"|<object>| |</object>|",
659 			true
660 		),
661 		input( 	/* 60 */
662 			"BeanWithWhitespaceMixedPwsFields-5",
663 			BeanWithWhitespaceMixedPwsFields.class,
664 			new BeanWithWhitespaceMixedPwsFields().init(a("  ")),
665 			"|<object>|  |</object>|",
666 			true
667 		),
668 		input( 	/* 61 */
669 			"BeanWithWhitespaceMixedPwsFields-6",
670 			BeanWithWhitespaceMixedPwsFields.class,
671 			new BeanWithWhitespaceMixedPwsFields().init(a("  foobar  ")),
672 			"|<object>|  foobar  |</object>|",
673 			true
674 		)
675 	};
676 
677 	private static class Input {
678 		final String label;
679 		final Class<?> type;
680 		final Object expected;
681 		final String input;
682 		final boolean skipWsTests;
683 
684 		Input(String label, Class<?> type, Object expected, String input, boolean skipWsTests) {
685 			this.label = label;
686 			this.type = type;
687 			this.expected = expected;
688 			this.input = input;
689 			this.skipWsTests = skipWsTests;
690 		}
691 	}
692 
693 	private static Input input(String label, Class<?> type, Object expected, String input, boolean skipWsTests) {
694 		return new Input(label, type, expected, input, skipWsTests);
695 	}
696 
697 	static Input[] input() {
698 		return INPUT;
699 	}
700 
701 	@ParameterizedTest
702 	@MethodSource("input")
703 	void a01_noComment(Input input) throws Exception {
704 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", ""), input.type);
705 		assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
706 	}
707 
708 	@ParameterizedTest
709 	@MethodSource("input")
710 	void a02_normalComment(Input input) throws Exception {
711 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", "<!--x-->"), input.type);
712 		assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
713 	}
714 
715 	@ParameterizedTest
716 	@MethodSource("input")
717 	void a03_commentWithWhitespace(Input input) throws Exception {
718 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", " \n <!-- \n x \n --> \n "), input.type);
719 		if (! input.skipWsTests)
720 			assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
721 	}
722 
723 	@ParameterizedTest
724 	@MethodSource("input")
725 	void a04_doubleCommentsWithWhitespace(Input input) throws Exception {
726 		var actual = XmlParser.DEFAULT.parse(input.input.replace("|", " \n <!-- \n x \n --> \n \n <!-- \n x \n --> \n "), input.type);
727 		if (! input.skipWsTests)
728 			assertEquals(json(actual), json(input.expected), fs("Test ''{0}'' failed with comparison error", input.label));
729 	}
730 
731 	//-----------------------------------------------------------------------------------------------------------------
732 	// Test beans
733 	//-----------------------------------------------------------------------------------------------------------------
734 
735 	public static class MapWithStrings extends LinkedHashMap<String,String> {
736 		public MapWithStrings append(String key, String value) {
737 			put(key, value);
738 			return this;
739 		}
740 	}
741 
742 	public static class MapWithNumbers extends LinkedHashMap<String,Number> {
743 		public MapWithNumbers append(String key, Number value) {
744 			put(key, value);
745 			return this;
746 		}
747 	}
748 
749 	public static class MapWithObjects extends LinkedHashMap<String,Object> {
750 		public MapWithObjects append(String key, Object value) {
751 			put(key, value);
752 			return this;
753 		}
754 	}
755 
756 	public static class ListWithStrings extends ArrayList<String> {
757 		public ListWithStrings append(String value) {
758 			this.add(value);
759 			return this;
760 		}
761 	}
762 
763 	public static class ListWithNumbers extends ArrayList<Number> {
764 		public ListWithNumbers append(Number value) {
765 			this.add(value);
766 			return this;
767 		}
768 	}
769 
770 	public static class ListWithObjects extends ArrayList<Object> {
771 		public ListWithObjects append(Object value) {
772 			this.add(value);
773 			return this;
774 		}
775 	}
776 
777 	public static class BeanWithNormalProperties {
778 		public String a;
779 		public int b;
780 		public Object c;
781 		public Object d;
782 		public Bean1a e;
783 		public String[] f;
784 		public int[] g;
785 
786 		BeanWithNormalProperties init() {
787 			a = "foo";
788 			b = 123;
789 			c = "bar";
790 			d = 456;
791 			e = new Bean1a().init();
792 			f = a("baz");
793 			g = ints( 789 );
794 			return this;
795 		}
796 	}
797 
798 	public static class Bean1a {
799 		public String h;
800 
801 		Bean1a init() {
802 			h = "qux";
803 			return this;
804 		}
805 	}
806 
807 	public static class BeanWithMapProperties {
808 		@Beanp(type=MapWithStrings.class)
809 		public Map<String,String> a;
810 		@Beanp(type=MapWithNumbers.class)
811 		public Map<String,Number> b;
812 		@Beanp(type=MapWithObjects.class)
813 		public Map<String,Object> c;
814 
815 		BeanWithMapProperties init() {
816 			a = new MapWithStrings().append("k1","foo");
817 			b = new MapWithNumbers().append("k2",123);
818 			c = new MapWithObjects().append("k3","bar").append("k4",456).append("k5",true).append("k6",null);
819 			return this;
820 		}
821 	}
822 
823 	@Bean(typeName="X")
824 	public static class BeanWithTypeName {
825 		public int a;
826 		public String b;
827 
828 		BeanWithTypeName init() {
829 			a = 123;
830 			b = "foo";
831 			return this;
832 		}
833 	}
834 
835 	@Bean(dictionary={B.class})
836 	public static class BeanWithPropertiesWithTypeNames {
837 		public B b1;
838 		public Object b2;
839 
840 		BeanWithPropertiesWithTypeNames init() {
841 			b1 = new B().init();
842 			b2 = new B().init();
843 			return this;
844 		}
845 	}
846 
847 	@Bean(dictionary={B.class})
848 	public static class BeanWithPropertiesWithArrayTypeNames {
849 		public B[] b1;
850 		public Object[] b2;
851 		public Object[] b3;
852 
853 		BeanWithPropertiesWithArrayTypeNames init() {
854 			b1 = a(new B().init());
855 			b2 = a(new B().init());
856 			b3 = ao(new B().init());
857 			return this;
858 		}
859 	}
860 
861 	@Bean(dictionary={B.class})
862 	public static class BeanWithPropertiesWith2dArrayTypeNames {
863 		public B[][] b1;
864 		public Object[][] b2;
865 		public Object[][] b3;
866 
867 		BeanWithPropertiesWith2dArrayTypeNames init() {
868 			b1 = a2(a(new B().init()));
869 			b2 = a2(a(new B().init()));
870 			b3 = a2(ao(new B().init()));
871 			return this;
872 		}
873 	}
874 
875 	@Bean(dictionary={B.class})
876 	public static class BeanWithPropertiesWithMapTypeNames {
877 		public Map<String,B> b1;
878 		public Map<String,Object> b2;
879 
880 		BeanWithPropertiesWithMapTypeNames init() {
881 			b1 = new HashMap<>();
882 			b1.put("k1", new B().init());
883 			b2 = new HashMap<>();
884 			b2.put("k2", new B().init());
885 			return this;
886 		}
887 	}
888 
889 	@Bean(typeName="B")
890 	public static class B {
891 		public String b;
892 
893 		B init() {
894 			b = "foo";
895 			return this;
896 		}
897 	}
898 
899 	public static class BeanWithChildTypeNames {
900 		public BeanX a;
901 		@Beanp(dictionary=BeanX.class)
902 		public Object b;
903 		public BeanX[] c;
904 		@Beanp(dictionary=BeanX.class)
905 		public Object[] d;
906 		BeanWithChildTypeNames init() {
907 			a = new BeanX().init();
908 			b = new BeanX().init();
909 			c = a(new BeanX().init());
910 			d = a(new BeanX().init());
911 			return this;
912 		}
913 	}
914 
915 	public static class BeanWithChildName {
916 		@Xml(childName = "X")
917 		public String[] a;
918 		@Xml(childName = "Y")
919 		public int[] b;
920 		BeanWithChildName init() {
921 			a = a("foo", "bar");
922 			b = ints( 123, 456 );
923 			return this;
924 		}
925 	}
926 
927 	public static class BeanWithXmlFormatAttrProperty {
928 		@Xml(format=XmlFormat.ATTR)
929 		public String a;
930 		@Xml(format=XmlFormat.ATTR)
931 		public int b;
932 		BeanWithXmlFormatAttrProperty init() {
933 			a = "foo";
934 			b = 123;
935 			return this;
936 		}
937 	}
938 
939 	@Xml(format=XmlFormat.ATTRS)
940 	public static class BeanWithXmlFormatAttrs {
941 		public String a;
942 		public int b;
943 		BeanWithXmlFormatAttrs init() {
944 			a = "foo";
945 			b = 123;
946 			return this;
947 		}
948 	}
949 
950 	@Xml(format=XmlFormat.ATTRS)
951 	public static class BeanWithXmlFormatElementProperty {
952 		public String a;
953 		@Xml(format=XmlFormat.ELEMENT)
954 		public int b;
955 		BeanWithXmlFormatElementProperty init() {
956 			a = "foo";
957 			b = 123;
958 			return this;
959 		}
960 	}
961 
962 	public static class BeanWithXmlFormatAttrsProperty {
963 		@Xml(format=XmlFormat.ATTRS)
964 		public Map<String,Object> a;
965 		@Xml(format=XmlFormat.ATTR)
966 		public int b;
967 		BeanWithXmlFormatAttrsProperty init() {
968 			a = JsonMap.of("k1", "foo", "k2", "123");
969 			b = 456;
970 			return this;
971 		}
972 	}
973 
974 	public static class BeanWithXmlFormatCollapsedProperty {
975 		@Xml(childName="A",format=XmlFormat.COLLAPSED)
976 		public String[] a;
977 		@Xml(childName="B",format=XmlFormat.COLLAPSED)
978 		public int[] b;
979 		BeanWithXmlFormatCollapsedProperty init() {
980 			a = a("foo","bar");
981 			b = ints(123,456);
982 			return this;
983 		}
984 	}
985 
986 	public static class BeanWithXmlFormatTextProperty {
987 		@Xml(format=XmlFormat.ATTR)
988 		public String a;
989 		@Xml(format=XmlFormat.TEXT)
990 		public String b;
991 		BeanWithXmlFormatTextProperty init() {
992 			a = "foo";
993 			b = "bar";
994 			return this;
995 		}
996 	}
997 
998 	public static class BeanWithXmlFormatXmlTextProperty {
999 		@Xml(format=XmlFormat.ATTR)
1000 		public String a;
1001 		@Xml(format=XmlFormat.XMLTEXT)
1002 		public String b;
1003 		BeanWithXmlFormatXmlTextProperty init() {
1004 			a = "foo";
1005 			b = "bar<b>baz</b>qux";
1006 			return this;
1007 		}
1008 	}
1009 
1010 	public static class BeanWithXmlFormatElementsPropertyCollection {
1011 		@Xml(format=XmlFormat.ATTR)
1012 		public String a;
1013 		@Xml(format=XmlFormat.ELEMENTS)
1014 		public Object[] b;
1015 		BeanWithXmlFormatElementsPropertyCollection init() {
1016 			a = "foo";
1017 			b = a("bar","baz",123,true,null);
1018 			return this;
1019 		}
1020 	}
1021 
1022 	public static class BeanWithMixedContent {
1023 		@Xml(format=XmlFormat.MIXED)
1024 		@Beanp(dictionary={BeanXSimple.class, BeanYSimple.class})
1025 		public Object[] a;
1026 		BeanWithMixedContent init() {
1027 			a = a(
1028 				"foo",
1029 				new BeanXSimple().init(),
1030 				"bar",
1031 				new BeanYSimple().init(),
1032 				"baz"
1033 			);
1034 			return this;
1035 		}
1036 	}
1037 
1038 	@Bean(typeName="X")
1039 	public static class BeanX {
1040 		public String fx;
1041 		BeanX init() {
1042 			fx = "fx1";
1043 			return this;
1044 		}
1045 	}
1046 
1047 	@Bean(typeName="X")
1048 	public static class BeanXSimple {
1049 		@Xml(format=XmlFormat.ATTR)
1050 		public String fx;
1051 		BeanXSimple init() {
1052 			fx = "fx1";
1053 			return this;
1054 		}
1055 	}
1056 
1057 	@Bean(typeName="Y")
1058 	public static class BeanY {
1059 		public String fy;
1060 		BeanY init() {
1061 			fy = "fy1";
1062 			return this;
1063 		}
1064 	}
1065 
1066 	@Bean(typeName="Y")
1067 	public static class BeanYSimple {
1068 		@Xml(format=XmlFormat.ATTR)
1069 		public String fy;
1070 		BeanYSimple init() {
1071 			fy = "fy1";
1072 			return this;
1073 		}
1074 	}
1075 
1076 	public static class BeanWithSpecialCharacters {
1077 		public String a;
1078 
1079 		BeanWithSpecialCharacters init() {
1080 			a = "  \b\f\n\t\r  ";
1081 			return this;
1082 		}
1083 	}
1084 
1085 	@Bean(typeName="  \b\f\n\t\r  ")
1086 	public static class BeanWithSpecialCharacters2 {
1087 
1088 		@Beanp(name="  \b\f\n\t\r  ")
1089 		public String a;
1090 
1091 		BeanWithSpecialCharacters2 init() {
1092 			a = "  \b\f\n\t\r  ";
1093 			return this;
1094 		}
1095 	}
1096 
1097 	public static class BeanWithNullProperties {
1098 		public String a;
1099 		public String[] b;
1100 	}
1101 
1102 	@Bean(dictionary={A.class})
1103 	public static class BeanWithAbstractFields {
1104 		public A a;
1105 		public IA ia;
1106 		public AA aa;
1107 		public Object o;
1108 
1109 		BeanWithAbstractFields init() {
1110 			ia = new A().init();
1111 			aa = new A().init();
1112 			a = new A().init();
1113 			o = new A().init();
1114 			return this;
1115 		}
1116 	}
1117 
1118 	@Bean(dictionary={A.class})
1119 	public static class BeanWithAbstractArrayFields {
1120 		public A[] a;
1121 		public IA[] ia1, ia2;
1122 		public AA[] aa1, aa2;
1123 		public Object[] o1, o2;
1124 
1125 		BeanWithAbstractArrayFields init() {
1126 			a = a(new A().init());
1127 			ia1 = a(new A().init());
1128 			aa1 = a(new A().init());
1129 			o1 = a(new A().init());
1130 			ia2 = a(new A().init());
1131 			aa2 = a(new A().init());
1132 			o2 = a(new A().init());
1133 			return this;
1134 		}
1135 	}
1136 
1137 	@Bean(dictionary={A.class})
1138 	public static class BeanWithAbstractMapFields {
1139 		public Map<String,A> a;
1140 		public Map<String,AA> b;
1141 		public Map<String,Object> c;
1142 
1143 		BeanWithAbstractMapFields init() {
1144 			a = new HashMap<>();
1145 			b = new HashMap<>();
1146 			c = new HashMap<>();
1147 			a.put("k1", new A().init());
1148 			b.put("k2", new A().init());
1149 			c.put("k3", new A().init());
1150 			return this;
1151 		}
1152 	}
1153 
1154 	@Bean(dictionary={A.class})
1155 	public static class BeanWithAbstractMapArrayFields {
1156 		public Map<String,A[]> a;
1157 		public Map<String,IA[]> ia;
1158 		public Map<String,AA[]> aa;
1159 		public Map<String,Object[]> o;
1160 
1161 		BeanWithAbstractMapArrayFields init() {
1162 			a = map();
1163 			ia = map();
1164 			aa = map();
1165 			o = map();
1166 			a.put("a1", a(new A().init()));
1167 			ia.put("ia1", a(new A().init()));
1168 			ia.put("ia2", a((IA)new A().init()));
1169 			aa.put("aa1", a(new A().init()));
1170 			aa.put("aa2", a((AA)new A().init()));
1171 			o.put("o1", a(new A().init()));
1172 			o.put("o2", ao(new A().init()));
1173 			return this;
1174 		}
1175 	}
1176 
1177 	public interface IA {
1178 		String getA();
1179 		void setA(String a);
1180 	}
1181 
1182 	public abstract static class AA implements IA {}
1183 
1184 	@Bean(typeName="A")
1185 	public static class A extends AA {
1186 		private String a;
1187 		@Override public String getA() { return a; }
1188 		@Override public void setA(String v) { a = v; }
1189 
1190 		A init() {
1191 			this.a = "foo";
1192 			return this;
1193 		}
1194 	}
1195 
1196 	public static class BeanWithWhitespaceTextFields {
1197 		@Xml(format=XmlFormat.TEXT)
1198 		public String a;
1199 
1200 		public BeanWithWhitespaceTextFields init(String s) {
1201 			a = s;
1202 			return this;
1203 		}
1204 	}
1205 
1206 	public static class BeanWithWhitespaceTextPwsFields {
1207 		@Xml(format=XmlFormat.TEXT_PWS)
1208 		public String a;
1209 
1210 		public BeanWithWhitespaceTextPwsFields init(String s) {
1211 			a = s;
1212 			return this;
1213 		}
1214 	}
1215 
1216 	public static class BeanWithWhitespaceMixedFields {
1217 		@Xml(format=XmlFormat.MIXED)
1218 		public String[] a;
1219 
1220 		public BeanWithWhitespaceMixedFields init(String[] s) {
1221 			a = s;
1222 			return this;
1223 		}
1224 	}
1225 
1226 	public static class BeanWithWhitespaceMixedPwsFields {
1227 		@Xml(format=XmlFormat.MIXED_PWS)
1228 		public String[] a;
1229 
1230 		public BeanWithWhitespaceMixedPwsFields init(String[] s) {
1231 			a = s;
1232 			return this;
1233 		}
1234 	}
1235 }