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.apache.juneau.urlencoding.*;
33  import org.junit.jupiter.api.*;
34  
35  class FormData_Test extends TestBase {
36  
37  	//------------------------------------------------------------------------------------------------------------------
38  	// Simple tests
39  	//------------------------------------------------------------------------------------------------------------------
40  
41  	@Rest(parsers=UrlEncodingParser.class)
42  	public static class A {
43  		@RestPost
44  		public String a(RestRequest req, @FormData("p1") @Schema(allowEmptyValue=true) String p1, @FormData("p2") @Schema(allowEmptyValue=true) int p2) throws Exception {
45  			var f = req.getFormParams();
46  			return "p1=["+p1+","+f.get("p1").orElse(null)+","+f.get("p1").asString().orElse(null)+"],p2=["+p2+","+f.get("p2").orElse(null)+","+f.get("p2").as(int.class).orElse(null)+"]";
47  		}
48  	}
49  
50  	@Test void a01_basic() throws Exception {
51  		var a = MockRestClient.build(A.class);
52  		a.post("/a", "p1=p1&p2=2").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[p1,p1,p1],p2=[2,2,2]");
53  		a.post("/a", "p1&p2").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
54  		a.post("/a", "p1=&p2=").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[,,],p2=[0,,0]");
55  		a.post("/a", "").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
56  		a.post("/a", "p1").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
57  		a.post("/a", "p1=").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[,,],p2=[0,null,0]");
58  		a.post("/a", "p2").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[null,null,null],p2=[0,null,0]");
59  		a.post("/a", "p2=").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[null,null,null],p2=[0,,0]");
60  		a.post("/a", "p1=foo&p2").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[foo,foo,foo],p2=[0,null,0]");
61  		a.post("/a", "p1&p2=1").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[null,null,null],p2=[1,1,1]");
62  		String x = "a%2Fb%25c%3Dd+e"; // [x/y%z=a+b]
63  		a.post("/a", "p1="+x+"&p2=1").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[a/b%c=d e,a/b%c=d e,a/b%c=d e],p2=[1,1,1]");
64  	}
65  
66  	//------------------------------------------------------------------------------------------------------------------
67  	// UON parameters
68  	//------------------------------------------------------------------------------------------------------------------
69  
70  	@Rest
71  	public static class B {
72  		@RestPost
73  		public String a(RestRequest req, @FormData("p1") String p1) throws Exception {
74  			var f = req.getFormParams();
75  			return "p1=["+p1+","+f.get("p1").orElse(null)+","+f.get("p1").orElse(null)+"]";
76  		}
77  		@RestPost
78  		public String b(RestRequest req, @FormData("p1") @Schema(format="uon") String p1) throws Exception {
79  			var f = req.getFormParams();
80  			return "p1=["+p1+","+f.get("p1").orElse(null)+","+f.get("p1").orElse(null)+"]";
81  		}
82  	}
83  
84  	@Test void b01_uonParameters() throws Exception {
85  		var b = MockRestClient.build(B.class);
86  
87  		b.post("/a", "p1=p1").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[p1,p1,p1]");
88  		b.post("/a", "p1='p1'").contentType("application/x-www-form-urlencoded").run().assertContent("p1=['p1','p1','p1']");
89  
90  		b.post("/b", "p1=p1").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[p1,p1,p1]");
91  		b.post("/b", "p1='p1'").contentType("application/x-www-form-urlencoded").run().assertContent("p1=[p1,'p1','p1']");
92  	}
93  
94  	//------------------------------------------------------------------------------------------------------------------
95  	// Default values.
96  	//------------------------------------------------------------------------------------------------------------------
97  
98  	@Rest
99  	public static class C {
100 		@RestPost(defaultRequestFormData={"f1:1","f2=2"," f3 : 3 "})
101 		public JsonMap a(RequestFormParams formData) {
102 			return JsonMap.create()
103 				.append("f1", formData.get("f1").asString())
104 				.append("f2", formData.get("f2").asString())
105 				.append("f3", formData.get("f3").asString());
106 		}
107 		@RestPost
108 		public JsonMap b(@FormData("f1") String f1, @FormData("f2") String f2, @FormData("f3") String f3) {
109 			return JsonMap.create()
110 				.append("f1", f1)
111 				.append("f2", f2)
112 				.append("f3", f3);
113 		}
114 		@RestPost
115 		public JsonMap c(@FormData("f1") @Schema(_default="1") String f1, @FormData("f2") @Schema(_default="2") String f2, @FormData("f3") @Schema(_default="3") String f3) {
116 			return JsonMap.create()
117 				.append("f1", f1)
118 				.append("f2", f2)
119 				.append("f3", f3);
120 		}
121 		@RestPost(defaultRequestFormData={"f1:1","f2=2"," f3 : 3 "})
122 		public JsonMap d(@FormData("f1") @Schema(_default="4") String f1, @FormData("f2") @Schema(_default="5") String f2, @FormData("f3") @Schema(_default="6") String f3) {
123 			return JsonMap.create()
124 				.append("f1", f1)
125 				.append("f2", f2)
126 				.append("f3", f3);
127 		}
128 	}
129 
130 	@Test void c01_defaultFormData() throws Exception {
131 		var c = MockRestClient.build(C.class);
132 
133 		c.post("/a").contentType("application/x-www-form-urlencoded").run().assertContent("{f1:'1',f2:'2',f3:'3'}");
134 		c.post("/a").contentType("application/x-www-form-urlencoded").formData("f1",4).formData("f2",5).formData("f3",6).run().assertContent("{f1:'4',f2:'5',f3:'6'}");
135 
136 		c.post("/b").contentType("application/x-www-form-urlencoded").run().assertContent("{f1:null,f2:null,f3:null}");
137 		c.post("/b").contentType("application/x-www-form-urlencoded").formData("f1",4).formData("f2",5).formData("f3",6).run().assertContent("{f1:'4',f2:'5',f3:'6'}");
138 
139 		c.post("/c").contentType("application/x-www-form-urlencoded").run().assertContent("{f1:'1',f2:'2',f3:'3'}");
140 		c.post("/c").contentType("application/x-www-form-urlencoded").formData("f1",4).formData("f2",5).formData("f3",6).run().assertContent("{f1:'4',f2:'5',f3:'6'}");
141 
142 		c.post("/d").contentType("application/x-www-form-urlencoded").run().assertContent("{f1:'1',f2:'2',f3:'3'}");
143 		c.post("/d").contentType("application/x-www-form-urlencoded").formData("f1",7).formData("f2",8).formData("f3",9).run().assertContent("{f1:'7',f2:'8',f3:'9'}");
144 	}
145 
146 	//------------------------------------------------------------------------------------------------------------------
147 	// Optional form data parameter.
148 	//------------------------------------------------------------------------------------------------------------------
149 
150 	@Rest(serializers=Json5Serializer.class)
151 	public static class D {
152 		@RestPost
153 		public Object a(@FormData("f1") Optional<Integer> f1) {
154 			assertNotNull(f1);
155 			return f1;
156 		}
157 		@RestPost
158 		public Object b(@FormData("f1") Optional<ABean> f1) {
159 			assertNotNull(f1);
160 			return f1;
161 		}
162 		@RestPost
163 		public Object c(@FormData("f1") Optional<List<ABean>> f1) {
164 			assertNotNull(f1);
165 			return f1;
166 		}
167 		@RestPost
168 		public Object d(@FormData("f1") List<Optional<ABean>> f1) {
169 			return f1;
170 		}
171 	}
172 
173 	@Test void d01_optionalParams() throws Exception {
174 		var d = MockRestClient.create(D.class).accept("application/json").contentType("application/x-www-form-urlencoded").build();
175 
176 		d.post("/a", "f1=123")
177 			.run()
178 			.assertStatus(200)
179 			.assertContent("123");
180 		d.post("/a", "null")
181 			.run()
182 			.assertStatus(200)
183 			.assertContent("null");
184 
185 		d.post("/b", "f1=a=1,b=foo")
186 			.run()
187 			.assertStatus(200)
188 			.assertContent("{a:1,b:'foo'}");
189 		d.post("/b", "null")
190 			.run()
191 			.assertStatus(200)
192 			.assertContent("null");
193 
194 		d.post("/c", "f1=@((a=1,b=foo))")
195 			.run()
196 			.assertStatus(200)
197 			.assertContent("[{a:1,b:'foo'}]");
198 		d.post("/c", "null")
199 			.run()
200 			.assertStatus(200)
201 			.assertContent("null");
202 
203 		d.post("/d", "f1=@((a=1,b=foo))")
204 			.run()
205 			.assertStatus(200)
206 			.assertContent("[{a:1,b:'foo'}]");
207 		d.post("/d", "null")
208 			.run()
209 			.assertStatus(200)
210 			.assertContent("null");
211 	}
212 
213 	//------------------------------------------------------------------------------------------------------------------
214 	// Default form data parameter.
215 	//------------------------------------------------------------------------------------------------------------------
216 
217 	@Rest(serializers=Json5Serializer.class)
218 	public static class F {
219 		@RestPost
220 		public Object a1(@FormData(name="f1",def="1") Integer f1) {
221 			assertNotNull(f1);
222 			return f1;
223 		}
224 		@RestPost
225 		public Object a2(@FormData(name="f1",def="1") Optional<Integer> f1) {
226 			assertNotNull(f1);
227 			return f1;
228 		}
229 		@RestPost
230 		public Object b1(@FormData(name="f1",def="a=2,b=bar") ABean f1) {
231 			assertNotNull(f1);
232 			return f1;
233 		}
234 		@RestPost
235 		public Object b2(@FormData(name="f1",def="a=2,b=bar") Optional<ABean> f1) {
236 			assertNotNull(f1);
237 			return f1;
238 		}
239 		@RestPost
240 		public Object c1(@FormData(name="f1",def="@((a=2,b=bar))") List<ABean> f1) {
241 			assertNotNull(f1);
242 			return f1;
243 		}
244 		@RestPost
245 		public Object c2(@FormData(name="f1",def="@((a=2,b=bar))") Optional<List<ABean>> f1) {
246 			assertNotNull(f1);
247 			return f1;
248 		}
249 		@RestPost
250 		public Object d(@FormData(name="f1",def="@((a=2,b=bar))") List<Optional<ABean>> f1) {
251 			return f1;
252 		}
253 	}
254 
255 	@Test void f01_defaultParams() throws Exception {
256 		var f = MockRestClient.create(F.class).accept("application/json").contentType("application/x-www-form-urlencoded").build();
257 
258 		f.post("/a1", "f1=123")
259 			.run()
260 			.assertStatus(200)
261 			.assertContent("123");
262 		f.post("/a1", "")
263 			.run()
264 			.assertStatus(200)
265 			.assertContent("1");
266 		f.post("/a2", "f1=123")
267 			.run()
268 			.assertStatus(200)
269 			.assertContent("123");
270 		f.post("/a2", "")
271 			.run()
272 			.assertStatus(200)
273 			.assertContent("1");
274 
275 		f.post("/b1", "f1=a=1,b=foo")
276 			.run()
277 			.assertStatus(200)
278 			.assertContent("{a:1,b:'foo'}");
279 		f.post("/b1", "")
280 			.run()
281 			.assertStatus(200)
282 			.assertContent("{a:2,b:'bar'}");
283 		f.post("/b2", "f1=a=1,b=foo")
284 			.run()
285 			.assertStatus(200)
286 			.assertContent("{a:1,b:'foo'}");
287 		f.post("/b2", "")
288 			.run()
289 			.assertStatus(200)
290 			.assertContent("{a:2,b:'bar'}");
291 
292 		f.post("/c1", "f1=@((a=1,b=foo))")
293 			.run()
294 			.assertStatus(200)
295 			.assertContent("[{a:1,b:'foo'}]");
296 		f.post("/c1", "null")
297 			.run()
298 			.assertStatus(200)
299 			.assertContent("[{a:2,b:'bar'}]");
300 		f.post("/c2", "f1=@((a=1,b=foo))")
301 			.run()
302 			.assertStatus(200)
303 			.assertContent("[{a:1,b:'foo'}]");
304 		f.post("/c2", "null")
305 			.run()
306 			.assertStatus(200)
307 			.assertContent("[{a:2,b:'bar'}]");
308 
309 
310 		f.post("/d", "f1=@((a=1,b=foo))")
311 			.run()
312 			.assertStatus(200)
313 			.assertContent("[{a:1,b:'foo'}]");
314 		f.post("/d", "null")
315 			.run()
316 			.assertStatus(200)
317 			.assertContent("[{a:2,b:'bar'}]");
318 	}
319 }