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.a.rttests;
18  
19  import static java.util.Collections.*;
20  import static org.apache.juneau.TestUtils.*;
21  
22  import java.util.*;
23  
24  import org.apache.juneau.*;
25  import org.apache.juneau.annotation.*;
26  import org.apache.juneau.html.*;
27  import org.apache.juneau.json.*;
28  import org.apache.juneau.msgpack.*;
29  import org.apache.juneau.uon.*;
30  import org.apache.juneau.urlencoding.*;
31  import org.apache.juneau.xml.*;
32  import org.junit.jupiter.params.*;
33  import org.junit.jupiter.params.provider.*;
34  
35  /**
36   * Tests designed to serialize and parse objects to make sure we end up
37   * with the same objects for all serializers and parsers.
38   */
39  class RoundTripBeansWithBuilders_Test extends TestBase {
40  
41  	private static RoundTrip_Tester[] TESTERS = {
42  		tester(1, "Json - default")
43  			.serializer(JsonSerializer.create().keepNullProperties().addBeanTypes().addRootType())
44  			.parser(JsonParser.create())
45  			.build(),
46  		tester(2, "Json - lax")
47  			.serializer(JsonSerializer.create().json5().keepNullProperties().addBeanTypes().addRootType())
48  			.parser(JsonParser.create())
49  			.build(),
50  		tester(3, "Json - lax, readable")
51  			.serializer(JsonSerializer.create().json5().ws().keepNullProperties().addBeanTypes().addRootType())
52  			.parser(JsonParser.create())
53  			.build(),
54  		tester(4, "Xml - namespaces, validation, readable")
55  			.serializer(XmlSerializer.create().ns().sq().keepNullProperties().addNamespaceUrisToRoot().useWhitespace().addBeanTypes().addRootType())
56  			.parser(XmlParser.create())
57  			.validateXmlWhitespace()
58  			.validateXml()
59  			.build(),
60  		tester(5, "Xml - no namespaces, validation")
61  			.serializer(XmlSerializer.create().sq().keepNullProperties().addBeanTypes().addRootType())
62  			.parser(XmlParser.create())
63  			.validateXmlWhitespace()
64  			.build(),
65  		tester(6, "Html - default")
66  			.serializer(HtmlSerializer.create().keepNullProperties().addBeanTypes().addRootType())
67  			.parser(HtmlParser.create())
68  			.validateXmlWhitespace()
69  			.build(),
70  		tester(7, "Html - readable")
71  			.serializer(HtmlSerializer.create().sq().ws().keepNullProperties().addBeanTypes().addRootType())
72  			.parser(HtmlParser.create())
73  			.validateXmlWhitespace()
74  			.build(),
75  		tester(8, "Html - with key/value headers")
76  			.serializer(HtmlSerializer.create().addKeyValueTableHeaders().addBeanTypes().addRootType())
77  			.parser(HtmlParser.create())
78  			.validateXmlWhitespace()
79  			.build(),
80  		tester(9, "Uon - default")
81  			.serializer(UonSerializer.create().keepNullProperties().addBeanTypes().addRootType())
82  			.parser(UonParser.create())
83  			.build(),
84  		tester(10, "Uon - readable")
85  			.serializer(UonSerializer.create().ws().keepNullProperties().addBeanTypes().addRootType())
86  			.parser(UonParser.create())
87  			.build(),
88  		tester(11, "Uon - encoded")
89  			.serializer(UonSerializer.create().encoding().keepNullProperties().addBeanTypes().addRootType())
90  			.parser(UonParser.create().decoding())
91  			.build(),
92  		tester(12, "UrlEncoding - default")
93  			.serializer(UrlEncodingSerializer.create().keepNullProperties().addBeanTypes().addRootType())
94  			.parser(UrlEncodingParser.create())
95  			.build(),
96  		tester(13, "UrlEncoding - readable")
97  			.serializer(UrlEncodingSerializer.create().ws().keepNullProperties().addBeanTypes().addRootType())
98  			.parser(UrlEncodingParser.create())
99  			.build(),
100 		tester(14, "UrlEncoding - expanded params")
101 			.serializer(UrlEncodingSerializer.create().expandedParams().addBeanTypes().addRootType())
102 			.parser(UrlEncodingParser.create().expandedParams())
103 			.build(),
104 		tester(15, "MsgPack")
105 			.serializer(MsgPackSerializer.create().keepNullProperties().addBeanTypes().addRootType())
106 			.parser(MsgPackParser.create())
107 			.build(),
108 		tester(16, "Json schema")
109 			.serializer(JsonSchemaSerializer.create().keepNullProperties().addBeanTypes().addRootType())
110 			.returnOriginalObject()
111 			.build(),
112 	};
113 
114 	static RoundTrip_Tester[] testers() {
115 		return TESTERS;
116 	}
117 
118 	protected static RoundTrip_Tester.Builder tester(int index, String label) {
119 		return RoundTrip_Tester.create(index, label).annotatedClasses(AcConfig.class);
120 	}
121 
122 	//====================================================================================================
123 	// simple
124 	//====================================================================================================
125 
126 	@ParameterizedTest
127 	@MethodSource("testers")
128 	void a01_simple(RoundTrip_Tester t) throws Exception {
129 		var x = A.builder().f1(1).build();
130 		x = t.roundTrip(x, A.class);
131 		assertBean(x, "f1", "1");
132 	}
133 
134 	public static class A {
135 		private final int f1;
136 
137 		public A(Builder b) {
138 			this.f1 = b.f1;
139 		}
140 
141 		public static Builder builder() {
142 			return new Builder();
143 		}
144 
145 		@Bean(findFluentSetters=true)
146 		public static class Builder {
147 
148 			private int f1;
149 			public Builder f1(int v) { f1 = v; return this; }
150 
151 			public A build() {
152 				return new A(this);
153 			}
154 		}
155 
156 		public int getF1() { return f1; }
157 	}
158 
159 	@ParameterizedTest
160 	@MethodSource("testers")
161 	void a02_simple_usingConfig(RoundTrip_Tester t) throws Exception {
162 		var x = Ac.builder().f1(1).build();
163 		x = t.roundTrip(x, Ac.class);
164 		assertBean(x, "f1", "1");
165 	}
166 
167 	@Bean(on="Dummy1", findFluentSetters=true)
168 	@Bean(on="Builder", findFluentSetters=true)
169 	@Bean(on="Dummy2", findFluentSetters=true)
170 	private static class AcConfig {}
171 
172 	public static class Ac {
173 		private final int f1;
174 
175 		public Ac(Builder b) {
176 			this.f1 = b.f1;
177 		}
178 
179 		public static Builder builder() {
180 			return new Builder();
181 		}
182 
183 		public static class Builder {
184 
185 			private int f1;
186 			public Builder f1(int v) { f1 = v; return this; }
187 
188 			public Ac build() {
189 				return new Ac(this);
190 			}
191 		}
192 
193 		public int getF1() { return f1; }
194 	}
195 
196 	//====================================================================================================
197 	// Bean property builder, simple
198 	//====================================================================================================
199 
200 	@ParameterizedTest
201 	@MethodSource("testers")
202 	void a03_beanPropertyBuilder_simple(RoundTrip_Tester t) throws Exception {
203 		var x = A2.builder().f1(A.builder().f1(1).build()).build();
204 		x = t.roundTrip(x, A2.class);
205 		assertBean(x, "f1{f1}", "{1}");
206 	}
207 
208 	public static class A2 {
209 		private final A f1;
210 
211 		public A2(Builder b) {
212 			this.f1 = b.f1;
213 		}
214 
215 		public static Builder builder() {
216 			return new Builder();
217 		}
218 
219 		@Bean(findFluentSetters=true)
220 		public static class Builder {
221 
222 			private A f1;
223 			public Builder f1(A v) { f1 = v; return this; }
224 
225 			public A2 build() {
226 				return new A2(this);
227 			}
228 		}
229 
230 		public A getF1() { return f1; }
231 	}
232 
233 	//====================================================================================================
234 	// Bean property builder, collections
235 	//====================================================================================================
236 
237 	@ParameterizedTest
238 	@MethodSource("testers")
239 	void a04_beanPropertyBuilder_collections(RoundTrip_Tester t) throws Exception {
240 		// It's simply not possible to allow for expanded parameters with a builder-based approach
241 		// since the value on the builder can only be set once.
242 		if (t.label.contains("UrlEncoding - expanded params"))
243 			return;
244 		var x = A3.builder()
245 			.f1(new A[]{A.builder().f1(1).build()})
246 			.f2(singletonList(A.builder().f1(2).build()))
247 			.f3(singletonList(singletonList(A.builder().f1(3).build())))
248 			.f4(singletonList(new A[]{A.builder().f1(4).build()}))
249 			.f5(singletonList(singletonList(new A[]{A.builder().f1(5).build()})))
250 			.f6(singletonMap("foo", A.builder().f1(6).build()))
251 			.f7(singletonMap("foo", singletonMap("bar", A.builder().f1(7).build())))
252 			.f8(singletonMap("foo", new A[]{A.builder().f1(8).build()}))
253 			.f9(singletonMap("foo", singletonList(new A[]{A.builder().f1(9).build()})))
254 			.build();
255 		x = t.roundTrip(x, A3.class);
256 		assertJson("{f1:[{f1:1}],f2:[{f1:2}],f3:[[{f1:3}]],f4:[[{f1:4}]],f5:[[[{f1:5}]]],f6:{foo:{f1:6}},f7:{foo:{bar:{f1:7}}},f8:{foo:[{f1:8}]},f9:{foo:[[{f1:9}]]}}", x);
257 	}
258 
259 	@Bean(sort=true)
260 	public static class A3 {
261 		private final A[] f1;
262 
263 		private final List<A> f2;
264 		private final List<List<A>> f3;
265 		private final List<A[]> f4;
266 		private final List<List<A[]>> f5;
267 
268 		private final Map<String,A> f6;
269 		private final Map<String,Map<String,A>> f7;
270 		private final Map<String,A[]> f8;
271 		private final Map<String,List<A[]>> f9;
272 
273 		public A3(Builder b) {
274 			this.f1 = b.f1;
275 			this.f2 = b.f2;
276 			this.f3 = b.f3;
277 			this.f4 = b.f4;
278 			this.f5 = b.f5;
279 			this.f6 = b.f6;
280 			this.f7 = b.f7;
281 			this.f8 = b.f8;
282 			this.f9 = b.f9;
283 		}
284 
285 		public static Builder builder() {
286 			return new Builder();
287 		}
288 
289 		@Bean(findFluentSetters=true)
290 		public static class Builder {
291 
292 			private A[] f1;
293 			public Builder f1(A[] v) { f1 = v; return this; }
294 
295 			private List<A> f2;
296 			public Builder f2(List<A> v) { f2 = v; return this; }
297 
298 			private List<List<A>> f3;
299 			public Builder f3(List<List<A>> v) { f3 = v; return this; }
300 
301 			private List<A[]> f4;
302 			public Builder f4(List<A[]> v) { f4 = v; return this; }
303 
304 			private List<List<A[]>> f5;
305 			public Builder f5(List<List<A[]>> v) { f5 = v; return this; }
306 
307 			private Map<String,A> f6;
308 			public Builder f6(Map<String,A> v) { f6 = v; return this; }
309 
310 			private Map<String,Map<String,A>> f7;
311 			public Builder f7(Map<String,Map<String,A>> v) { f7 = v; return this; }
312 
313 			private Map<String,A[]> f8;
314 			public Builder f8(Map<String,A[]> v) { f8 = v; return this; }
315 
316 			private Map<String,List<A[]>> f9;
317 			public Builder f9(Map<String,List<A[]>> v) { f9 = v; return this; }
318 
319 			public A3 build() {
320 				return new A3(this);
321 			}
322 		}
323 
324 		public A[] getF1() { return f1; }
325 		public List<A> getF2() { return f2; }
326 		public List<List<A>> getF3() { return f3; }
327 		public List<A[]> getF4() { return f4; }
328 		public List<List<A[]>> getF5() { return f5; }
329 		public Map<String,A> getF6() { return f6; }
330 		public Map<String,Map<String,A>> getF7() { return f7; }
331 		public Map<String,A[]> getF8() { return f8; }
332 		public Map<String,List<A[]>> getF9() { return f9; }
333 	}
334 }