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.annotation;
18  
19  import static org.apache.juneau.commons.utils.CollectionUtils.*;
20  import static org.junit.jupiter.api.Assertions.*;
21  
22  import org.apache.juneau.*;
23  import org.apache.juneau.commons.reflect.*;
24  import org.apache.juneau.json.*;
25  import org.apache.juneau.marshaller.*;
26  import org.apache.juneau.svl.*;
27  import org.junit.jupiter.api.*;
28  
29  class Bean_Test extends TestBase {
30  
31  	static VarResolverSession vr = VarResolver.create().vars(XVar.class).build().createSession();
32  
33  	//------------------------------------------------------------------------------------------------------------------
34  	// @Bean annotation overrides visibility rules on class and constructor.
35  	//------------------------------------------------------------------------------------------------------------------
36  
37  	@Bean
38  	@SuppressWarnings("unused")
39  	private static class A1 {
40  		public int f1;
41  
42  		public static A1 create() {
43  			var a = new A1();
44  			a.f1 = 1;
45  			return a;
46  		}
47  	}
48  
49  	@Test void a01_beanAnnotationOverridesPrivate() throws Exception {
50  		var json = Json5.of(A1.create());
51  		assertEquals("{f1:1}", json);
52  		var a = Json5.DEFAULT.read(json, A1.class);
53  		json = Json5.of(a);
54  		assertEquals("{f1:1}", json);
55  	}
56  
57  	@Bean(on="Dummy1")
58  	@Bean(on="A2")
59  	@Bean(on="Dummy2")
60  	private static class A2Config {}
61  
62  	@SuppressWarnings("unused")
63  	private static class A2 {
64  		public int f1;
65  
66  		public static A2 create() {
67  			var a = new A2();
68  			a.f1 = 1;
69  			return a;
70  		}
71  	}
72  	static ClassInfo a2ci = ClassInfo.of(A2Config.class);
73  
74  	@Test void a02_beanAnnotationOverridesPrivate_usingConfig() throws Exception {
75  		var al = AnnotationWorkList.of(rstream(a2ci.getAnnotations()));
76  		var js = Json5Serializer.create().apply(al).build();
77  		var jp = JsonParser.create().apply(al).build();
78  
79  		var json = js.serialize(A2.create());
80  		assertEquals("{f1:1}", json);
81  		var a = jp.parse(json, A2.class);
82  		json = js.serialize(a);
83  		assertEquals("{f1:1}", json);
84  	}
85  
86  	//------------------------------------------------------------------------------------------------------------------
87  	// @Beanc and @Beanp annotations overrides visibility rules on constructors/properties.
88  	//------------------------------------------------------------------------------------------------------------------
89  
90  	public static class B1 {
91  
92  		@Beanp
93  		private int f1;
94  
95  		private int f2;
96  
97  		@Beanp
98  		private void setF2(int f2) {
99  			this.f2 = f2;
100 		}
101 
102 		@Beanp
103 		private int getF2() {
104 			return f2;
105 		}
106 
107 		@Beanc
108 		private B1() {}
109 
110 		public static B1 create() {
111 			var b = new B1();
112 			b.f1 = 1;
113 			b.f2 = 2;
114 			return b;
115 		}
116 	}
117 
118 	@Test void a03_beanxAnnotationOverridesPrivate() throws Exception {
119 		var json = Json5.of(B1.create());
120 		assertEquals("{f1:1,f2:2}", json);
121 		var b = Json5.DEFAULT.read(json, B1.class);
122 		json = Json5.of(b);
123 		assertEquals("{f1:1,f2:2}", json);
124 	}
125 
126 	@Beanc(on="B2()")
127 	@Beanp(on="B2.f1")
128 	@Beanp(on="B2.setF2")
129 	@Beanp(on="B2.getF2")
130 	private static class B2Config {}
131 
132 	@SuppressWarnings("unused")
133 	public static class B2 {
134 
135 		private int f1;
136 
137 		private int f2;
138 
139 		private void setF2(int f2) {
140 			this.f2 = f2;
141 		}
142 
143 		private int getF2() {
144 			return f2;
145 		}
146 
147 		private B2() {}
148 
149 		public static B2 create() {
150 			var b = new B2();
151 			b.f1 = 1;
152 			b.f2 = 2;
153 			return b;
154 		}
155 	}
156 	static ClassInfo b2ci = ClassInfo.of(B2Config.class);
157 
158 	@Test void a04_beanxAnnotationOverridesPrivate_usingConfig() throws Exception {
159 		var al = AnnotationWorkList.of(rstream(b2ci.getAnnotations()));
160 		var js = Json5Serializer.create().apply(al).build();
161 		var jp = JsonParser.create().apply(al).build();
162 
163 		var json = js.serialize(B2.create());
164 		assertEquals("{f1:1,f2:2}", json);
165 		var b = jp.parse(json, B2.class);
166 		json = js.serialize(b);
167 		assertEquals("{f1:1,f2:2}", json);
168 	}
169 
170 	//-----------------------------------------------------------------------------------------------------------------
171 	// @Bean(on=X,properties=) should override @Bean(properties=)
172 	//-----------------------------------------------------------------------------------------------------------------
173 
174 	@Bean(properties="a,b,c", excludeProperties="b")
175 	static class D1 {
176 		public int a, b, c, d;
177 
178 		public static D1 create() {
179 			var d = new D1();
180 			d.a = 1;
181 			d.b = 2;
182 			d.c = 3;
183 			d.d = 4;
184 			return d;
185 		}
186 	}
187 
188 	@Bean(p="a,b,c", xp="b")
189 	static class D2 {
190 		public int a, b, c, d;
191 
192 		public static D2 create() {
193 			var d = new D2();
194 			d.a = 1;
195 			d.b = 2;
196 			d.c = 3;
197 			d.d = 4;
198 			return d;
199 		}
200 	}
201 
202 	@Bean(on="Dummy", p="b,c,d", xp="c")
203 	@Bean(on="D1", properties="b,c,d", excludeProperties="c")
204 	@Bean(on="D2", p="b,c,d", xp="c")
205 	static class DConfig {}
206 
207 	private static ClassInfo dConfig = ClassInfo.of(DConfig.class);
208 
209 	@Test void d01_beanPropertiesExcludePropertiesCombined_noBeanConfig() throws Exception {
210 		var json = Json5.of(D1.create());
211 		assertEquals("{a:1,c:3}", json);
212 		var x = Json5.DEFAULT.read(json, D1.class);
213 		json = Json5.of(x);
214 		assertEquals("{a:1,c:3}", json);
215 	}
216 
217 	@Test void d02_beanPXpCombined_noBeanConfig() throws Exception {
218 		var json = Json5.of(D2.create());
219 		assertEquals("{a:1,c:3}", json);
220 		var x = Json5.DEFAULT.read(json, D2.class);
221 		json = Json5.of(x);
222 		assertEquals("{a:1,c:3}", json);
223 	}
224 
225 	@Test void d03_beanPropertiesExcludePropertiesCombined_beanConfigOverride() throws Exception {
226 		var al = AnnotationWorkList.of(vr, rstream(dConfig.getAnnotations()));
227 		var js = Json5Serializer.create().apply(al).build();
228 		var jp = JsonParser.create().apply(al).build();
229 
230 		var json = js.serialize(D1.create());
231 		assertEquals("{b:2,d:4}", json);
232 		var d = jp.parse(json, D1.class);
233 		json = js.serialize(d);
234 		assertEquals("{b:2,d:4}", json);
235 	}
236 
237 	@Test void d04_beanPXpCombined_beanConfigOverride() throws Exception {
238 		var al = AnnotationWorkList.of(vr, rstream(dConfig.getAnnotations()));
239 		var js = Json5Serializer.create().apply(al).build();
240 		var jp = JsonParser.create().apply(al).build();
241 
242 		var json = js.serialize(D2.create());
243 		assertEquals("{b:2,d:4}", json);
244 		var d = jp.parse(json, D2.class);
245 		json = js.serialize(d);
246 		assertEquals("{b:2,d:4}", json);
247 	}
248 
249 	@Test void d05_beanPropertiesExcludePropertiesCombined_beanContextBuilderOverride() throws Exception {
250 		var ba = BeanAnnotation.create("D1").properties("b,c,d").excludeProperties("c").build();
251 		var js = Json5Serializer.create().annotations(ba).build();
252 		var jp = JsonParser.create().annotations(ba).build();
253 
254 		var json = js.serialize(D1.create());
255 		assertEquals("{b:2,d:4}", json);
256 		var d = jp.parse(json, D1.class);
257 		json = js.serialize(d);
258 		assertEquals("{b:2,d:4}", json);
259 	}
260 
261 	@Test void d06_beanPXpCombined_beanContextBuilderOverride() throws Exception {
262 		var ba = BeanAnnotation.create("D2").p("b,c,d").xp("c").build();
263 		var js = Json5Serializer.create().annotations(ba).build();
264 		var jp = JsonParser.create().annotations(ba).build();
265 
266 		var json = js.serialize(D2.create());
267 		assertEquals("{b:2,d:4}", json);
268 		var d = jp.parse(json, D2.class);
269 		json = js.serialize(d);
270 		assertEquals("{b:2,d:4}", json);
271 	}
272 
273 	//-----------------------------------------------------------------------------------------------------------------
274 	// @BeanConfig(bpi/bpx) should override @Bean(bpi/bpx)
275 	//-----------------------------------------------------------------------------------------------------------------
276 
277 	@Bean(properties="a,b,c")
278 	static class E1a {
279 		public int a, b, c, d;
280 	}
281 
282 	@Bean(excludeProperties="b")
283 	static class E1 extends E1a {
284 
285 		public static E1 create() {
286 			var e = new E1();
287 			e.a = 1;
288 			e.b = 2;
289 			e.c = 3;
290 			e.d = 4;
291 			return e;
292 		}
293 	}
294 
295 	@Bean(p="a,b,c")
296 	static class E2a {
297 		public int a, b, c, d;
298 	}
299 
300 	@Bean(xp="b")
301 	static class E2 extends E2a {
302 
303 		public static E2 create() {
304 			var e = new E2();
305 			e.a = 1;
306 			e.b = 2;
307 			e.c = 3;
308 			e.d = 4;
309 			return e;
310 		}
311 	}
312 
313 	@Bean(on="Dummy", p="b,c,d", xp="c")
314 	@Bean(on="E1", properties="b,c,d", excludeProperties="c")
315 	@Bean(on="E2", p="b,c,d", xp="c")
316 	static class EConfig {}
317 
318 	private static ClassInfo eConfig = ClassInfo.of(EConfig.class);
319 
320 	@Test void e01_beanPropertiesExcludePropertiesCombined_multipleBeanAnnotations_noBeanConfig() throws Exception {
321 		var json = Json5.of(E1.create());
322 		assertEquals("{a:1,c:3}", json);
323 		var e = Json5.DEFAULT.read(json, E1.class);
324 		json = Json5.of(e);
325 		assertEquals("{a:1,c:3}", json);
326 	}
327 
328 	@Test void e02_beanPXpCombined_multipleBeanAnnotations_noBeanConfig() throws Exception {
329 		var json = Json5.of(E2.create());
330 		assertEquals("{a:1,c:3}", json);
331 		var e = Json5.DEFAULT.read(json, E2.class);
332 		json = Json5.of(e);
333 		assertEquals("{a:1,c:3}", json);
334 	}
335 
336 	@Test void e03_beanPropertiesExcludePropertiesCombined_multipleBeanAnnotations_beanConfigOverride() throws Exception {
337 		var al = AnnotationWorkList.of(vr, rstream(eConfig.getAnnotations()));
338 		var js = Json5Serializer.create().apply(al).build();
339 		var jp = JsonParser.create().apply(al).build();
340 
341 		var json = js.serialize(E1.create());
342 		assertEquals("{b:2,d:4}", json);
343 		var e = jp.parse(json, E1.class);
344 		json = js.serialize(e);
345 		assertEquals("{b:2,d:4}", json);
346 	}
347 
348 	@Test void e04_beanPXpCombined_multipleBeanAnnotations_beanConfigOverride() throws Exception {
349 		var al = AnnotationWorkList.of(vr, rstream(eConfig.getAnnotations()));
350 		var js = Json5Serializer.create().apply(al).build();
351 		var jp = JsonParser.create().apply(al).build();
352 
353 		var json = js.serialize(E2.create());
354 		assertEquals("{b:2,d:4}", json);
355 		var e = jp.parse(json, E2.class);
356 		json = js.serialize(e);
357 		assertEquals("{b:2,d:4}", json);
358 	}
359 
360 	@Test void e05_beanPropertiersExcludePropertiesCombined_multipleBeanAnnotations_beanContextBuilderOverride() throws Exception {
361 		var ba = BeanAnnotation.create("E1").properties("b,c,d").excludeProperties("c").build();
362 		var js = Json5Serializer.create().annotations(ba).build();
363 		var jp = JsonParser.create().annotations(ba).build();
364 
365 		var json = js.serialize(E1.create());
366 		assertEquals("{b:2,d:4}", json);
367 		var e = jp.parse(json, E1.class);
368 		json = js.serialize(e);
369 		assertEquals("{b:2,d:4}", json);
370 	}
371 
372 	@Test void e06_beanBpiBpxCombined_multipleBeanAnnotations_beanContextBuilderOverride() throws Exception {
373 		var ba = BeanAnnotation.create("E2").p("b,c,d").xp("c").build();
374 		var js = Json5Serializer.create().annotations(ba).build();
375 		var jp = JsonParser.create().annotations(ba).build();
376 
377 		var json = js.serialize(E2.create());
378 		assertEquals("{b:2,d:4}", json);
379 		var e = jp.parse(json, E2.class);
380 		json = js.serialize(e);
381 		assertEquals("{b:2,d:4}", json);
382 	}
383 }