1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.http.remote;
18
19 import static org.apache.juneau.TestUtils.*;
20 import static org.apache.juneau.http.HttpParts.*;
21 import static org.junit.jupiter.api.Assertions.*;
22
23 import java.math.*;
24 import java.util.*;
25 import java.util.concurrent.atomic.*;
26
27 import org.apache.http.*;
28 import org.apache.http.client.config.*;
29 import org.apache.juneau.*;
30 import org.apache.juneau.annotation.*;
31 import org.apache.juneau.collections.*;
32 import org.apache.juneau.http.annotation.*;
33 import org.apache.juneau.http.part.*;
34 import org.apache.juneau.internal.*;
35 import org.apache.juneau.rest.RestRequest;
36 import org.apache.juneau.rest.annotation.*;
37 import org.apache.juneau.rest.client.*;
38 import org.apache.juneau.rest.mock.*;
39 import org.apache.juneau.uon.*;
40 import org.apache.juneau.utest.utils.*;
41 import org.junit.jupiter.api.*;
42
43 class Remote_PathAnnotation_Test extends TestBase {
44
45 public static class Bean {
46 public int x;
47
48 public static Bean create() {
49 var b = new Bean();
50 b.x = 1;
51 return b;
52 }
53 }
54
55
56
57
58
59 @Rest
60 public static class A {
61 @RestGet(path="/a/{x}")
62 public String a(@Path("x") Object x) {
63 return x.toString();
64 }
65 }
66
67 @Remote
68 public interface A1 {
69 @RemoteOp(path="a/{x}") String getX1(@Path("x") int b);
70 @RemoteOp(path="a/{x}") String getX2(@Path("x") float b);
71 @RemoteOp(path="a/{x}") String getX3(@Path("x") Bean b);
72 @RemoteOp(path="a/{x}") String getX4(@Path("*") Bean b);
73 @RemoteOp(path="a/{x}") String getX5(@Path Bean b);
74 @RemoteOp(path="a/{x}") String getX6(@Path("x") Bean[] b);
75 @RemoteOp(path="a/{x}") String getX7(@Path("x") @Schema(cf="uon") Bean[] b);
76 @RemoteOp(path="a/{x}") String getX8(@Path("x") List<Bean> b);
77 @RemoteOp(path="a/{x}") String getX9(@Path("x") @Schema(cf="uon") List<Bean> b);
78 @RemoteOp(path="a/{x}") String getX10(@Path("x") Map<String,Bean> b);
79 @RemoteOp(path="a/{x}") String getX11(@Path("*") Map<String,Bean> b);
80 @RemoteOp(path="a/{x}") String getX12(@Path Map<String,Bean> b);
81 @RemoteOp(path="a/{x}") String getX13(@Path("x") @Schema(cf="uon") Map<String,Bean> b);
82 @RemoteOp(path="a/{x}") String getX14(@Path @Schema(f="uon") Map<String,Bean> b);
83 @RemoteOp(path="a/{x}") String getX15(@Path("*") PartList b);
84 @RemoteOp(path="a/{x}") String getX16(@Path PartList b);
85 @RemoteOp(path="a/{x}") String getX17(@Path(name="x",serializer=UonSerializer.class) Map<String,Bean> b);
86 @RemoteOp(path="a/{x}") String getX18(@Path("*") NameValuePair b);
87 @RemoteOp(path="a/{x}") String getX19(@Path NameValuePair b);
88 @RemoteOp(path="a/{x}") String getX20(@Path NameValuePair[] b);
89 @RemoteOp(path="a/{x}") String getX21(@Path String b);
90 @RemoteOp(path="a/{x}") String getX22(@Path List<NameValuePair> b);
91 }
92
93 @Test void a01_path_objectTypes() {
94 var x = remote(A.class,A1.class);
95 assertEquals("1",x.getX1(1));
96 assertEquals("1.0",x.getX2(1));
97 assertEquals("x=1",x.getX3(Bean.create()));
98 assertEquals("1",x.getX4(Bean.create()));
99 assertEquals("1",x.getX5(Bean.create()));
100 assertEquals("x=1,x=1",x.getX6(new Bean[]{Bean.create(),Bean.create()}));
101 assertEquals("@((x=1),(x=1))",x.getX7(new Bean[]{Bean.create(),Bean.create()}));
102 assertEquals("x=1,x=1",x.getX8(alist(Bean.create(),Bean.create())));
103 assertEquals("@((x=1),(x=1))",x.getX9(alist(Bean.create(),Bean.create())));
104 assertEquals("x=x\\=1",x.getX10(map("x",Bean.create())));
105 assertEquals("x=1",x.getX11(map("x",Bean.create())));
106 assertEquals("x=1",x.getX12(map("x",Bean.create())));
107 assertEquals("(x=(x=1))",x.getX13(map("x",Bean.create())));
108 assertEquals("x=1",x.getX14(map("x",Bean.create())));
109 assertEquals("bar",x.getX15(parts("x","bar")));
110 assertEquals("bar",x.getX16(parts("x","bar")));
111 assertEquals("(x=(x=1))",x.getX17(map("x",Bean.create())));
112 assertEquals("bar",x.getX18(part("x","bar")));
113 assertEquals("bar",x.getX19(part("x","bar")));
114 assertEquals("bar",x.getX20(new NameValuePair[]{part("x","bar")}));
115 assertEquals("{x}",x.getX20(null));
116 assertThrowsWithMessage(Exception.class, "Invalid value type for path arg 'null': java.lang.String", ()->x.getX21("foo"));
117 assertEquals("bar",x.getX22(alist(part("x","bar"))));
118 }
119
120
121
122
123
124 @Rest
125 public static class B {
126 @RestGet(path="/a/{x}")
127 public String a(@Path("x") Object x) {
128 return x.toString();
129 }
130 }
131
132 @Remote
133 public interface B1 {
134 @RemoteOp(path="/a/{x}") String getX1(@Path("x") String...b);
135 @RemoteOp(path="/a/{x}") String getX2(@Path("x") @Schema(cf="csv") String...b);
136 @RemoteOp(path="/a/{x}") String getX3(@Path("x") @Schema(cf="ssv") String...b);
137 @RemoteOp(path="/a/{x}") String getX4(@Path("x") @Schema(cf="tsv") String...b);
138 @RemoteOp(path="/a/{x}") String getX5(@Path("x") @Schema(cf="pipes") String...b);
139 @RemoteOp(path="/a/{x}") String getX6(@Path("x") @Schema(cf="multi") String...b);
140 @RemoteOp(path="/a/{x}") String getX7(@Path("x") @Schema(cf="uon") String...b);
141 }
142
143 @Test void b01_path_collectionFormat() {
144 var x = remote(B.class,B1.class);
145 assertEquals("foo,bar",x.getX1("foo","bar"));
146 assertEquals("foo,bar",x.getX2("foo","bar"));
147 assertEquals("foo bar",x.getX3("foo","bar"));
148 assertEquals("foo\tbar",x.getX4("foo","bar"));
149 assertEquals("foo|bar",x.getX5("foo","bar"));
150 assertEquals("foo,bar",x.getX6("foo","bar"));
151 assertEquals("@(foo,bar)",x.getX7("foo","bar"));
152 }
153
154
155
156
157
158 @Rest
159 public static class C {
160 @RestOp(path="/a/{x}")
161 public String get(@Path("*") JsonMap m) {
162 m.removeAll("/*","/**");
163 return m.toString();
164 }
165 }
166
167 @Remote
168 public interface C1 {
169 @RemoteOp(path="/a/{x}") String getX1(@Path("x") @Schema(min="1",max="10") int b);
170 @RemoteOp(path="/a/{x}") String getX2(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) int b);
171 @RemoteOp(path="/a/{x}") String getX3(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) int b);
172 @RemoteOp(path="/a/{x}") String getX4(@Path("x") @Schema(min="1",max="10") short b);
173 @RemoteOp(path="/a/{x}") String getX5(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) short b);
174 @RemoteOp(path="/a/{x}") String getX6(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) short b);
175 @RemoteOp(path="/a/{x}") String getX7(@Path("x") @Schema(min="1",max="10") long b);
176 @RemoteOp(path="/a/{x}") String getX8(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) long b);
177 @RemoteOp(path="/a/{x}") String getX9(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) long b);
178 @RemoteOp(path="/a/{x}") String getX10(@Path("x") @Schema(min="1",max="10") float b);
179 @RemoteOp(path="/a/{x}") String getX11(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) float b);
180 @RemoteOp(path="/a/{x}") String getX12(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) float b);
181 @RemoteOp(path="/a/{x}") String getX13(@Path("x") @Schema(min="1",max="10") double b);
182 @RemoteOp(path="/a/{x}") String getX14(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) double b);
183 @RemoteOp(path="/a/{x}") String getX15(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) double b);
184 @RemoteOp(path="/a/{x}") String getX16(@Path("x") @Schema(min="1",max="10") byte b);
185 @RemoteOp(path="/a/{x}") String getX17(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) byte b);
186 @RemoteOp(path="/a/{x}") String getX18(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) byte b);
187 @RemoteOp(path="/a/{x}") String getX19(@Path("x") @Schema(min="1",max="10") AtomicInteger b);
188 @RemoteOp(path="/a/{x}") String getX20(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) AtomicInteger b);
189 @RemoteOp(path="/a/{x}") String getX21(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) AtomicInteger b);
190 @RemoteOp(path="/a/{x}") String getX22(@Path("x") @Schema(min="1",max="10") BigDecimal b);
191 @RemoteOp(path="/a/{x}") String getX23(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) BigDecimal b);
192 @RemoteOp(path="/a/{x}") String getX24(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) BigDecimal b);
193 @RemoteOp(path="/a/{x}") String getX25(@Path("x") @Schema(min="1",max="10") Integer b);
194 @RemoteOp(path="/a/{x}") String getX26(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) Integer b);
195 @RemoteOp(path="/a/{x}") String getX27(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) Integer b);
196 @RemoteOp(path="/a/{x}") String getX28(@Path("x") @Schema(min="1",max="10") Short b);
197 @RemoteOp(path="/a/{x}") String getX29(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) Short b);
198 @RemoteOp(path="/a/{x}") String getX30(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) Short b);
199 @RemoteOp(path="/a/{x}") String getX31(@Path("x") @Schema(min="1",max="10") Long b);
200 @RemoteOp(path="/a/{x}") String getX32(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) Long b);
201 @RemoteOp(path="/a/{x}") String getX33(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) Long b);
202 @RemoteOp(path="/a/{x}") String getX34(@Path("x") @Schema(min="1",max="10") Float b);
203 @RemoteOp(path="/a/{x}") String getX35(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) Float b);
204 @RemoteOp(path="/a/{x}") String getX36(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) Float b);
205 @RemoteOp(path="/a/{x}") String getX37(@Path("x") @Schema(min="1",max="10") Double b);
206 @RemoteOp(path="/a/{x}") String getX38(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) Double b);
207 @RemoteOp(path="/a/{x}") String getX39(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) Double b);
208 @RemoteOp(path="/a/{x}") String getX40(@Path("x") @Schema(min="1",max="10") Byte b);
209 @RemoteOp(path="/a/{x}") String getX41(@Path("x") @Schema(min="1",max="10",emin=false,emax=false) Byte b);
210 @RemoteOp(path="/a/{x}") String getX42(@Path("x") @Schema(min="1",max="10",emin=true,emax=true) Byte b);
211 }
212
213 @Test void c01_path_min_max_emin_emax() {
214 var x = remote(C.class,C1.class);
215 assertEquals("{x:'1'}",x.getX1(1));
216 assertEquals("{x:'10'}",x.getX1(10));
217 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX1(0));
218 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX1(11));
219 assertEquals("{x:'1'}",x.getX2(1));
220 assertEquals("{x:'10'}",x.getX2(10));
221 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX2(0));
222 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX2(11));
223 assertEquals("{x:'2'}",x.getX3(2));
224 assertEquals("{x:'9'}",x.getX3(9));
225 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX3(1));
226 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX3(10));
227 assertEquals("{x:'1'}",x.getX4((short)1));
228 assertEquals("{x:'10'}",x.getX4((short)10));
229 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX4((short)0));
230 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX4((short)11));
231 assertEquals("{x:'1'}",x.getX5((short)1));
232 assertEquals("{x:'10'}",x.getX5((short)10));
233 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX5((short)0));
234 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX5((short)11));
235 assertEquals("{x:'2'}",x.getX6((short)2));
236 assertEquals("{x:'9'}",x.getX6((short)9));
237 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX6((short)1));
238 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX6((short)10));
239 assertEquals("{x:'1'}",x.getX7(1L));
240 assertEquals("{x:'10'}",x.getX7(10L));
241 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX7(0L));
242 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX7(11L));
243 assertEquals("{x:'1'}",x.getX8(1L));
244 assertEquals("{x:'10'}",x.getX8(10L));
245 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX8(0L));
246 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX8(11L));
247 assertEquals("{x:'2'}",x.getX9(2L));
248 assertEquals("{x:'9'}",x.getX9(9L));
249 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX9(1L));
250 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX9(10L));
251 assertEquals("{x:'1.0'}",x.getX10(1f));
252 assertEquals("{x:'10.0'}",x.getX10(10f));
253 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX10(0.9f));
254 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX10(10.1f));
255 assertEquals("{x:'1.0'}",x.getX11(1f));
256 assertEquals("{x:'10.0'}",x.getX11(10f));
257 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX11(0.9f));
258 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX11(10.1f));
259 assertEquals("{x:'1.1'}",x.getX12(1.1f));
260 assertEquals("{x:'9.9'}",x.getX12(9.9f));
261 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX12(1f));
262 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX12(10f));
263 assertEquals("{x:'1.0'}",x.getX13(1d));
264 assertEquals("{x:'10.0'}",x.getX13(10d));
265 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX13(0.9d));
266 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX13(10.1d));
267 assertEquals("{x:'1.0'}",x.getX14(1d));
268 assertEquals("{x:'10.0'}",x.getX14(10d));
269 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX14(0.9d));
270 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX14(10.1d));
271 assertEquals("{x:'1.1'}",x.getX15(1.1d));
272 assertEquals("{x:'9.9'}",x.getX15(9.9d));
273 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX15(1d));
274 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX15(10d));
275 assertEquals("{x:'1'}",x.getX16((byte)1));
276 assertEquals("{x:'10'}",x.getX16((byte)10));
277 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX16((byte)0));
278 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX16((byte)11));
279 assertEquals("{x:'1'}",x.getX17((byte)1));
280 assertEquals("{x:'10'}",x.getX17((byte)10));
281 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX17((byte)0));
282 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX17((byte)11));
283 assertEquals("{x:'2'}",x.getX18((byte)2));
284 assertEquals("{x:'9'}",x.getX18((byte)9));
285 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX18((byte)1));
286 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX18((byte)10));
287 assertEquals("{x:'1'}",x.getX19(new AtomicInteger(1)));
288 assertEquals("{x:'10'}",x.getX19(new AtomicInteger(10)));
289 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX19(new AtomicInteger(0)));
290 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX19(new AtomicInteger(11)));
291 assertEquals("{x:'1'}",x.getX20(new AtomicInteger(1)));
292 assertEquals("{x:'10'}",x.getX20(new AtomicInteger(10)));
293 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX20(new AtomicInteger(0)));
294 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX20(new AtomicInteger(11)));
295 assertEquals("{x:'2'}",x.getX21(new AtomicInteger(2)));
296 assertEquals("{x:'9'}",x.getX21(new AtomicInteger(9)));
297 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX21(new AtomicInteger(1)));
298 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX21(new AtomicInteger(10)));
299 assertEquals("{x:'1'}",x.getX22(new BigDecimal(1)));
300 assertEquals("{x:'10'}",x.getX22(new BigDecimal(10)));
301 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX22(new BigDecimal(0)));
302 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX22(new BigDecimal(11)));
303 assertEquals("{x:'1'}",x.getX23(new BigDecimal(1)));
304 assertEquals("{x:'10'}",x.getX23(new BigDecimal(10)));
305 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX23(new BigDecimal(0)));
306 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX23(new BigDecimal(11)));
307 assertEquals("{x:'2'}",x.getX24(new BigDecimal(2)));
308 assertEquals("{x:'9'}",x.getX24(new BigDecimal(9)));
309 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX24(new BigDecimal(1)));
310 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX24(new BigDecimal(10)));
311 assertEquals("{x:'1'}",x.getX25(1));
312 assertEquals("{x:'10'}",x.getX25(10));
313 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX25(0));
314 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX25(11));
315 assertEquals("{x:'1'}",x.getX26(1));
316 assertEquals("{x:'10'}",x.getX26(10));
317 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX26(0));
318 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX26(11));
319 assertEquals("{x:'2'}",x.getX27(2));
320 assertEquals("{x:'9'}",x.getX27(9));
321 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX27(1));
322 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX27(10));
323 assertEquals("{x:'1'}",x.getX28((short)1));
324 assertEquals("{x:'10'}",x.getX28((short)10));
325 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX28((short)0));
326 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX28((short)11));
327 assertEquals("{x:'1'}",x.getX29((short)1));
328 assertEquals("{x:'10'}",x.getX29((short)10));
329 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX29((short)0));
330 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX29((short)11));
331 assertEquals("{x:'2'}",x.getX30((short)2));
332 assertEquals("{x:'9'}",x.getX30((short)9));
333 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX30((short)1));
334 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX30((short)10));
335 assertEquals("{x:'1'}",x.getX31(1L));
336 assertEquals("{x:'10'}",x.getX31(10L));
337 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX31(0L));
338 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX31(11L));
339 assertEquals("{x:'1'}",x.getX32(1L));
340 assertEquals("{x:'10'}",x.getX32(10L));
341 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX32(0L));
342 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX32(11L));
343 assertEquals("{x:'2'}",x.getX33(2L));
344 assertEquals("{x:'9'}",x.getX33(9L));
345 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX33(1L));
346 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX33(10L));
347 assertEquals("{x:'1.0'}",x.getX34(1f));
348 assertEquals("{x:'10.0'}",x.getX34(10f));
349 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX34(0.9f));
350 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX34(10.1f));
351 assertEquals("{x:'1.0'}",x.getX35(1f));
352 assertEquals("{x:'10.0'}",x.getX35(10f));
353 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX35(0.9f));
354 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX35(10.1f));
355 assertEquals("{x:'1.1'}",x.getX36(1.1f));
356 assertEquals("{x:'9.9'}",x.getX36(9.9f));
357 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX36(1f));
358 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX36(10f));
359 assertEquals("{x:'1.0'}",x.getX37(1d));
360 assertEquals("{x:'10.0'}",x.getX37(10d));
361 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX37(0.9d));
362 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX37(10.1d));
363 assertEquals("{x:'1.0'}",x.getX38(1d));
364 assertEquals("{x:'10.0'}",x.getX38(10d));
365 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX38(0.9d));
366 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX38(10.1d));
367 assertEquals("{x:'1.1'}",x.getX39(1.1d));
368 assertEquals("{x:'9.9'}",x.getX39(9.9d));
369 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX39(1d));
370 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX39(10d));
371 assertEquals("{x:'1'}",x.getX40((byte)1));
372 assertEquals("{x:'10'}",x.getX40((byte)10));
373 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX40((byte)0));
374 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX40((byte)11));
375 assertEquals("{x:'1'}",x.getX41((byte)1));
376 assertEquals("{x:'10'}",x.getX41((byte)10));
377 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX41((byte)0));
378 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX41((byte)11));
379 assertEquals("{x:'2'}",x.getX42((byte)2));
380 assertEquals("{x:'9'}",x.getX42((byte)9));
381 assertThrowsWithMessage(Exception.class, "Minimum value not met.", ()->x.getX42((byte)1));
382 assertThrowsWithMessage(Exception.class, "Maximum value exceeded.", ()->x.getX42((byte)10));
383 }
384
385
386
387
388
389 @Rest
390 public static class D {
391 @RestOp(path="/{x}")
392 public String get(@Path("*") JsonMap m) {
393 m.removeAll("/*","/**");
394 return m.toString();
395 }
396 }
397
398 @Remote
399 public interface D1 {
400 @RemoteOp(path="/{x}") String getX1(@Path("x") @Schema(cf="pipes",mini=1,maxi=2) String...b);
401 @RemoteOp(path="/{x}") String getX2(@Path("x") @Schema(items=@Items(cf="pipes",mini=1,maxi=2)) String[]...b);
402 @RemoteOp(path="/{x}") String getX3(@Path("x") @Schema(cf="pipes",ui=false) String...b);
403 @RemoteOp(path="/{x}") String getX4(@Path("x") @Schema(items=@Items(cf="pipes",ui=false)) String[]...b);
404 @RemoteOp(path="/{x}") String getX5(@Path("x") @Schema(cf="pipes",ui=true) String...b);
405 @RemoteOp(path="/{x}") String getX6(@Path("x") @Schema(items=@Items(cf="pipes",ui=true)) String[]...b);
406 }
407
408 @Test void d01_path_miniMaxi() {
409 var x = remote(D.class,D1.class);
410 assertEquals("{x:'1'}",x.getX1("1"));
411 assertEquals("{x:'1|2'}",x.getX1("1","2"));
412 assertThrowsWithMessage(Exception.class, "Minimum number of items not met.", x::getX1);
413 assertThrowsWithMessage(Exception.class, "Maximum number of items exceeded.", ()->x.getX1("1","2","3"));
414 assertEquals("{x:'null'}",x.getX1((String)null));
415 assertEquals("{x:'1'}",x.getX2(new String[]{"1"}));
416 assertEquals("{x:'1|2'}",x.getX2(new String[]{"1","2"}));
417 assertThrowsWithMessage(Exception.class, "Minimum number of items not met.", ()->x.getX2(new String[]{}));
418 assertThrowsWithMessage(Exception.class, "Maximum number of items exceeded.", ()->x.getX2(new String[]{"1","2","3"}));
419 assertEquals("{x:'null'}",x.getX2(new String[]{null}));
420 assertEquals("{x:'1|1'}",x.getX3("1","1"));
421 assertEquals("{x:'1|1'}",x.getX4(new String[]{"1","1"}));
422 assertEquals("{x:'1|2'}",x.getX5("1","2"));
423 assertThrowsWithMessage(Exception.class, "Duplicate items not allowed.", ()->x.getX5("1","1"));
424 assertEquals("{x:'1|2'}",x.getX6(new String[]{"1","2"}));
425 assertThrowsWithMessage(Exception.class, "Duplicate items not allowed.", ()->x.getX6(new String[]{"1","1"}));
426 }
427
428
429
430
431
432 @Rest
433 public static class E {
434 @RestOp(path="/{x}")
435 public String get(@Path("*") JsonMap m) {
436 m.removeAll("/*","/**");
437 return m.toString();
438 }
439 }
440
441 @Remote
442 public interface E1 {
443 @RemoteOp(path="/{x}") String getX1(@Path("x") @Schema(minl=2,maxl=3) String b);
444 @RemoteOp(path="/{x}") String getX2(@Path("x") @Schema(cf="pipes",items=@Items(minl=2,maxl=3)) String...b);
445 @RemoteOp(path="/{x}") String getX3(@Path("x") @Schema(e={"foo"}) String b);
446 @RemoteOp(path="/{x}") String getX4(@Path("x") @Schema(cf="pipes",items=@Items(e={"foo"})) String...b);
447 @RemoteOp(path="/{x}") String getX5(@Path("x") @Schema(p="foo\\d{1,3}") String b);
448 @RemoteOp(path="/{x}") String getX6(@Path("x") @Schema(cf="pipes",items=@Items(p="foo\\d{1,3}")) String...b);
449 }
450
451 @Test void e01_path_minLength_maxLength() {
452 var x = remote(E.class,E1.class);
453 assertEquals("{x:'12'}",x.getX1("12"));
454 assertEquals("{x:'123'}",x.getX1("123"));
455 assertThrowsWithMessage(Exception.class, "Minimum length of value not met.", ()->x.getX1("1"));
456 assertThrowsWithMessage(Exception.class, "Maximum length of value exceeded.", ()->x.getX1("1234"));
457 assertEquals("{x:'12|34'}",x.getX2("12","34"));
458 assertEquals("{x:'123|456'}",x.getX2("123","456"));
459 assertThrowsWithMessage(Exception.class, "Minimum length of value not met.", ()->x.getX2("1","2"));
460 assertThrowsWithMessage(Exception.class, "Maximum length of value exceeded.", ()->x.getX2("1234","5678"));
461 assertEquals("{x:'12|null'}",x.getX2("12",null));
462 assertEquals("{x:'foo'}",x.getX3("foo"));
463 assertThrowsWithMessage(Exception.class, "Value does not match one of the expected values. Must be one of the following: foo", ()->x.getX3("bar"));
464 assertEquals("{x:'foo'}",x.getX4("foo"));
465 assertThrowsWithMessage(Exception.class, "Value does not match one of the expected values. Must be one of the following: foo", ()->x.getX4("bar"));
466 assertEquals("{x:'null'}",x.getX4((String)null));
467 assertEquals("{x:'foo123'}",x.getX5("foo123"));
468 assertThrowsWithMessage(Exception.class, "Value does not match expected pattern. Must match pattern: foo\\d{1,3}", ()->x.getX5("bar"));
469 assertEquals("{x:'foo123'}",x.getX6("foo123"));
470 assertThrowsWithMessage(Exception.class, "Value does not match expected pattern. Must match pattern: foo\\d{1,3}", ()->x.getX6("foo"));
471 assertEquals("{x:'null'}",x.getX6((String)null));
472 }
473
474
475
476
477
478 @Rest
479 public static class F {
480 @RestOp(path="/{x}")
481 public String get(@Path("*") JsonMap m) {
482 m.removeAll("/*","/**");
483 return m.toString();
484 }
485 }
486
487 @Remote
488 public interface F1 {
489 @RemoteOp(path="/{x}") String getX1(@Path("x") @Schema(mo="2") int b);
490 @RemoteOp(path="/{x}") String getX2(@Path("x") @Schema(mo="2") short b);
491 @RemoteOp(path="/{x}") String getX3(@Path("x") @Schema(mo="2") long b);
492 @RemoteOp(path="/{x}") String getX4(@Path("x") @Schema(mo="2") float b);
493 @RemoteOp(path="/{x}") String getX5(@Path("x") @Schema(mo="2") double b);
494 @RemoteOp(path="/{x}") String getX6(@Path("x") @Schema(mo="2") byte b);
495 @RemoteOp(path="/{x}") String getX7(@Path("x") @Schema(mo="2") AtomicInteger b);
496 @RemoteOp(path="/{x}") String getX8(@Path("x") @Schema(mo="2") BigDecimal b);
497 @RemoteOp(path="/{x}") String getX9(@Path("x") @Schema(mo="2") Integer b);
498 @RemoteOp(path="/{x}") String getX10(@Path("x") @Schema(mo="2") Short b);
499 @RemoteOp(path="/{x}") String getX11(@Path("x") @Schema(mo="2") Long b);
500 @RemoteOp(path="/{x}") String getX12(@Path("x") @Schema(mo="2") Float b);
501 @RemoteOp(path="/{x}") String getX13(@Path("x") @Schema(mo="2") Double b);
502 @RemoteOp(path="/{x}") String getX14(@Path("x") @Schema(mo="2") Byte b);
503 }
504
505 @Test void f01_path_multipleOf() {
506 var x = remote(F.class,F1.class);
507 assertEquals("{x:'4'}",x.getX1(4));
508 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX1(5));
509 assertEquals("{x:'4'}",x.getX2((short)4));
510 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX2((short)5));
511 assertEquals("{x:'4'}",x.getX3(4));
512 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX3(5));
513 assertEquals("{x:'4.0'}",x.getX4(4));
514 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX4(5));
515 assertEquals("{x:'4.0'}",x.getX5(4));
516 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX5(5));
517 assertEquals("{x:'4'}",x.getX6((byte)4));
518 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX6((byte)5));
519 assertEquals("{x:'4'}",x.getX7(new AtomicInteger(4)));
520 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX7(new AtomicInteger(5)));
521 assertEquals("{x:'4'}",x.getX8(new BigDecimal(4)));
522 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX8(new BigDecimal(5)));
523 assertEquals("{x:'4'}",x.getX9(4));
524 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX9(5));
525 assertEquals("{x:'4'}",x.getX10((short)4));
526 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX10((short)5));
527 assertEquals("{x:'4'}",x.getX11(4L));
528 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX11(5L));
529 assertEquals("{x:'4.0'}",x.getX12(4f));
530 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX12(5f));
531 assertEquals("{x:'4.0'}",x.getX13(4d));
532 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX13(5d));
533 assertEquals("{x:'4'}",x.getX14((byte)4));
534 assertThrowsWithMessage(Exception.class, "Multiple-of not met.", ()->x.getX14((byte)5));
535 }
536
537
538
539
540
541 @Rest
542 public static class G {
543 }
544
545 @Remote
546 public interface G1 {
547 @RemoteOp(path="/{x}") String getX1(@Path("x") String b);
548 }
549
550 @Test void h01_path_required() {
551 var x = remote(G.class,G1.class);
552 assertThrowsWithMessage(Exception.class, "Required value not provided.", ()->x.getX1(null));
553 }
554
555
556
557
558
559 @Rest
560 public static class H {
561 @RestOp(path="/{x}")
562 public String get(@Path("*") JsonMap m) {
563 m.removeAll("/*","/**");
564 return m.toString();
565 }
566 }
567
568 @Remote
569 public interface H1 {
570 @RemoteOp(path="/{x}") String getX1(@Path(name="x",serializer=FakeWriterSerializer.X.class) String b);
571 }
572
573 @Test void h01_path_serializer() {
574 var x = remote(H.class,H1.class);
575 assertEquals("{x:'xXx'}",x.getX1("X"));
576 }
577
578
579
580
581
582 @Rest
583 public static class K {
584 @RestOp(path="/*")
585 public String get(RestRequest req) {
586 return req.getPathParams().getRemainder().orElse(null);
587 }
588 }
589
590
591
592
593
594 @Remote(path="/")
595 public interface K1 {
596 @RemoteOp(path="/{a}/{b}/{c}/{e}/{g}/{h}") String getX1(@Request K1a rb);
597 @RemoteOp(path="/{a}/{b}/{c}/{e}/{g}/{h}") String getX2(@Request(serializer=FakeWriterSerializer.X.class) K1a rb);
598 }
599
600 public static class K1a {
601 @Path public String getA() { return "a1"; }
602 @Path("b") public String getX1() { return "b1"; }
603 @Path("c") public String getX2() { return "c1"; }
604 @Path("e") @Schema(aev=true) public String getX4() { return ""; }
605 @Path("g") public String getX6() { return "true"; }
606 @Path("h") public String getX7() { return "123"; }
607 }
608
609 @Test void k01_requestBean_simpleVals() {
610 var x1 = remote(K.class,K1.class);
611 var x2 = client(K.class).partSerializer(UonSerializer.class).build().getRemote(K1.class);
612 assertEquals("a1/b1/c1//true/123",x1.getX1(new K1a()));
613 assertEquals("a1/b1/c1//'true'/'123'",x2.getX1(new K1a()));
614 assertEquals("xa1x/xb1x/xc1x/xx/xtruex/x123x",x2.getX2(new K1a()));
615 }
616
617
618
619
620
621 @Remote(path="/")
622 public interface K2 {
623 @RemoteOp(path="/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}") String getX1(@Request K2a rb);
624 @RemoteOp(path="/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}") String getX2(@Request(serializer=FakeWriterSerializer.X.class) K2a rb);
625 }
626
627 public static class K2a {
628 @Path("*") @Schema(aev=true) public Map<String,Object> getA() { return CollectionUtils.mapBuilder(String.class,Object.class).add("a1","v1").add("a2",123).add("a3",null).add("a4","").build(); }
629 @Path("*") public Map<String,Object> getB() { return map("b1","true","b2","123","b3","null"); }
630 @Path("*") @Schema(aev=true) public Map<String,Object> getC() { return CollectionUtils.mapBuilder(String.class,Object.class).add("c1","v1").add("c2",123).add("c3",null).add("c4","").build(); }
631 @Path("*")
632 public Map<String,Object> getD() { return null; }
633 }
634
635 @Test void k02_reauestBean_maps() {
636 var x1 = remote(K.class,K2.class);
637 var x2 = client(K.class).partSerializer(UonSerializer.class).build().getRemote(K2.class);
638 assertEquals("v1/123/null//true/123/null/v1/123/null/",x1.getX1(new K2a()));
639 assertEquals("v1/123/null//'true'/'123'/'null'/v1/123/null/",x2.getX1(new K2a()));
640 assertEquals("xv1x/x123x/null/xx/xtruex/x123x/xnullx/xv1x/x123x/null/xx",x2.getX2(new K2a()));
641 }
642
643
644
645
646
647 @Remote(path="/")
648 public interface K3 {
649 @RemoteOp(path="/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}/{e1}/{e2}/{e3}/{e4}") String getX1(@Request K3a rb);
650 @RemoteOp(path="/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}/{e1}/{e2}/{e3}/{e4}") String getX2(@Request(serializer=FakeWriterSerializer.X.class) K3a rb);
651 }
652
653 public static class K3a {
654 @Path("*") @Schema(aev=true) public PartList getA() { return parts("a1","v1","a2","123","a3",null,"a4",""); }
655 @Path("/*") public PartList getB() { return parts("b1","true","b2","123","b3","null"); }
656 @Path("*") @Schema(aev=true) public PartList getC() { return parts("c1","v1","c2","123","c3",null,"c4",""); }
657 @Path("/*")
658 public PartList getD() { return null; }
659 @Path @Schema(aev=true) public NameValuePair[] getE() { return parts("e1","v1","e2","123","e3",null,"e4","").getAll(); }
660 }
661
662 @Test void k03_requestBean_nameValuePairs() {
663 var x1 = remote(K.class,K3.class);
664 var x2 = client(K.class).partSerializer(UonSerializer.class).build().getRemote(K3.class);
665 assertEquals("v1/123/null//true/123/null/v1/123/null//v1/123/null/",x1.getX1(new K3a()));
666 assertEquals("v1/123/null//true/123/null/v1/123/null//v1/123/null/",x2.getX1(new K3a()));
667 assertEquals("v1/123/null//true/123/null/v1/123/null//v1/123/null/",x2.getX2(new K3a()));
668 }
669
670
671
672
673
674 @Remote(path="/")
675 public interface K4 {
676 @RemoteOp(path="/{a}/{b}/{c}/{d}/{f}/{g}/{h}") String getX1(@Request K4a rb);
677 @RemoteOp(path="/{a}/{b}/{c}/{d}/{f}/{g}/{h}") String getX2(@Request(serializer=FakeWriterSerializer.X.class) K4a rb);
678 }
679
680 public static class K4a {
681 @Path public List<Object> getA() { return alist("foo","","true","123","null",true,123,null); }
682 @Path("b") public List<Object> getX1() { return alist("foo","","true","123","null",true,123,null); }
683 @Path(name="c",serializer=FakeWriterSerializer.X.class) public List<Object> getX2() { return alist("foo","","true","123","null",true,123,null); }
684 @Path("d") @Schema(aev=true) public List<Object> getX3() { return alist(); }
685 @Path("f") public Object[] getX5() { return new Object[]{"foo","","true","123","null",true,123,null}; }
686 @Path(name="g",serializer=FakeWriterSerializer.X.class) public Object[] getX6() { return new Object[]{"foo","","true","123","null",true,123,null}; }
687 @Path("h") @Schema(aev=true)
688 public Object[] getX7() {
689 return new Object[]{};
690 }
691 }
692
693 @Test void k04_requestBean_collections() {
694 var x1 = remote(K.class,K4.class);
695 var x2 = client(K.class).partSerializer(UonSerializer.class).build().getRemote(K4.class);
696 assertEquals("foo,,true,123,null,true,123,null/foo,,true,123,null,true,123,null/xfoo||true|123|null|true|123|nullx//foo,,true,123,null,true,123,null/xfoo||true|123|null|true|123|nullx/", x1.getX1(new K4a()));
697 assertEquals("@(foo,'','true','123','null',true,123,null)/@(foo,'','true','123','null',true,123,null)/xfoo||true|123|null|true|123|nullx/@()/@(foo,'','true','123','null',true,123,null)/xfoo||true|123|null|true|123|nullx/@()", x2.getX1(new K4a()));
698 assertEquals("xfoo||true|123|null|true|123|nullx/xfoo||true|123|null|true|123|nullx/xfoo||true|123|null|true|123|nullx/xx/xfoo||true|123|null|true|123|nullx/xfoo||true|123|null|true|123|nullx/xx", x2.getX2(new K4a()));
699 }
700
701
702
703
704
705 private static PartList parts(String...pairs) {
706 return partList(pairs);
707 }
708
709 private static NameValuePair part(String key, Object val) {
710 return basicPart(key, val);
711 }
712
713 private static RestClient.Builder client(Class<?> c) {
714 return MockRestClient.create(c).defaultRequestConfig(RequestConfig.custom().setNormalizeUri(false).build());
715 }
716
717 private static <T> T remote(Class<?> rest, Class<T> t) {
718 return MockRestClient.create(rest).defaultRequestConfig(RequestConfig.custom().setNormalizeUri(false).build()).build().getRemote(t);
719 }
720 }