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.urlencoding;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import java.net.*;
24  import java.util.*;
25  
26  import org.apache.juneau.*;
27  import org.apache.juneau.annotation.*;
28  import org.apache.juneau.collections.*;
29  import org.junit.jupiter.api.*;
30  
31  class Common_UrlEncodingTest extends TestBase {
32  	UrlEncodingParser p = UrlEncodingParser.DEFAULT;
33  
34  	//====================================================================================================
35  	// Trim nulls from beans
36  	//====================================================================================================
37  	@Test void a01_trimNullsFromBeans() throws Exception {
38  		var s = UrlEncodingSerializer.create();
39  		var t1 = A.create();
40  
41  		var r = s.build().serialize(t1);
42  		assertEquals("s2=s2", r);
43  		var t2 = p.parse(r, A.class);
44  		assertEquals(json(t2), json(t1));
45  
46  		s.keepNullProperties();
47  		r = s.build().serialize(t1);
48  		assertEquals("s1=null&s2=s2", r);
49  		t2 = p.parse(r, A.class);
50  		assertEquals(json(t2), json(t1));
51  	}
52  
53  	public static class A {
54  		public String s1, s2;
55  
56  		public static A create() {
57  			var t = new A();
58  			t.s2 = "s2";
59  			return t;
60  		}
61  	}
62  
63  	//====================================================================================================
64  	// Trim empty maps
65  	//====================================================================================================
66  	@Test void a02_trimEmptyMaps() throws Exception {
67  		var s = UrlEncodingSerializer.create();
68  		var t1 = B.create();
69  		var r = s.build().serialize(t1);
70  
71  		assertEquals("f1=()&f2=(f2a=null,f2b=(s2=s2))", r);
72  		var t2 = p.parse(r, B.class);
73  		assertEquals(json(t2), json(t1));
74  
75  		s.trimEmptyMaps();
76  		r = s.build().serialize(t1);
77  		assertEquals("f2=(f2a=null,f2b=(s2=s2))", r);
78  		t2 = p.parse(r, B.class);
79  		assertNull(t2.f1);
80  	}
81  
82  	public static class B {
83  		public TreeMap<String,A> f1, f2;
84  
85  		public static B create() {
86  			var t = new B();
87  			t.f1 = new TreeMap<>();
88  			t.f2 = new TreeMap<>(){{put("f2a",null);put("f2b",A.create());}};
89  			return t;
90  		}
91  	}
92  
93  	//====================================================================================================
94  	// Trim empty lists
95  	//====================================================================================================
96  	@Test void a03_trimEmptyLists() throws Exception {
97  		var s = UrlEncodingSerializer.create();
98  		var t1 = C.create();
99  		var r = s.build().serialize(t1);
100 
101 		assertEquals("f1=@()&f2=@(null,(s2=s2))", r);
102 		var t2 = p.parse(r, C.class);
103 		assertEquals(json(t2), json(t1));
104 
105 		s.trimEmptyCollections();
106 		r = s.build().serialize(t1);
107 		assertEquals("f2=@(null,(s2=s2))", r);
108 		t2 = p.parse(r, C.class);
109 		assertNull(t2.f1);
110 	}
111 
112 	public static class C {
113 		public List<A> f1, f2;
114 
115 		public static C create() {
116 			var t = new C();
117 			t.f1 = l();
118 			t.f2 = l(null,A.create());
119 			return t;
120 		}
121 	}
122 
123 	//====================================================================================================
124 	// Trim empty arrays
125 	//====================================================================================================
126 	@Test void a04_trimEmptyArrays() throws Exception {
127 		var s = UrlEncodingSerializer.create();
128 		var t1 = D.create();
129 		var r = s.build().serialize(t1);
130 
131 		assertEquals("f1=@()&f2=@(null,(s2=s2))", r);
132 		var t2 = p.parse(r, D.class);
133 		assertEquals(json(t2), json(t1));
134 
135 		s.trimEmptyCollections();
136 		r = s.build().serialize(t1);
137 		assertEquals("f2=@(null,(s2=s2))", r);
138 		t2 = p.parse(r, D.class);
139 		assertNull(t2.f1);
140 	}
141 
142 	public static class D {
143 		public A[] f1, f2;
144 
145 		public static D create() {
146 			var t = new D();
147 			t.f1 = a();
148 			t.f2 = a(null, A.create());
149 			return t;
150 		}
151 	}
152 
153 	//====================================================================================================
154 	// @Beanp.bpi annotation.
155 	//====================================================================================================
156 	@Test void a05_beanPropertyProperies() throws Exception {
157 		var s = UrlEncodingSerializer.DEFAULT;
158 		var ue = s.serialize(new E1());
159 		assertEquals("x1=(f1=1)&x2=(f1=1)&x3=@((f1=1))&x4=@((f1=1))&x5=@((f1=1))&x6=@((f1=1))", ue);
160 	}
161 
162 	public static class E1 {
163 		@Beanp(properties="f1") public E2 x1 = new E2();
164 		@Beanp(properties="f1") public Map<String,Integer> x2 = m("f1",1,"f2",2);
165 		@Beanp(properties="f1") public E2[] x3 = {new E2()};
166 		@Beanp(properties="f1") public List<E2> x4 = l(new E2());
167 		@Beanp(properties="f1") public JsonMap[] x5 = {JsonMap.of("f1",1,"f2",2)};
168 		@Beanp(properties="f1") public List<JsonMap> x6 = l(JsonMap.of("f1",1,"f2",2));
169 	}
170 
171 	public static class E2 {
172 		public int f1 = 1;
173 		public int f2 = 2;
174 	}
175 
176 	//====================================================================================================
177 	// @Beanp.bpi annotation on list of beans.
178 	//====================================================================================================
179 	@Test void a06_beanPropertyPropertiesOnListOfBeans() throws Exception {
180 		var s = UrlEncodingSerializer.DEFAULT;
181 		var l = new LinkedList<>();
182 		var t = new F();
183 		t.x1.add(new F());
184 		l.add(t);
185 		var m = JsonMap.of("t", l);
186 		var xml = s.serialize(m);
187 		assertEquals("t=@((x1=@((x2=2)),x2=2))", xml);
188 		xml = s.serialize(l);
189 		assertEquals("0=(x1=@((x2=2)),x2=2)", xml);
190 	}
191 
192 	public static class F {
193 		@Beanp(properties="x2") public List<F> x1 = new LinkedList<>();
194 		public int x2 = 2;
195 	}
196 
197 	//====================================================================================================
198 	// Test URIAttr - Test that URLs and URIs are serialized and parsed correctly.
199 	//====================================================================================================
200 	@Test void a07_uRIAttr() throws Exception {
201 		var s = UrlEncodingSerializer.DEFAULT;
202 		var p2 = UrlEncodingParser.DEFAULT;
203 
204 		var t = new G();
205 		t.uri = new URI("http://uri");
206 		t.f1 = new URI("http://f1");
207 		t.f2 = url("http://f2");
208 
209 		var r = s.serialize(t);
210 		t = p2.parse(r, G.class);
211 		assertEquals("http://uri", t.uri.toString());
212 		assertEquals("http://f1", t.f1.toString());
213 		assertEquals("http://f2", t.f2.toString());
214 	}
215 
216 	public static class G {
217 		public URI uri;
218 		public URI f1;
219 		public URL f2;
220 	}
221 
222 	//====================================================================================================
223 	// Recursion
224 	//====================================================================================================
225 	@Test void a08_recursion() throws Exception {
226 		var s = UrlEncodingSerializer.create().maxDepth(Integer.MAX_VALUE);
227 
228 		var r1 = new R1();
229 		var r2 = new R2();
230 		var r3 = new R3();
231 		r1.r2 = r2;
232 		r2.r3 = r3;
233 		r3.r1 = r1;
234 
235 		// No recursion detection
236 		assertThrowsWithMessage(Exception.class, "It's recommended you use the BeanTraverseContext.BEANTRAVERSE_detectRecursions setting to help locate the loop.", ()->s.build().serialize(r1));
237 
238 		// Recursion detection, no ignore
239 		s.detectRecursions();
240 		assertThrowsWithMessage(Exception.class, l("[0] root:org.apache.juneau.urlencoding.Common_UrlEncodingTest$R1", "->[1] r2:org.apache.juneau.urlencoding.Common_UrlEncodingTest$R2", "->[2] r3:org.apache.juneau.urlencoding.Common_UrlEncodingTest$R3", "->[3] r1:org.apache.juneau.urlencoding.Common_UrlEncodingTest$R1"), ()->s.build().serialize(r1));
241 
242 		s.ignoreRecursions();
243 		assertEquals("name=foo&r2=(name=bar,r3=(name=baz))", s.build().serialize(r1));
244 	}
245 
246 	public static class R1 {
247 		public String name = "foo";
248 		public R2 r2;
249 	}
250 	public static class R2 {
251 		public String name = "bar";
252 		public R3 r3;
253 	}
254 	public static class R3 {
255 		public String name = "baz";
256 		public R1 r1;
257 	}
258 }