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.apache.juneau.commons.utils.Utils.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import java.util.*;
24  import java.util.function.*;
25  import java.util.stream.*;
26  
27  import org.apache.juneau.*;
28  import org.apache.juneau.collections.*;
29  import org.apache.juneau.commons.reflect.*;
30  import org.apache.juneau.json.*;
31  import org.apache.juneau.marshaller.*;
32  import org.apache.juneau.svl.*;
33  import org.apache.juneau.swap.*;
34  import org.junit.jupiter.api.*;
35  
36  /**
37   * Tests the @BeanConfig annotation.
38   */
39  class BeanConfigAnnotation_Test extends TestBase {
40  
41  	private static void check(String expected, Object o) {
42  		assertEquals(expected, TO_STRING.apply(o));
43  	}
44  
45  		private static final Function<Object,String> TO_STRING = new Function<>() {
46  		@Override
47  		public String apply(Object t) {
48  			if (t == null)
49  				return null;
50  			if (t instanceof List)
51  				return ((List<?>)t)
52  					.stream()
53  					.map(TO_STRING)
54  					.collect(Collectors.joining(","));
55  			if (t instanceof Set)
56  				return ((Set<?>)t)
57  					.stream()
58  					.map(TO_STRING)
59  					.collect(Collectors.joining(","));
60  			if (isArray(t))
61  				return apply(toList(t, Object.class));
62  			if (t instanceof JsonMap)
63  				return ((JsonMap)t).toString();
64  			if (t instanceof Map)
65  				return ((Map<?,?>)t)
66  					.entrySet()
67  					.stream()
68  					.map(TO_STRING)
69  					.collect(Collectors.joining(","));
70  			if (t instanceof Map.Entry e) {
71  				return apply(e.getKey()) + "=" + apply(e.getValue());
72  			}
73  			if (t instanceof BeanFilter)
74  				return ((BeanFilter)t).getBeanClass().getNameSimple();
75  			if (t instanceof Class)
76  				return ((Class<?>)t).getSimpleName();
77  			if (t instanceof ClassInfo)
78  				return ((ClassInfo)t).getNameSimple();
79  			if (t instanceof PropertyNamer)
80  				return t.getClass().getSimpleName();
81  			if (t instanceof TimeZone)
82  				return ((TimeZone)t).getID();
83  			return t.toString();
84  		}
85  	};
86  
87  	static VarResolverSession sr = VarResolver.create().vars(XVar.class).build().createSession();
88  
89  	//-----------------------------------------------------------------------------------------------------------------
90  	// Basic tests
91  	//-----------------------------------------------------------------------------------------------------------------
92  
93  	@Bean(typeName="A1")
94  	public static class A1 {
95  		public int foo;
96  		@Override
97  		public String toString() {return Json5.of(this);}
98  	}
99  	@Bean(typeName="A2")
100 	public static class A2 {
101 		public int foo;
102 	}
103 	@Bean(typeName="A3")
104 	public static class A3 {
105 		public int foo;
106 	}
107 	public static class AB1 extends ObjectSwap<String,Integer> {
108 	}
109 	public static class AB2 extends ObjectSwap<String,Integer> {
110 	}
111 	public static class AB3 extends ObjectSwap<String,Integer> {
112 	}
113 
114 	@BeanConfig(
115 		beanClassVisibility="$X{PRIVATE}",
116 		beanConstructorVisibility="$X{PRIVATE}",
117 		dictionary={A1.class,A2.class},
118 		dictionary_replace={A1.class,A2.class,A3.class},
119 		beanFieldVisibility="$X{PRIVATE}",
120 		beanMapPutReturnsOldValue="$X{true}",
121 		beanMethodVisibility="$X{PRIVATE}",
122 		beansRequireDefaultConstructor="$X{true}",
123 		beansRequireSerializable="$X{true}",
124 		beansRequireSettersForGetters="$X{true}",
125 		disableBeansRequireSomeProperties="$X{true}",
126 		typePropertyName="$X{foo}",
127 		debug="$X{true}",
128 		disableIgnoreUnknownNullBeanProperties="$X{true}",
129 		disableIgnoreMissingSetters="$X{true}",
130 		disableInterfaceProxies="$X{true}",
131 		findFluentSetters="$X{true}",
132 		ignoreInvocationExceptionsOnGetters="$X{true}",
133 		ignoreInvocationExceptionsOnSetters="$X{true}",
134 		ignoreUnknownBeanProperties="$X{true}",
135 		locale="$X{en-US}",
136 		mediaType="$X{text/foo}",
137 		notBeanClasses={A1.class,A2.class},
138 		notBeanClasses_replace={A1.class,A2.class,A3.class},
139 		notBeanPackages={"$X{foo1}","$X{foo2}"},
140 		notBeanPackages_replace={"$X{foo1}","$X{foo2}","$X{foo3}"},
141 		swaps={AB1.class,AB2.class},
142 		swaps_replace={AB1.class,AB2.class,AB3.class},
143 		propertyNamer=PropertyNamerULC.class,
144 		sortProperties="$X{true}",
145 		timeZone="$X{z}",
146 		useEnumNames="$X{true}",
147 		useJavaBeanIntrospector="$X{true}"
148 	)
149 	static class A {}
150 	static ClassInfo a = ClassInfo.of(A.class);
151 
152 	@Test void a01_basic() {
153 		var al = AnnotationWorkList.of(sr, rstream(a.getAnnotations()));
154 		var bs = JsonSerializer.create().apply(al).build().getSession();
155 
156 		check("PRIVATE", bs.getBeanClassVisibility());
157 		check("PRIVATE", bs.getBeanConstructorVisibility());
158 		check("A1,A2,A3", bs.getBeanDictionary());
159 		check("PRIVATE", bs.getBeanFieldVisibility());
160 		check("true", bs.isBeanMapPutReturnsOldValue());
161 		check("PRIVATE", bs.getBeanMethodVisibility());
162 		check("true", bs.isBeansRequireDefaultConstructor());
163 		check("true", bs.isBeansRequireSerializable());
164 		check("true", bs.isBeansRequireSettersForGetters());
165 		check("false", bs.isBeansRequireSomeProperties());
166 		check("foo", bs.getBeanTypePropertyName());
167 		check("true", bs.isDebug());
168 		check("true", bs.isFindFluentSetters());
169 		check("true", bs.isIgnoreInvocationExceptionsOnGetters());
170 		check("true", bs.isIgnoreInvocationExceptionsOnSetters());
171 		check("false", bs.isIgnoreMissingSetters());
172 		check("true", bs.isIgnoreUnknownBeanProperties());
173 		check("false", bs.isIgnoreUnknownNullBeanProperties());
174 		check("en_US", bs.getLocale());
175 		check("text/foo", bs.getMediaType());
176 		check("A1,A2,A3,Map,Collection,Reader,Writer,InputStream,OutputStream,Throwable", bs.getNotBeanClasses());
177 		check("foo1,foo2,foo3,java.lang,java.lang.annotation,java.lang.ref,java.lang.reflect,java.io,java.net", bs.getNotBeanPackagesNames());
178 		check("AB1<String,Integer>,AB2<String,Integer>,AB3<String,Integer>", bs.getSwaps());
179 		check("PropertyNamerULC", bs.getPropertyNamer());
180 		check("true", bs.isSortProperties());
181 		check("GMT", bs.getTimeZone());
182 		check("true", bs.isUseEnumNames());
183 		check("false", bs.isUseInterfaceProxies());
184 		check("true", bs.isUseJavaBeanIntrospector());
185 	}
186 
187 	//-----------------------------------------------------------------------------------------------------------------
188 	// Annotation with no values.
189 	//-----------------------------------------------------------------------------------------------------------------
190 
191 	@BeanConfig()
192 	static class B {}
193 	static ClassInfo b = ClassInfo.of(B.class);
194 
195 	@Test void b01_noValues() {
196 		var al = AnnotationWorkList.of(sr, rstream(b.getAnnotations()));
197 		var js = JsonSerializer.create().apply(al).build();
198 		var bc = js.getBeanContext();
199 		check("PUBLIC", bc.getBeanClassVisibility());
200 		check("PUBLIC", bc.getBeanConstructorVisibility());
201 		check("", bc.getBeanDictionary());
202 		check("PUBLIC", bc.getBeanFieldVisibility());
203 		check("false", bc.isBeanMapPutReturnsOldValue());
204 		check("PUBLIC", bc.getBeanMethodVisibility());
205 		check("false", bc.isBeansRequireDefaultConstructor());
206 		check("false", bc.isBeansRequireSerializable());
207 		check("false", bc.isBeansRequireSettersForGetters());
208 		check("true", bc.isBeansRequireSomeProperties());
209 		check("_type", bc.getBeanTypePropertyName());
210 		check("false", js.isDebug());
211 		check("false", js.isDetectRecursions());
212 		check("false", bc.isFindFluentSetters());
213 		check("false", bc.isIgnoreInvocationExceptionsOnGetters());
214 		check("false", bc.isIgnoreInvocationExceptionsOnSetters());
215 		check("true", bc.isIgnoreMissingSetters());
216 		check("false", js.isIgnoreRecursions());
217 		check("false", bc.isIgnoreUnknownBeanProperties());
218 		check("true", bc.isIgnoreUnknownNullBeanProperties());
219 		check("0", js.getInitialDepth());
220 		check(Locale.getDefault().toString(), bc.getDefaultLocale());
221 		check("100", js.getMaxDepth());
222 		check(null, bc.getDefaultMediaType());
223 		check("java.lang,java.lang.annotation,java.lang.ref,java.lang.reflect,java.io,java.net", bc.getNotBeanPackagesNames());
224 		check("", bc.getSwaps());
225 		check("BasicPropertyNamer", bc.getPropertyNamer());
226 		check("false", bc.isSortProperties());
227 		check(null, bc.getDefaultTimeZone());
228 		check("false", bc.isUseEnumNames());
229 		check("true", bc.isUseInterfaceProxies());
230 		check("false", bc.isUseJavaBeanIntrospector());
231 	}
232 
233 	//-----------------------------------------------------------------------------------------------------------------
234 	// No annotation.
235 	//-----------------------------------------------------------------------------------------------------------------
236 
237 	static class C {}
238 	static ClassInfo c = ClassInfo.of(C.class);
239 
240 	@Test void c01_noAnnotation() {
241 		var al = AnnotationWorkList.of(sr, rstream(c.getAnnotations()));
242 		var js = JsonSerializer.create().apply(al).build();
243 		var bc = js.getBeanContext();
244 		check("PUBLIC", bc.getBeanClassVisibility());
245 		check("PUBLIC", bc.getBeanConstructorVisibility());
246 		check("", bc.getBeanDictionary());
247 		check("PUBLIC", bc.getBeanFieldVisibility());
248 		check("false", bc.isBeanMapPutReturnsOldValue());
249 		check("PUBLIC", bc.getBeanMethodVisibility());
250 		check("false", bc.isBeansRequireDefaultConstructor());
251 		check("false", bc.isBeansRequireSerializable());
252 		check("false", bc.isBeansRequireSettersForGetters());
253 		check("true", bc.isBeansRequireSomeProperties());
254 		check("_type", bc.getBeanTypePropertyName());
255 		check("false", js.isDebug());
256 		check("false", js.isDetectRecursions());
257 		check("false", bc.isFindFluentSetters());
258 		check("false", bc.isIgnoreInvocationExceptionsOnGetters());
259 		check("false", bc.isIgnoreInvocationExceptionsOnSetters());
260 		check("true", bc.isIgnoreMissingSetters());
261 		check("false", js.isIgnoreRecursions());
262 		check("false", bc.isIgnoreUnknownBeanProperties());
263 		check("true", bc.isIgnoreUnknownNullBeanProperties());
264 		check("0", js.getInitialDepth());
265 		check(Locale.getDefault().toString(), bc.getDefaultLocale());
266 		check("100", js.getMaxDepth());
267 		check(null, bc.getDefaultMediaType());
268 		check("java.lang,java.lang.annotation,java.lang.ref,java.lang.reflect,java.io,java.net", bc.getNotBeanPackagesNames());
269 		check("", bc.getSwaps());
270 		check("BasicPropertyNamer", bc.getPropertyNamer());
271 		check("false", bc.isSortProperties());
272 		check(null, bc.getDefaultTimeZone());
273 		check("false", bc.isUseEnumNames());
274 		check("true", bc.isUseInterfaceProxies());
275 		check("false", bc.isUseJavaBeanIntrospector());
276 	}
277 }