1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.rest.annotation;
18
19 import static org.apache.juneau.TestUtils.*;
20 import static org.apache.juneau.commons.utils.CollectionUtils.*;
21 import static org.apache.juneau.commons.utils.IoUtils.*;
22 import static org.apache.juneau.http.header.ContentType.*;
23 import static org.junit.jupiter.api.Assertions.*;
24
25 import java.io.*;
26 import java.util.*;
27
28 import org.apache.juneau.*;
29 import org.apache.juneau.annotation.*;
30 import org.apache.juneau.http.annotation.*;
31 import org.apache.juneau.json.*;
32 import org.apache.juneau.marshaller.*;
33 import org.apache.juneau.rest.mock.*;
34 import org.apache.juneau.testutils.pojos.*;
35 import org.apache.juneau.uon.*;
36 import org.apache.juneau.urlencoding.*;
37 import org.apache.juneau.urlencoding.annotation.*;
38 import org.apache.juneau.urlencoding.annotation.UrlEncoding;
39 import org.junit.jupiter.api.*;
40
41 class Content_Test extends TestBase {
42
43
44
45
46
47 @Rest(serializers=Json5Serializer.class, parsers=JsonParser.class, defaultAccept="text/json")
48 public static class A {
49 @RestPut(path="/String")
50 public String a(@Content String b) {
51 return b;
52 }
53 @RestPut(path="/Integer")
54 public Integer b(@Content Integer b) {
55 return b;
56 }
57 @RestPut(path="/int")
58 public Integer c(@Content int b) {
59 return b;
60 }
61 @RestPut(path="/Boolean")
62 public Boolean d(@Content Boolean b) {
63 return b;
64 }
65 @RestPut(path="/boolean")
66 public Boolean e(@Content boolean b) {
67 return b;
68 }
69 @RestPut(path="/float")
70 public float f(@Content float f) {
71 return f;
72 }
73 @RestPut(path="/Float")
74 public Float g(@Content Float f) {
75 return f;
76 }
77 @RestPut(path="/Map")
78 public TreeMap<String,Integer> h(@Content TreeMap<String,Integer> m) {
79 return m;
80 }
81 @RestPut(path="/enum")
82 public TestEnum i(@Content TestEnum e) {
83 return e;
84 }
85 public static class A11 {
86 public String f1;
87 }
88 @RestPut(path="/Bean")
89 public A11 j(@Content A11 b) {
90 return b;
91 }
92 @RestPut(path="/InputStream")
93 public String k(@Content InputStream b) throws Exception {
94 return read(b);
95 }
96 @RestPut(path="/Reader")
97 public String l(@Content Reader b) throws Exception {
98 return read(b);
99 }
100 @RestPut(path="/InputStreamTransform")
101 public A14 m(@Content A14 b) {
102 return b;
103 }
104 public static class A14 {
105 String s;
106 public A14(InputStream in) throws Exception { this.s = read(in); }
107 @Override public String toString() { return s; }
108 }
109 @RestPut(path="/ReaderTransform")
110 public A15 n(@Content A15 b) {
111 return b;
112 }
113 public static class A15 {
114 private String s;
115 public A15(Reader in) throws Exception { this.s = read(in); }
116 @Override public String toString() { return s; }
117 }
118 @RestPut(path="/StringTransform")
119 public A16 o(@Content A16 b) { return b; }
120 public static class A16 {
121 private String s;
122 public A16(String s) { this.s = s; }
123 @Override public String toString() { return s; }
124 }
125 }
126
127 @Test void a01_onParameters() throws Exception {
128 var a = MockRestClient.buildLax(A.class);
129
130 a.put("/String", "foo")
131 .json()
132 .run()
133 .assertContent("'foo'");
134
135 a.put("/String", "'foo'")
136 .run()
137 .assertContent("'\\'foo\\''");
138
139 a.put("/String", "'foo'").contentType("")
140 .run()
141 .assertContent("'\\'foo\\''");
142 a.put("/String", "'foo'").contentType("text/plain")
143 .run()
144 .assertContent("'\\'foo\\''");
145 a.put("/String?content=foo", null)
146 .run()
147 .assertContent("'foo'");
148 a.put("/String?content=null", null)
149 .run()
150 .assertContent("null");
151 a.put("/String?content=", null)
152 .run()
153 .assertContent("''");
154
155 a.put("/Integer", "123").json()
156 .run()
157 .assertContent("123");
158
159 a.put("/Integer", "123")
160 .run()
161 .assertContent("123");
162 a.put("/Integer?content=123", null)
163 .run()
164 .assertContent("123");
165 a.put("/Integer?content=-123", null)
166 .run()
167 .assertContent("-123");
168 a.put("/Integer?content=null", null)
169 .run()
170 .assertContent("null");
171 a.put("/Integer?content=", null)
172 .run()
173 .assertContent("null");
174 a.put("/Integer?content=bad&noTrace=true", null)
175 .run()
176 .assertStatus(400);
177
178 a.put("/int", "123").json()
179 .run()
180 .assertContent("123");
181 a.put("/int", "123")
182 .run()
183 .assertContent("123");
184 a.put("/int?content=123", null)
185 .run()
186 .assertContent("123");
187 a.put("/int?content=-123", null)
188 .run()
189 .assertContent("-123");
190 a.put("/int?content=null", null)
191 .run()
192 .assertContent("0");
193 a.put("/int?content=", null)
194 .run()
195 .assertContent("0");
196 a.put("/int?content=bad&noTrace=true", null)
197 .run()
198 .assertStatus(400);
199
200 a.put("/Boolean", "true").json()
201 .run()
202 .assertContent("true");
203
204 a.put("/Boolean", "true")
205 .run()
206 .assertContent("true");
207 a.put("/Boolean?content=true", null)
208 .run()
209 .assertContent("true");
210 a.put("/Boolean?content=false", null)
211 .run()
212 .assertContent("false");
213 a.put("/Boolean?content=null", null)
214 .run()
215 .assertContent("null");
216 a.put("/Boolean?content=", null)
217 .run()
218 .assertContent("null");
219 a.put("/Boolean?content=bad&noTrace=true", null)
220 .run()
221 .assertStatus(400);
222
223 a.put("/boolean", "true").json()
224 .run()
225 .assertContent("true");
226 a.put("/boolean", "true")
227 .run()
228 .assertContent("true");
229 a.put("/boolean?content=true", null)
230 .run()
231 .assertContent("true");
232 a.put("/boolean?content=false", null)
233 .run()
234 .assertContent("false");
235 a.put("/boolean?content=null", null)
236 .run()
237 .assertContent("false");
238 a.put("/boolean?content=", null)
239 .run()
240 .assertContent("false");
241 a.put("/boolean?content=bad&noTrace=true", null)
242 .run()
243 .assertStatus(400);
244
245 a.put("/float", "1.23").json()
246 .run()
247 .assertContent("1.23");
248 a.put("/float", "1.23")
249 .run()
250 .assertContent("1.23");
251 a.put("/float?content=1.23", null)
252 .run()
253 .assertContent("1.23");
254 a.put("/float?content=-1.23", null)
255 .run()
256 .assertContent("-1.23");
257 a.put("/float?content=null", null)
258 .run()
259 .assertContent("0.0");
260 a.put("/float?content=", null)
261 .run()
262 .assertContent("0.0");
263 a.put("/float?content=bad&noTrace=true", null)
264 .run()
265 .assertStatus(400);
266
267 a.put("/Float", "1.23").json()
268 .run()
269 .assertContent("1.23");
270
271 a.put("/Float", "1.23")
272 .run()
273 .assertContent("1.23");
274 a.put("/Float?content=1.23", null)
275 .run()
276 .assertContent("1.23");
277 a.put("/Float?content=-1.23", null)
278 .run()
279 .assertContent("-1.23");
280 a.put("/Float?content=null", null)
281 .run()
282 .assertContent("null");
283 a.put("/Float?content=", null)
284 .run()
285 .assertContent("null");
286 a.put("/Float?content=bad&noTrace=true", null)
287 .run()
288 .assertStatus(400);
289
290 a.put("/Map", "{foo:123}", APPLICATION_JSON)
291 .run()
292 .assertContent("{foo:123}");
293 a.put("/Map", "(foo=123)", TEXT_OPENAPI)
294 .run()
295 .assertStatus(415);
296 a.put("/Map?content=(foo=123)", null)
297 .run()
298 .assertContent("{foo:123}");
299 a.put("/Map?content=()", null)
300 .run()
301 .assertContent("{}");
302 a.put("/Map?content=null", null)
303 .run()
304 .assertContent("null");
305 a.put("/Map?content=", null)
306 .run()
307 .assertContent("null");
308 a.put("/Map?content=bad&noTrace=true", null)
309 .run()
310 .assertStatus(400);
311
312 a.put("/enum", "'ONE'", APPLICATION_JSON)
313 .run()
314 .assertContent("'ONE'");
315 a.put("/enum", "ONE")
316 .run()
317 .assertContent("'ONE'");
318 a.put("/enum?content=ONE", null)
319 .run()
320 .assertContent("'ONE'");
321 a.put("/enum?content=TWO", null)
322 .run()
323 .assertContent("'TWO'");
324 a.put("/enum?content=null", null)
325 .run()
326 .assertContent("null");
327 a.put("/enum?content=", null)
328 .run()
329 .assertContent("null");
330 a.put("/enum?content=bad&noTrace=true", null)
331 .run()
332 .assertStatus(400);
333
334 a.put("/Bean", "{f1:'a'}", APPLICATION_JSON)
335 .run()
336 .assertContent("{f1:'a'}");
337 a.put("/Bean", "(f1=a)", TEXT_OPENAPI)
338 .run()
339 .assertStatus(415);
340 a.put("/Bean?content=(f1=a)", null)
341 .run()
342 .assertContent("{f1:'a'}");
343 a.put("/Bean?content=()", null)
344 .run()
345 .assertContent("{}");
346 a.put("/Bean?content=null", null)
347 .run()
348 .assertContent("null");
349 a.put("/Bean?content=", null)
350 .run()
351 .assertContent("null");
352 a.put("/Bean?content=bad&noTrace=true", null)
353 .run()
354 .assertStatus(400);
355
356
357 a.put("/InputStream", "'a'", APPLICATION_JSON)
358 .run()
359 .assertContent("'\\'a\\''");
360 a.put("/InputStream", "'a'")
361 .run()
362 .assertContent("'\\'a\\''");
363 a.put("/InputStream?content=a", null)
364 .run()
365 .assertContent("'a'");
366 a.put("/InputStream?content=null", null)
367 .run()
368 .assertContent("'null'");
369 a.put("/InputStream?content=", null)
370 .run()
371 .assertContent("''");
372
373
374 a.put("/Reader", "'a'", APPLICATION_JSON)
375 .run()
376 .assertContent("'\\'a\\''");
377 a.put("/Reader", "'a'")
378 .run()
379 .assertContent("'\\'a\\''");
380 a.put("/Reader?content=a", null)
381 .run()
382 .assertContent("'a'");
383 a.put("/Reader?content=null", null)
384 .run()
385 .assertContent("'null'");
386 a.put("/Reader?content=", null)
387 .run()
388 .assertContent("''");
389
390
391
392
393 a.put("/InputStreamTransform?noTrace=true", "'a'", APPLICATION_JSON)
394 .run()
395 .assertContent().isContains("Bad Request");
396 a.put("/InputStreamTransform", "'a'")
397 .run()
398 .assertContent("'\\'a\\''");
399
400
401 a.put("/ReaderTransform?noTrace=true", "'a'", APPLICATION_JSON)
402 .run()
403 .assertContent().isContains("Bad Request");
404 a.put("/ReaderTransform", "'a'")
405 .run()
406 .assertContent("'\\'a\\''");
407
408
409 a.put("/StringTransform", "'a'", APPLICATION_JSON)
410 .run()
411 .assertContent("'a'");
412
413 a.put("/StringTransform", "'a'")
414 .run()
415 .assertContent("'\\'a\\''");
416 }
417
418
419
420
421
422 @Rest(serializers=Json5Serializer.class, parsers=JsonParser.class, defaultAccept="application/json")
423 public static class B {
424 @RestPut(path="/StringTransform")
425 public B1 a(B1 b) {
426 return b;
427 }
428 @Content
429 public static class B1 {
430 private String val;
431 public B1(String val) { this.val = val; }
432 @Override public String toString() { return val; }
433 }
434 @RestPut(path="/Bean")
435 public B2 b(B2 b) {
436 return b;
437 }
438 @Content
439 public static class B2 {
440 public String f1;
441 }
442 @RestPut(path="/BeanList")
443 public B3 c(B3 b) {
444 return b;
445 }
446 @SuppressWarnings("serial")
447 @Content
448 public static class B3 extends LinkedList<B2> {}
449 @RestPut(path="/InputStreamTransform")
450 public B4 d(B4 b) {
451 return b;
452 }
453 @Content
454 public static class B4 {
455 String s;
456 public B4(InputStream in) throws Exception { this.s = read(in); }
457 @Override public String toString() { return s; }
458 }
459 @RestPut(path="/ReaderTransform")
460 public B5 e(B5 b) {
461 return b;
462 }
463 @Content
464 public static class B5 {
465 private String s;
466 public B5(Reader in) throws Exception { this.s = read(in); }
467 @Override public String toString() { return s; }
468 }
469 }
470
471 @Test void b01_onPojos() throws Exception {
472 var b = MockRestClient.buildLax(B.class);
473 b.put("/StringTransform", "'foo'", APPLICATION_JSON)
474 .run()
475 .assertContent("'foo'");
476
477 b.put("/StringTransform", "'foo'")
478 .run()
479 .assertContent("'\\'foo\\''");
480 b.put("/Bean", "{f1:'a'}", APPLICATION_JSON)
481 .run()
482 .assertContent("{f1:'a'}");
483 b.put("/Bean", "(f1=a)", TEXT_OPENAPI)
484 .run()
485 .assertStatus(415);
486 b.put("/BeanList", "[{f1:'a'}]", APPLICATION_JSON)
487 .run()
488 .assertContent("[{f1:'a'}]");
489 b.put("/BeanList", "(f1=a)", TEXT_OPENAPI)
490 .run()
491 .assertStatus(415);
492 b.put("/InputStreamTransform", "a")
493 .run()
494 .assertContent("'a'");
495
496 b.put("/InputStreamTransform?noTrace=true", "a", APPLICATION_JSON)
497 .run()
498 .assertContent().isContains("Bad Request");
499 b.put("/ReaderTransform", "a")
500 .run()
501 .assertContent("'a'");
502
503 b.put("/ReaderTransform?noTrace=true", "a", APPLICATION_JSON)
504 .run()
505 .assertContent().isContains("Bad Request");
506 }
507
508
509
510
511
512 @Rest
513 public static class D {
514 @RestPut(path="/String")
515 public Reader a(@Content Reader b) {
516 return b;
517 }
518 @RestPut(path="/InputStream")
519 public InputStream b(@Content InputStream b) {
520 return b;
521 }
522 @RestPut(path="/Reader")
523 public Reader c(@Content Reader b) {
524 return b;
525 }
526 @RestPut(path="/StringTransform")
527 public Reader d(@Content D1 b) {
528 return reader(b.toString());
529 }
530 public static class D1 {
531 private String s;
532 public D1(String in) { this.s = in; }
533 @Override public String toString() { return s; }
534 }
535 @RestPut(path="/InputStreamTransform")
536 public Reader e(@Content D2 b) {
537 return reader(b.toString());
538 }
539 public static class D2 {
540 String s;
541 public D2(InputStream in) throws Exception { this.s = read(in); }
542 @Override public String toString() { return s; }
543 }
544 @RestPut(path="/ReaderTransform")
545 public Reader f(@Content D3 b) {
546 return reader(b.toString());
547 }
548 public static class D3 {
549 private String s;
550 public D3(Reader in) throws Exception{ this.s = read(in); }
551 @Override public String toString() { return s; }
552 }
553 @RestPut(path="/StringTransformBodyOnPojo")
554 public Reader g(D4 b) {
555 return reader(b.toString());
556 }
557 @Content
558 public static class D4 {
559 private String s;
560 public D4(String in) { this.s = in; }
561 @Override public String toString() { return s; }
562 }
563 @RestPut(path="/InputStreamTransformBodyOnPojo")
564 public Reader h(D5 b) {
565 return reader(b.toString());
566 }
567 @Content
568 public static class D5 {
569 String s;
570 public D5(InputStream in) throws Exception { this.s = read(in); }
571 @Override public String toString() { return s; }
572 }
573
574 @RestPut(path="/ReaderTransformBodyOnPojo")
575 public Reader i(D6 b) {
576 return reader(b.toString());
577 }
578 @Content
579 public static class D6 {
580 private String s;
581 public D6(Reader in) throws Exception{ this.s = read(in); }
582 @Override public String toString() { return s; }
583 }
584 }
585
586 @Test void d01_noMediaTypesOnStreams() throws Exception {
587 var d = MockRestClient.buildLax(D.class);
588 d.put("/String", "a")
589 .run()
590 .assertContent("a");
591 d.put("/String", "a", APPLICATION_JSON)
592 .run()
593 .assertContent("a");
594 d.put("/InputStream", "a")
595 .run()
596 .assertContent("a");
597 d.put("/InputStream", "a", APPLICATION_JSON)
598 .run()
599 .assertContent("a");
600 d.put("/Reader", "a")
601 .run()
602 .assertContent("a");
603 d.put("/Reader", "a", APPLICATION_JSON)
604 .run()
605 .assertContent("a");
606 d.put("/StringTransform", "a")
607 .run()
608 .assertContent("a");
609 d.put("/StringTransform?noTrace=true", "a", APPLICATION_JSON)
610 .run()
611 .assertStatus(415);
612 d.put("/InputStreamTransform", "a")
613 .run()
614 .assertContent("a");
615 d.put("/InputStreamTransform", "a", APPLICATION_JSON)
616 .run()
617 .assertContent("a");
618 d.put("/ReaderTransform", "a")
619 .run()
620 .assertContent("a");
621 d.put("/ReaderTransform", "a", APPLICATION_JSON)
622 .run()
623 .assertContent("a");
624 d.put("/StringTransformBodyOnPojo", "a")
625 .run()
626 .assertContent("a");
627 d.put("/StringTransformBodyOnPojo?noTrace=true", "a", APPLICATION_JSON)
628 .run()
629 .assertStatus(415);
630 d.put("/InputStreamTransformBodyOnPojo", "a")
631 .run()
632 .assertContent("a");
633 d.put("/InputStreamTransformBodyOnPojo", "a", APPLICATION_JSON)
634 .run()
635 .assertContent("a");
636 d.put("/ReaderTransformBodyOnPojo", "a")
637 .run()
638 .assertContent("a");
639 d.put("/ReaderTransformBodyOnPojo", "a", APPLICATION_JSON)
640 .run()
641 .assertContent("a");
642 }
643
644
645
646
647
648 @Rest(serializers=Json5Serializer.class, parsers=JsonParser.class, defaultAccept="application/json")
649 public static class E {
650 @RestPut(path="/B")
651 public XBeans.XB a(@Content XBeans.XB b) {
652 return b;
653 }
654 @RestPut(path="/C")
655 public XBeans.XC b(@Content XBeans.XC c) {
656 return c;
657 }
658 }
659
660 @Test void e01_complexPojos() throws Exception {
661 var e = MockRestClient.build(E.class);
662 var expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
663
664 e.put("/B", Json5Serializer.DEFAULT.toString(XBeans.XB.INSTANCE), APPLICATION_JSON)
665 .run()
666 .assertContent(expected);
667
668 expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
669 e.put("/B?content=" + UonSerializer.DEFAULT.serialize(XBeans.XB.INSTANCE), "a")
670 .run()
671 .assertContent(expected);
672
673 expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
674 e.put("/C", Json5Serializer.DEFAULT.toString(XBeans.XB.INSTANCE), APPLICATION_JSON)
675 .run()
676 .assertContent(expected);
677
678 expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
679 e.put("/C?content=" + UonSerializer.DEFAULT.serialize(XBeans.XB.INSTANCE), "a")
680 .run()
681 .assertContent(expected);
682 }
683
684 @Rest(serializers=Json5Serializer.class, parsers=JsonParser.class, defaultAccept="application/json")
685 @Bean(on="A,B,C",sort=true)
686 @UrlEncoding(on="C",expandedParams=true)
687 public static class E2 {
688 @RestPut(path="/B")
689 public XBeans.XE a(@Content XBeans.XE b) {
690 return b;
691 }
692 @RestPut(path="/C")
693 public XBeans.XF b(@Content XBeans.XF c) {
694 return c;
695 }
696 }
697
698 @Test void e02_complexPojos() throws Exception {
699 var e2 = MockRestClient.build(E2.class);
700 var expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
701
702 e2.put("/B", Json5Serializer.DEFAULT.copy().applyAnnotations(XBeans.Annotations.class).build().toString(XBeans.XE.INSTANCE), APPLICATION_JSON)
703 .run()
704 .assertContent(expected);
705
706 expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
707 e2.put("/B?content=" + UonSerializer.DEFAULT.copy().applyAnnotations(XBeans.Annotations.class).build().serialize(XBeans.XE.INSTANCE), "a")
708 .run()
709 .assertContent(expected);
710
711 expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
712 e2.put("/C", Json5Serializer.DEFAULT.copy().applyAnnotations(XBeans.Annotations.class).build().toString(XBeans.XE.INSTANCE), APPLICATION_JSON)
713 .run()
714 .assertContent(expected);
715
716 expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}";
717 e2.put("/C?content=" + UonSerializer.DEFAULT.copy().applyAnnotations(XBeans.Annotations.class).build().serialize(XBeans.XE.INSTANCE), "a")
718 .run()
719 .assertContent(expected);
720 }
721
722
723
724
725
726 @Rest(serializers=JsonSerializer.class,parsers=JsonParser.class)
727 public static class F {
728 @RestPost(path="/*")
729 public Reader a(
730 @Content F1 bean,
731 @HasQuery("p1") boolean hqp1, @HasQuery("p2") boolean hqp2,
732 @Query("p1") String qp1, @Query("p2") int qp2) {
733 return reader("bean=["+Json5Serializer.DEFAULT.toString(bean)+"],qp1=["+qp1+"],qp2=["+qp2+"],hqp1=["+hqp1+"],hqp2=["+hqp2+"]");
734 }
735 public static class F1 {
736 public String p1;
737 public int p2;
738 }
739 }
740
741 @Test void f01_formPostAsContent() throws Exception {
742 var f = MockRestClient.build(F.class);
743 f.post("/", "{p1:'p1',p2:2}", APPLICATION_JSON)
744 .run()
745 .assertContent("bean=[{p1:'p1',p2:2}],qp1=[null],qp2=[0],hqp1=[false],hqp2=[false]");
746 f.post("/", "{}", APPLICATION_JSON)
747 .run()
748 .assertContent("bean=[{p2:0}],qp1=[null],qp2=[0],hqp1=[false],hqp2=[false]");
749 f.post("?p1=p3&p2=4", "{p1:'p1',p2:2}", APPLICATION_JSON)
750 .run()
751 .assertContent("bean=[{p1:'p1',p2:2}],qp1=[p3],qp2=[4],hqp1=[true],hqp2=[true]");
752 f.post("?p1=p3&p2=4", "{}", APPLICATION_JSON)
753 .run()
754 .assertContent("bean=[{p2:0}],qp1=[p3],qp2=[4],hqp1=[true],hqp2=[true]");
755 }
756
757
758
759
760
761
762
763 @Rest(serializers=UrlEncodingSerializer.class,parsers=UrlEncodingParser.class)
764 public static class G {
765 @RestPost(path="/")
766 public XBeans.XC a(@Content XBeans.XC content) {
767 return content;
768 }
769 }
770
771 @Test void g01_multiPartParameterKeysOnCollections() throws Exception {
772 var g = MockRestClient.build(G.class);
773 var in = """
774 f01=a&f01=b\
775 &f02=c&f02=d\
776 &f03=1&f03=2\
777 &f04=3&f04=4\
778 &f05=@(e,f)&f05=@(g,h)\
779 &f06=@(i,j)&f06=@(k,l)\
780 &f07=(a=a,b=1,c=true)&f07=(a=b,b=2,c=false)\
781 &f08=(a=a,b=1,c=true)&f08=(a=b,b=2,c=false)\
782 &f09=@((a=a,b=1,c=true))&f09=@((a=b,b=2,c=false))\
783 &f10=@((a=a,b=1,c=true))&f10=@((a=b,b=2,c=false))\
784 &f11=a&f11=b\
785 &f12=c&f12=d\
786 &f13=1&f13=2\
787 &f14=3&f14=4\
788 &f15=@(e,f)&f15=@(g,h)\
789 &f16=@(i,j)&f16=@(k,l)\
790 &f17=(a=a,b=1,c=true)&f17=(a=b,b=2,c=false)\
791 &f18=(a=a,b=1,c=true)&f18=(a=b,b=2,c=false)\
792 &f19=@((a=a,b=1,c=true))&f19=@((a=b,b=2,c=false))\
793 &f20=@((a=a,b=1,c=true))&f20=@((a=b,b=2,c=false))""";
794 g.post("/", in, APPLICATION_FORM_URLENCODED)
795 .run()
796 .assertContent(in);
797 }
798
799
800
801
802
803
804
805 @Rest(serializers=UrlEncodingSerializer.class,parsers=UrlEncodingParser.class)
806 public static class H {
807 @RestPost(path="/")
808 @UrlEncodingConfig(expandedParams="true")
809 public XBeans.XB a(@Content XBeans.XB content) {
810 return content;
811 }
812 }
813
814 @Test void h01_multiPartParameterKeysOnCollections_usingExpandedParams() throws Exception {
815 var h = MockRestClient.build(H.class);
816 var in = """
817 f01=a&f01=b\
818 &f02=c&f02=d\
819 &f03=1&f03=2\
820 &f04=3&f04=4\
821 &f05=@(e,f)&f05=@(g,h)\
822 &f06=@(i,j)&f06=@(k,l)\
823 &f07=(a=a,b=1,c=true)&f07=(a=b,b=2,c=false)\
824 &f08=(a=a,b=1,c=true)&f08=(a=b,b=2,c=false)\
825 &f09=@((a=a,b=1,c=true))&f09=@((a=b,b=2,c=false))\
826 &f10=@((a=a,b=1,c=true))&f10=@((a=b,b=2,c=false))\
827 &f11=a&f11=b\
828 &f12=c&f12=d\
829 &f13=1&f13=2\
830 &f14=3&f14=4\
831 &f15=@(e,f)&f15=@(g,h)\
832 &f16=@(i,j)&f16=@(k,l)\
833 &f17=(a=a,b=1,c=true)&f17=(a=b,b=2,c=false)\
834 &f18=(a=a,b=1,c=true)&f18=(a=b,b=2,c=false)\
835 &f19=@((a=a,b=1,c=true))&f19=@((a=b,b=2,c=false))\
836 &f20=@((a=a,b=1,c=true))&f20=@((a=b,b=2,c=false))""";
837 h.post("/", in, APPLICATION_FORM_URLENCODED)
838 .run()
839 .assertContent(in);
840 }
841
842 @Rest(serializers=UrlEncodingSerializer.class,parsers=UrlEncodingParser.class)
843 @Bean(on="A,B,C",sort=true)
844 @UrlEncoding(on="C",expandedParams=true)
845 public static class H2 {
846 @RestPost(path="/")
847 @UrlEncodingConfig(expandedParams="true")
848 public XBeans.XE a(@Content XBeans.XE content) {
849 return content;
850 }
851 }
852
853 @Test void h02_multiPartParameterKeysOnCollections_usingExpandedParams() throws Exception {
854 var h2 = MockRestClient.build(H2.class);
855 var in = """
856 f01=a&f01=b\
857 &f02=c&f02=d\
858 &f03=1&f03=2\
859 &f04=3&f04=4\
860 &f05=@(e,f)&f05=@(g,h)\
861 &f06=@(i,j)&f06=@(k,l)\
862 &f07=(a=a,b=1,c=true)&f07=(a=b,b=2,c=false)\
863 &f08=(a=a,b=1,c=true)&f08=(a=b,b=2,c=false)\
864 &f09=@((a=a,b=1,c=true))&f09=@((a=b,b=2,c=false))\
865 &f10=@((a=a,b=1,c=true))&f10=@((a=b,b=2,c=false))\
866 &f11=a&f11=b\
867 &f12=c&f12=d\
868 &f13=1&f13=2\
869 &f14=3&f14=4\
870 &f15=@(e,f)&f15=@(g,h)\
871 &f16=@(i,j)&f16=@(k,l)\
872 &f17=(a=a,b=1,c=true)&f17=(a=b,b=2,c=false)\
873 &f18=(a=a,b=1,c=true)&f18=(a=b,b=2,c=false)\
874 &f19=@((a=a,b=1,c=true))&f19=@((a=b,b=2,c=false))\
875 &f20=@((a=a,b=1,c=true))&f20=@((a=b,b=2,c=false))""";
876 h2.post("/", in, APPLICATION_FORM_URLENCODED)
877 .run()
878 .assertContent(in);
879 }
880
881
882
883
884
885 @Rest(serializers=JsonSerializer.class,parsers=JsonParser.class)
886 public static class I {
887 @RestPost
888 public XBeans.XB a(@Content @Schema(r=true) XBeans.XB content) {
889 return content;
890 }
891 @RestPost
892 @Bean(on="A,B,C",sort=true)
893 @UrlEncoding(on="C",expandedParams=true)
894 public XBeans.XE b(@Content @Schema(r=true) XBeans.XE content) {
895 return content;
896 }
897 }
898
899 @Test void i01_required() throws Exception {
900 var i = MockRestClient.buildLax(I.class);
901
902 i.post("/a", "", APPLICATION_JSON)
903 .run()
904 .assertStatus(400)
905 .assertContent().isContains("Required value not provided.");
906 i.post("/a", "{}", APPLICATION_JSON)
907 .run()
908 .assertStatus(200);
909
910 i.post("/b", "", APPLICATION_JSON)
911 .run()
912 .assertStatus(400)
913 .assertContent().isContains("Required value not provided.");
914 i.post("/b", "{}", APPLICATION_JSON)
915 .run()
916 .assertStatus(200);
917 }
918
919
920
921
922
923 @Rest(serializers=Json5Serializer.class,parsers=JsonParser.class)
924 public static class J {
925 @RestPost
926 public Object a(@Content Optional<Integer> body) {
927 assertNotNull(body);
928 return body;
929 }
930 @RestPost
931 public Object b(@Content Optional<ABean> body) {
932 assertNotNull(body);
933 return body;
934 }
935 @RestPost
936 public Object c(@Content Optional<List<ABean>> body) {
937 assertNotNull(body);
938 return body;
939 }
940 @RestPost
941 public Object d(@Content List<Optional<ABean>> body) {
942 return body;
943 }
944 }
945
946 @Test void j01_optionalParams() throws Exception {
947 var j = MockRestClient.buildJson(J.class);
948 j.post("/a", 123)
949 .run()
950 .assertStatus(200)
951 .assertContent("123");
952 j.post("/a", null)
953 .run()
954 .assertStatus(200)
955 .assertContent("null");
956
957 j.post("/b", ABean.get())
958 .run()
959 .assertStatus(200)
960 .assertContent("{a:1,b:'foo'}");
961 j.post("/b", null)
962 .run()
963 .assertStatus(200)
964 .assertContent("null");
965
966 var body1 = Json5.of(l(ABean.get()));
967 j.post("/c", body1, APPLICATION_JSON)
968 .run()
969 .assertStatus(200)
970 .assertContent("[{a:1,b:'foo'}]");
971 j.post("/c", null)
972 .run()
973 .assertStatus(200)
974 .assertContent("null");
975
976 var body2 = Json5.of(l(opt(ABean.get())));
977 j.post("/d", body2, APPLICATION_JSON)
978 .run()
979 .assertStatus(200)
980 .assertContent("[{a:1,b:'foo'}]");
981 j.post("/d", null)
982 .run()
983 .assertStatus(200)
984 .assertContent("null");
985 }
986 }