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.rest.annotation;
18  
19  import static org.junit.jupiter.api.Assertions.*;
20  
21  import java.util.*;
22  
23  import org.apache.juneau.*;
24  import org.apache.juneau.annotation.*;
25  import org.apache.juneau.collections.*;
26  import org.apache.juneau.http.annotation.*;
27  import org.apache.juneau.json.*;
28  import org.apache.juneau.rest.*;
29  import org.apache.juneau.rest.httppart.*;
30  import org.apache.juneau.rest.mock.*;
31  import org.apache.juneau.testutils.pojos.*;
32  import org.junit.jupiter.api.*;
33  
34  class Query_Test extends TestBase {
35  
36  	//------------------------------------------------------------------------------------------------------------------
37  	// Simple tests
38  	//------------------------------------------------------------------------------------------------------------------
39  
40  	@Rest
41  	public static class A {
42  		@RestGet
43  		public String a(RestRequest req, @Query("p1") @Schema(aev=true) String p1, @Query("p2") @Schema(aev=true) int p2) {
44  			var q = req.getQueryParams();
45  			return "p1=["+p1+","+q.get("p1").orElse(null)+","+q.get("p1").asString().orElse(null)+"],p2=["+p2+","+q.get("p2").orElse(null)+","+q.get("p2").asInteger().orElse(0)+"]";
46  		}
47  		@RestPost
48  		public String b(RestRequest req, @Query("p1") @Schema(aev=true) String p1, @Query("p2") @Schema(aev=true) int p2) {
49  			var q = req.getQueryParams();
50  			return "p1=["+p1+","+q.get("p1").orElse(null)+","+q.get("p1").asString().orElse(null)+"],p2=["+p2+","+q.get("p2").orElse(null)+","+q.get("p2").asInteger().orElse(0)+"]";
51  		}
52  	}
53  
54  	@Test void a01_basic() throws Exception {
55  		var a = MockRestClient.build(A.class);
56  
57  		a.get("/a?p1=p1&p2=2").run().assertContent("p1=[p1,p1,p1],p2=[2,2,2]");
58  		a.get("/a?p1&p2").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
59  		a.get("/a?p1=&p2=").run().assertContent("p1=[,,],p2=[0,,0]");
60  		a.get("/a").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
61  		a.get("/a?p1").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
62  		a.get("/a?p1=").run().assertContent("p1=[,,],p2=[0,null,0]");
63  		a.get("/a?p2").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
64  		a.get("/a?p2=").run().assertContent("p1=[null,null,null],p2=[0,,0]");
65  		a.get("/a?p1=foo&p2").run().assertContent("p1=[foo,foo,foo],p2=[0,null,0]");
66  		a.get("/a?p1&p2=1").run().assertContent("p1=[null,null,null],p2=[1,1,1]");
67  		String x1 = "a%2Fb%25c%3Dd+e"; // [x/y%z=a+b]
68  		a.get("/a?p1="+x1+"&p2=1").run().assertContent("p1=[a/b%c=d e,a/b%c=d e,a/b%c=d e],p2=[1,1,1]");
69  
70  		a.post("/b?p1=p1&p2=2", null).run().assertContent("p1=[p1,p1,p1],p2=[2,2,2]");
71  		a.post("/b?p1&p2", null).run().assertContent("p1=[null,null,null],p2=[0,null,0]");
72  		a.post("/b?p1=&p2=", null).run().assertContent("p1=[,,],p2=[0,,0]");
73  		a.post("/b", null).run().assertContent("p1=[null,null,null],p2=[0,null,0]");
74  		a.post("/b?p1", null).run().assertContent("p1=[null,null,null],p2=[0,null,0]");
75  		a.post("/b?p1=", null).run().assertContent("p1=[,,],p2=[0,null,0]");
76  		a.post("/b?p2", null).run().assertContent("p1=[null,null,null],p2=[0,null,0]");
77  		a.post("/b?p2=", null).run().assertContent("p1=[null,null,null],p2=[0,,0]");
78  		a.post("/b?p1=foo&p2", null).run().assertContent("p1=[foo,foo,foo],p2=[0,null,0]");
79  		a.post("/b?p1&p2=1", null).run().assertContent("p1=[null,null,null],p2=[1,1,1]");
80  		String x2 = "a%2Fb%25c%3Dd+e"; // [x/y%z=a+b]
81  		a.post("/b?p1="+x2+"&p2=1", null).run().assertContent("p1=[a/b%c=d e,a/b%c=d e,a/b%c=d e],p2=[1,1,1]");
82  	}
83  
84  	//------------------------------------------------------------------------------------------------------------------
85  	// UON parameters
86  	//------------------------------------------------------------------------------------------------------------------
87  
88  	@Rest
89  	public static class B {
90  		@RestGet
91  		public String a(RestRequest req, @Query("p1") String p1) {
92  			var q = req.getQueryParams();
93  			return "p1=["+p1+","+q.get("p1").orElse(null)+","+q.get("p1").asString().orElse(null)+"]";
94  		}
95  		@RestGet
96  		public String b(RestRequest req, @Query("p1") @Schema(f="uon") String p1) {
97  			var q = req.getQueryParams();
98  			return "p1=["+p1+","+q.get("p1").orElse(null)+","+q.get("p1").asString().orElse(null)+"]";
99  		}
100 		@RestPost
101 		public String c(RestRequest req, @Query("p1") String p1) {
102 			var q = req.getQueryParams();
103 			return "p1=["+p1+","+q.get("p1").orElse(null)+","+q.get("p1").asString().orElse(null)+"]";
104 		}
105 		@RestPost
106 		public String d(RestRequest req, @Query("p1") @Schema(f="uon") String p1) {
107 			var q = req.getQueryParams();
108 			return "p1=["+p1+","+q.get("p1").orElse(null)+","+q.get("p1").asString().orElse(null)+"]";
109 		}
110 	}
111 
112 	@Test void b01_uonParameters() throws Exception {
113 		var b = MockRestClient.build(B.class);
114 		b.get("/a?p1=p1").run().assertContent("p1=[p1,p1,p1]");
115 		b.get("/a?p1='p1'").run().assertContent("p1=['p1','p1','p1']");
116 		b.get("/b?p1=p1").run().assertContent("p1=[p1,p1,p1]");
117 		b.get("/b?p1='p1'").run().assertContent("p1=[p1,'p1','p1']");
118 		b.post("/c?p1=p1", null).run().assertContent("p1=[p1,p1,p1]");
119 		b.post("/c?p1='p1'", null).run().assertContent("p1=['p1','p1','p1']");
120 		b.post("/d?p1=p1", null).run().assertContent("p1=[p1,p1,p1]");
121 		b.post("/d?p1='p1'", null).run().assertContent("p1=[p1,'p1','p1']");
122 	}
123 
124 	//------------------------------------------------------------------------------------------------------------------
125 	// Multipart parameters (e.g. &key=val1,&key=val2).
126 	//------------------------------------------------------------------------------------------------------------------
127 
128 	@Rest(serializers=Json5Serializer.class)
129 	public static class C {
130 		public static class C1 {
131 			public String a;
132 			public int b;
133 			public boolean c;
134 		}
135 
136 		@RestGet
137 		public Object a(@Query("x") @Schema(cf="multi") String[] x) {
138 			return x;
139 		}
140 		@RestGet
141 		public Object b(@Query("x") @Schema(cf="multi") int[] x) {
142 			return x;
143 		}
144 		@RestGet
145 		public Object c(@Query("x") @Schema(cf="multi") List<String> x) {
146 			return x;
147 		}
148 		@RestGet
149 		public Object d(@Query("x") @Schema(cf="multi") List<Integer> x) {
150 			return x;
151 		}
152 		@RestGet
153 		public Object e(@Query("x") @Schema(cf="multi",items=@Items(f="uon")) C1[] x) {
154 			return x;
155 		}
156 		@RestGet
157 		public Object f(@Query("x") @Schema(cf="multi",items=@Items(f="uon")) List<C1> x) {
158 			return x;
159 		}
160 	}
161 
162 	@Test void c01_multipartParams() throws Exception {
163 		var c = MockRestClient.build(C.class);
164 		c.get("/a?x=a").run().assertContent("['a']");
165 		c.get("/a?x=a&x=b").run().assertContent("['a','b']");
166 		c.get("/b?x=1").run().assertContent("[1]");
167 		c.get("/b?x=1&x=2").run().assertContent("[1,2]");
168 		c.get("/c?x=a").run().assertContent("['a']");
169 		c.get("/c?x=a&x=b").run().assertContent("['a','b']");
170 		c.get("/d?x=1").run().assertContent("[1]");
171 		c.get("/d?x=1&x=2").run().assertContent("[1,2]");
172 		c.get("/e?x=a=1,b=2,c=false").run().assertContent("[{a:'1,b=2,c=false',b:0,c:false}]");
173 		c.get("/e?x=a=1,b=2,c=false&x=a=3,b=4,c=true").run().assertContent("[{a:'1,b=2,c=false',b:0,c:false},{a:'3,b=4,c=true',b:0,c:false}]");
174 		c.get("/f?x=a=1,b=2,c=false").run().assertContent("[{a:'1,b=2,c=false',b:0,c:false}]");
175 		c.get("/f?x=a=1,b=2,c=false&x=a=3,b=4,c=true").run().assertContent("[{a:'1,b=2,c=false',b:0,c:false},{a:'3,b=4,c=true',b:0,c:false}]");
176 	}
177 
178 	//------------------------------------------------------------------------------------------------------------------
179 	// Default values.
180 	//------------------------------------------------------------------------------------------------------------------
181 
182 	@Rest
183 	public static class D {
184 		@RestGet(defaultRequestQueryData={"f1:1","f2=2"," f3 : 3 "})
185 		public JsonMap a(RequestQueryParams query) {
186 			return JsonMap.create()
187 				.append("f1", query.get("f1").asString())
188 				.append("f2", query.get("f2").asString())
189 				.append("f3", query.get("f3").asString());
190 		}
191 		@RestGet
192 		public JsonMap b(@Query("f1") String f1, @Query("f2") String f2, @Query("f3") String f3) {
193 			return JsonMap.create()
194 				.append("f1", f1)
195 				.append("f2", f2)
196 				.append("f3", f3);
197 		}
198 		@RestGet
199 		public JsonMap c(@Query("f1") @Schema(df="1") String f1, @Query("f2") @Schema(df="2") String f2, @Query("f3") @Schema(df="3") String f3) {
200 			return JsonMap.create()
201 				.append("f1", f1)
202 				.append("f2", f2)
203 				.append("f3", f3);
204 		}
205 		@RestGet(defaultRequestQueryData={"f1:1","f2=2"," f3 : 3 "})
206 		public JsonMap d(@Query("f1") @Schema(df="4") String f1, @Query("f2") @Schema(df="5") String f2, @Query("f3") @Schema(df="6") String f3) {
207 			return JsonMap.create()
208 				.append("f1", f1)
209 				.append("f2", f2)
210 				.append("f3", f3);
211 		}
212 	}
213 
214 	@Test void d01_defaultValues() throws Exception {
215 		var d = MockRestClient.build(D.class);
216 		d.get("/a").run().assertContent("{f1:'1',f2:'2',f3:'3'}");
217 		d.get("/a").queryData("f1",4).queryData("f2",5).queryData("f3",6).run().assertContent("{f1:'4',f2:'5',f3:'6'}");
218 		d.get("/b").run().assertContent("{f1:null,f2:null,f3:null}");
219 		d.get("/b").queryData("f1",4).queryData("f2",5).queryData("f3",6).run().assertContent("{f1:'4',f2:'5',f3:'6'}");
220 		d.get("/c").run().assertContent("{f1:'1',f2:'2',f3:'3'}");
221 		d.get("/c").queryData("f1",4).queryData("f2",5).queryData("f3",6).run().assertContent("{f1:'4',f2:'5',f3:'6'}");
222 		d.get("/d").run().assertContent("{f1:'1',f2:'2',f3:'3'}");
223 		d.get("/d").queryData("f1",7).queryData("f2",8).queryData("f3",9).run().assertContent("{f1:'7',f2:'8',f3:'9'}");
224 	}
225 
226 	//------------------------------------------------------------------------------------------------------------------
227 	// Optional query parameter.
228 	//------------------------------------------------------------------------------------------------------------------
229 
230 	@Rest(serializers=Json5Serializer.class)
231 	public static class E {
232 		@RestGet
233 		public Object a(@Query("f1") Optional<Integer> f1) {
234 			assertNotNull(f1);
235 			return f1;
236 		}
237 		@RestGet
238 		public Object b(@Query("f1") Optional<ABean> f1) {
239 			assertNotNull(f1);
240 			return f1;
241 		}
242 		@RestGet
243 		public Object c(@Query("f1") Optional<List<ABean>> f1) {
244 			assertNotNull(f1);
245 			return f1;
246 		}
247 		@RestGet
248 		public Object d(@Query("f1") List<Optional<ABean>> f1) {
249 			return f1;
250 		}
251 	}
252 
253 	@Test void e01_optionalParams() throws Exception {
254 		var e = MockRestClient.buildJson(E.class);
255 		e.get("/a?f1=123")
256 			.run()
257 			.assertStatus(200)
258 			.assertContent("123");
259 		e.get("/a")
260 			.run()
261 			.assertStatus(200)
262 			.assertContent("null");
263 		e.get("/b?f1=a=1,b=foo")
264 			.run()
265 			.assertStatus(200)
266 			.assertContent("{a:1,b:'foo'}");
267 		e.get("/b")
268 			.run()
269 			.assertStatus(200)
270 			.assertContent("null");
271 		e.get("/c?f1=@((a=1,b=foo))")
272 			.run()
273 			.assertStatus(200)
274 			.assertContent("[{a:1,b:'foo'}]");
275 		e.get("/c")
276 			.run()
277 			.assertStatus(200)
278 			.assertContent("null");
279 		e.get("/d?f1=@((a=1,b=foo))")
280 			.run()
281 			.assertStatus(200)
282 			.assertContent("[{a:1,b:'foo'}]");
283 		e.get("/d")
284 			.run()
285 			.assertStatus(200)
286 			.assertContent("null");
287 	}
288 
289 	//------------------------------------------------------------------------------------------------------------------
290 	// Default parameters
291 	//------------------------------------------------------------------------------------------------------------------
292 
293 	@Rest(serializers=Json5Serializer.class)
294 	public static class F {
295 		@RestGet
296 		public Object a1(@Query(name="f1", def="1") Integer f1) {
297 			assertNotNull(f1);
298 			return f1;
299 		}
300 		@RestGet
301 		public Object a2(@Query(name="f1", def="1") Optional<Integer> f1) {
302 			assertNotNull(f1);
303 			return f1.get();
304 		}
305 		@RestGet
306 		public Object b1(@Query(name="f1", def="a=1,b=foo") ABean f1) {
307 			assertNotNull(f1);
308 			return f1;
309 		}
310 		@RestGet
311 		public Object b2(@Query(name="f1", def="a=1,b=foo") Optional<ABean> f1) {
312 			assertNotNull(f1);
313 			return f1.get();
314 		}
315 		@RestGet
316 		public Object c1(@Query(name="f1", def="@((a=1,b=foo))") List<ABean> f1) {
317 			assertNotNull(f1);
318 			return f1;
319 		}
320 		@RestGet
321 		public Object c2(@Query(name="f1", def="@((a=1,b=foo))") Optional<List<ABean>> f1) {
322 			assertNotNull(f1);
323 			return f1.get();
324 		}
325 		@RestGet
326 		public Object d(@Query(name="f1", def="@((a=1,b=foo))") List<Optional<ABean>> f1) {
327 			return f1;
328 		}
329 	}
330 
331 	@Test void f01_defaultParams() throws Exception {
332 		var f = MockRestClient.buildJson(F.class);
333 		f.get("/a1?f1=123")
334 			.run()
335 			.assertStatus(200)
336 			.assertContent("123");
337 		f.get("/a1")
338 			.run()
339 			.assertStatus(200)
340 			.assertContent("1");
341 		f.get("/a2?f1=123")
342 			.run()
343 			.assertStatus(200)
344 			.assertContent("123");
345 		f.get("/a2")
346 			.run()
347 			.assertStatus(200)
348 			.assertContent("1");
349 		f.get("/b1?f1=a=2,b=bar")
350 			.run()
351 			.assertStatus(200)
352 			.assertContent("{a:2,b:'bar'}");
353 		f.get("/b1")
354 			.run()
355 			.assertStatus(200)
356 			.assertContent("{a:1,b:'foo'}");
357 		f.get("/b2?f1=a=2,b=bar")
358 			.run()
359 			.assertStatus(200)
360 			.assertContent("{a:2,b:'bar'}");
361 		f.get("/b2")
362 			.run()
363 			.assertStatus(200)
364 			.assertContent("{a:1,b:'foo'}");
365 		f.get("/c1?f1=@((a=2,b=bar))")
366 			.run()
367 			.assertStatus(200)
368 			.assertContent("[{a:2,b:'bar'}]");
369 		f.get("/c1")
370 			.run()
371 			.assertStatus(200)
372 			.assertContent("[{a:1,b:'foo'}]");
373 		f.get("/c2?f1=@((a=2,b=bar))")
374 			.run()
375 			.assertStatus(200)
376 			.assertContent("[{a:2,b:'bar'}]");
377 		f.get("/c2")
378 			.run()
379 			.assertStatus(200)
380 			.assertContent("[{a:1,b:'foo'}]");
381 		f.get("/d?f1=@((a=2,b=bar))")
382 			.run()
383 			.assertStatus(200)
384 			.assertContent("[{a:2,b:'bar'}]");
385 		f.get("/d")
386 			.run()
387 			.assertStatus(200)
388 			.assertContent("[{a:1,b:'foo'}]");
389 	}
390 }