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