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.http.remote;
18  
19  import static org.junit.jupiter.api.Assertions.*;
20  
21  import org.apache.juneau.http.annotation.*;
22  import org.apache.juneau.rest.annotation.*;
23  import org.apache.juneau.rest.config.*;
24  import org.apache.juneau.rest.mock.*;
25  import org.junit.jupiter.api.*;
26  
27  /**
28   * Tests for method-level default values on remote proxy interfaces.
29   *
30   * @since 9.2.0
31   */
32  class Remote_MethodDefaultsAnnotation_Test {
33  
34  	//-----------------------------------------------------------------------------------------------------------------
35  	// @Header defaults on methods
36  	//-----------------------------------------------------------------------------------------------------------------
37  
38  	@Rest
39  	public static class A implements BasicJson5Config {
40  		@RestGet(path="/x1")
41  		public String x1(@Header("Foo") String foo, @Header("Bar") String bar) {
42  			return "Foo=" + foo + ",Bar=" + bar;
43  		}
44  	}
45  
46  	@Remote
47  	public interface A1 {
48  		@RemoteGet("/x1")
49  		@Header(name="Foo", def="defaultFoo")
50  		String x1(@Header("Foo") String foo, @Header("Bar") String bar);
51  	}
52  
53  	@Test
54  	void a01_headerDefaults_providedValue() {
55  		var x = MockRestClient.buildJson(A.class).getRemote(A1.class);
56  		assertEquals("Foo=customFoo,Bar=customBar", x.x1("customFoo", "customBar"));
57  	}
58  
59  	@Test
60  	void a02_headerDefaults_nullValue() {
61  		var x = MockRestClient.buildJson(A.class).getRemote(A1.class);
62  		assertEquals("Foo=defaultFoo,Bar=customBar", x.x1(null, "customBar"));
63  	}
64  
65  	@Test
66  	void a03_headerDefaults_bothNull() {
67  		var x = MockRestClient.buildJson(A.class).getRemote(A1.class);
68  		assertEquals("Foo=defaultFoo,Bar=null", x.x1(null, null));
69  	}
70  
71  	@Remote
72  	public interface A2 {
73  		@RemoteGet("/x1")
74  		@Header(name="Foo", def="defaultFoo")
75  		@Header(name="Bar", def="defaultBar")
76  		String x1(@Header("Foo") String foo, @Header("Bar") String bar);
77  	}
78  
79  	@Test
80  	void a04_headerDefaults_multipleDefaults() {
81  		var x = MockRestClient.buildJson(A.class).getRemote(A2.class);
82  		assertEquals("Foo=defaultFoo,Bar=defaultBar", x.x1(null, null));
83  		assertEquals("Foo=customFoo,Bar=defaultBar", x.x1("customFoo", null));
84  		assertEquals("Foo=defaultFoo,Bar=customBar", x.x1(null, "customBar"));
85  		assertEquals("Foo=customFoo,Bar=customBar", x.x1("customFoo", "customBar"));
86  	}
87  
88  	//-----------------------------------------------------------------------------------------------------------------
89  	// @Query defaults on methods
90  	//-----------------------------------------------------------------------------------------------------------------
91  
92  	@Rest
93  	public static class B implements BasicJson5Config {
94  		@RestGet(path="/x1")
95  		public String x1(@Query("foo") String foo, @Query("bar") String bar) {
96  			return "foo=" + foo + ",bar=" + bar;
97  		}
98  	}
99  
100 	@Remote
101 	public interface B1 {
102 		@RemoteGet("/x1")
103 		@Query(name="foo", def="defaultFoo")
104 		String x1(@Query("foo") String foo, @Query("bar") String bar);
105 	}
106 
107 	@Test
108 	void b01_queryDefaults_providedValue() {
109 		var x = MockRestClient.buildJson(B.class).getRemote(B1.class);
110 		assertEquals("foo=customFoo,bar=customBar", x.x1("customFoo", "customBar"));
111 	}
112 
113 	@Test
114 	void b02_queryDefaults_nullValue() {
115 		var x = MockRestClient.buildJson(B.class).getRemote(B1.class);
116 		assertEquals("foo=defaultFoo,bar=customBar", x.x1(null, "customBar"));
117 	}
118 
119 	@Remote
120 	public interface B2 {
121 		@RemoteGet("/x1")
122 		@Query(name="foo", def="defaultFoo")
123 		@Query(name="bar", def="defaultBar")
124 		String x1(@Query("foo") String foo, @Query("bar") String bar);
125 	}
126 
127 	@Test
128 	void b03_queryDefaults_multipleDefaults() {
129 		var x = MockRestClient.buildJson(B.class).getRemote(B2.class);
130 		assertEquals("foo=defaultFoo,bar=defaultBar", x.x1(null, null));
131 		assertEquals("foo=customFoo,bar=defaultBar", x.x1("customFoo", null));
132 		assertEquals("foo=defaultFoo,bar=customBar", x.x1(null, "customBar"));
133 	}
134 
135 	//-----------------------------------------------------------------------------------------------------------------
136 	// @FormData defaults on methods
137 	//-----------------------------------------------------------------------------------------------------------------
138 
139 	@Rest
140 	public static class C implements BasicJson5Config {
141 		@RestPost(path="/x1")
142 		public String x1(@FormData("foo") String foo, @FormData("bar") String bar) {
143 			return "foo=" + foo + ",bar=" + bar;
144 		}
145 	}
146 
147 	@Remote
148 	public interface C1 {
149 		@RemotePost("/x1")
150 		@FormData(name="foo", def="defaultFoo")
151 		String x1(@FormData("foo") String foo, @FormData("bar") String bar);
152 	}
153 
154 	@Test
155 	void c01_formDataDefaults_providedValue() {
156 		var x = MockRestClient.buildJson(C.class).getRemote(C1.class);
157 		assertEquals("foo=customFoo,bar=customBar", x.x1("customFoo", "customBar"));
158 	}
159 
160 	@Test
161 	void c02_formDataDefaults_nullValue() {
162 		var x = MockRestClient.buildJson(C.class).getRemote(C1.class);
163 		assertEquals("foo=defaultFoo,bar=customBar", x.x1(null, "customBar"));
164 	}
165 
166 	@Remote
167 	public interface C2 {
168 		@RemotePost("/x1")
169 		@FormData(name="foo", def="defaultFoo")
170 		@FormData(name="bar", def="defaultBar")
171 		String x1(@FormData("foo") String foo, @FormData("bar") String bar);
172 	}
173 
174 	@Test
175 	void c03_formDataDefaults_multipleDefaults() {
176 		var x = MockRestClient.buildJson(C.class).getRemote(C2.class);
177 		assertEquals("foo=defaultFoo,bar=defaultBar", x.x1(null, null));
178 		assertEquals("foo=customFoo,bar=defaultBar", x.x1("customFoo", null));
179 	}
180 
181 	//-----------------------------------------------------------------------------------------------------------------
182 	// @Path defaults on methods
183 	// NOTE: Path variables with nulls cause validation errors, so we test with actual provided values only
184 	//-----------------------------------------------------------------------------------------------------------------
185 
186 	@Rest
187 	public static class D implements BasicJson5Config {
188 		@RestGet(path="/x1/{foo}/{bar}")
189 		public String x1(@Path("foo") String foo, @Path("bar") String bar) {
190 			return "foo=" + foo + ",bar=" + bar;
191 		}
192 	}
193 
194 	@Remote
195 	public interface D1 {
196 		@RemoteGet("/x1/{foo}/{bar}")
197 		@Path(name="foo", def="defaultFoo")
198 		String x1(@Path("foo") String foo, @Path("bar") String bar);
199 	}
200 
201 	@Test
202 	void d01_pathDefaults_providedValue() {
203 		var x = MockRestClient.buildJson(D.class).getRemote(D1.class);
204 		assertEquals("foo=customFoo,bar=customBar", x.x1("customFoo", "customBar"));
205 	}
206 
207 	//-----------------------------------------------------------------------------------------------------------------
208 	// @Content defaults on methods
209 	//-----------------------------------------------------------------------------------------------------------------
210 
211 	@Rest
212 	public static class E implements BasicJson5Config {
213 		@RestPost(path="/x1")
214 		public String x1(@Content String content) {
215 			return "content=" + content;
216 		}
217 	}
218 
219 	@Remote
220 	public interface E1 {
221 		@RemotePost("/x1")
222 		@Content(def="{foo:'defaultBar'}")
223 		String x1(@Content String content);
224 	}
225 
226 	@Test
227 	void e01_contentDefaults_providedValue() {
228 		var x = MockRestClient.buildJson(E.class).getRemote(E1.class);
229 		assertEquals("content={foo:'customBar'}", x.x1("{foo:'customBar'}"));
230 	}
231 
232 	@Test
233 	void e02_contentDefaults_nullValue() {
234 		var x = MockRestClient.buildJson(E.class).getRemote(E1.class);
235 		assertEquals("content={foo:'defaultBar'}", x.x1(null));
236 	}
237 
238 	@Remote
239 	public interface E2 {
240 		@RemotePost("/x1")
241 		@Content(def="{foo:'defaultBar'}")
242 		String x1();
243 	}
244 
245 	@Test
246 	void e03_contentDefaults_noParameter() {
247 		var x = MockRestClient.buildJson(E.class).getRemote(E2.class);
248 		assertEquals("content={foo:'defaultBar'}", x.x1());
249 	}
250 
251 	//-----------------------------------------------------------------------------------------------------------------
252 	// Combined defaults test (without @Path since nulls cause validation errors)
253 	//-----------------------------------------------------------------------------------------------------------------
254 
255 	@Rest
256 	public static class F implements BasicJson5Config {
257 		@RestPost(path="/x1")
258 		public String x1(
259 			@Query("queryParam") String queryParam,
260 			@Header("HeaderParam") String headerParam,
261 			@Content String content
262 		) {
263 			return "queryParam=" + queryParam
264 				+ ",HeaderParam=" + headerParam
265 				+ ",content=" + content;
266 		}
267 	}
268 
269 	@Remote
270 	public interface F1 {
271 		@RemotePost("/x1")
272 		@Query(name="queryParam", def="defaultQuery")
273 		@Header(name="HeaderParam", def="defaultHeader")
274 		@Content(def="defaultContent")
275 		String x1(
276 			@Query("queryParam") String queryParam,
277 			@Header("HeaderParam") String headerParam,
278 			@Content String content
279 		);
280 	}
281 
282 	@Test
283 	void f01_combinedDefaults_allNull() {
284 		var x = MockRestClient.buildJson(F.class).getRemote(F1.class);
285 		assertEquals(
286 			"queryParam=defaultQuery,HeaderParam=defaultHeader,content=defaultContent",
287 			x.x1(null, null, null)
288 		);
289 	}
290 
291 	@Test
292 	void f02_combinedDefaults_allProvided() {
293 		var x = MockRestClient.buildJson(F.class).getRemote(F1.class);
294 		assertEquals(
295 			"queryParam=customQuery,HeaderParam=customHeader,content=customContent",
296 			x.x1("customQuery", "customHeader", "customContent")
297 		);
298 	}
299 
300 	@Test
301 	void f03_combinedDefaults_mixed() {
302 		var x = MockRestClient.buildJson(F.class).getRemote(F1.class);
303 		assertEquals(
304 			"queryParam=defaultQuery,HeaderParam=customHeader,content=customContent",
305 			x.x1(null, "customHeader", "customContent")
306 		);
307 	}
308 
309 	//-----------------------------------------------------------------------------------------------------------------
310 	// Parameter-level defaults (9.2.0)
311 	//-----------------------------------------------------------------------------------------------------------------
312 
313 	@Rest
314 	public static class G implements BasicJson5Config {
315 		@RestGet(path="/x1")
316 		public String x1(
317 			@Header("Foo") String foo,
318 			@Query("bar") String bar
319 		) {
320 			return "Foo=" + foo + ",bar=" + bar;
321 		}
322 	}
323 
324 	@Remote
325 	public interface G1 {
326 		@RemoteGet("/x1")
327 		String x1(
328 			@Header(name="Foo", def="paramDefaultFoo") String foo,
329 			@Query(name="bar", def="paramDefaultBar") String bar
330 		);
331 	}
332 
333 	@Test
334 	void g01_parameterDefaults_bothNull() {
335 		var x = MockRestClient.buildJson(G.class).getRemote(G1.class);
336 		assertEquals("Foo=paramDefaultFoo,bar=paramDefaultBar", x.x1(null, null));
337 	}
338 
339 	@Test
340 	void g02_parameterDefaults_oneProvided() {
341 		var x = MockRestClient.buildJson(G.class).getRemote(G1.class);
342 		assertEquals("Foo=customFoo,bar=paramDefaultBar", x.x1("customFoo", null));
343 		assertEquals("Foo=paramDefaultFoo,bar=customBar", x.x1(null, "customBar"));
344 	}
345 
346 	@Test
347 	void g03_parameterDefaults_bothProvided() {
348 		var x = MockRestClient.buildJson(G.class).getRemote(G1.class);
349 		assertEquals("Foo=customFoo,bar=customBar", x.x1("customFoo", "customBar"));
350 	}
351 
352 	//-----------------------------------------------------------------------------------------------------------------
353 	// Parameter-level defaults take precedence over method-level defaults
354 	//-----------------------------------------------------------------------------------------------------------------
355 
356 	@Rest
357 	public static class H implements BasicJson5Config {
358 		@RestGet(path="/x1")
359 		public String x1(@Query("param") String param) {
360 			return "param=" + param;
361 		}
362 	}
363 
364 	@Remote
365 	public interface H1 {
366 		@RemoteGet("/x1")
367 		@Query(name="param", def="methodDefault")
368 		String x1(@Query(name="param", def="paramDefault") String param);
369 	}
370 
371 	@Test
372 	void h01_parameterOverridesMethod_nullValue() {
373 		var x = MockRestClient.buildJson(H.class).getRemote(H1.class);
374 		// Parameter-level default should take precedence
375 		assertEquals("param=paramDefault", x.x1(null));
376 	}
377 
378 	@Test
379 	void h02_parameterOverridesMethod_providedValue() {
380 		var x = MockRestClient.buildJson(H.class).getRemote(H1.class);
381 		assertEquals("param=customValue", x.x1("customValue"));
382 	}
383 
384 	//-----------------------------------------------------------------------------------------------------------------
385 	// @Content parameter-level defaults
386 	//-----------------------------------------------------------------------------------------------------------------
387 
388 	@Rest
389 	public static class I implements BasicJson5Config {
390 		@RestPost(path="/x1")
391 		public String x1(@Content String content) {
392 			return "content=" + content;
393 		}
394 	}
395 
396 	@Remote
397 	public interface I1 {
398 		@RemotePost("/x1")
399 		String x1(@Content(def="{paramDefault:true}") String content);
400 	}
401 
402 	@Test
403 	void i01_contentParameterDefault_nullValue() {
404 		var x = MockRestClient.buildJson(I.class).getRemote(I1.class);
405 		assertEquals("content={paramDefault:true}", x.x1(null));
406 	}
407 
408 	@Test
409 	void i02_contentParameterDefault_providedValue() {
410 		var x = MockRestClient.buildJson(I.class).getRemote(I1.class);
411 		assertEquals("content={custom:true}", x.x1("{custom:true}"));
412 	}
413 
414 	// Test that parameter-level Content default overrides method-level
415 	@Remote
416 	public interface I2 {
417 		@RemotePost("/x1")
418 		@Content(def="{methodDefault:true}")
419 		String x1(@Content(def="{paramDefault:true}") String content);
420 	}
421 
422 	@Test
423 	void i03_contentParameterOverridesMethod() {
424 		var x = MockRestClient.buildJson(I.class).getRemote(I2.class);
425 		assertEquals("content={paramDefault:true}", x.x1(null));
426 	}
427 }