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