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