001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau; 014 015import static org.apache.juneau.Visibility.*; 016import static org.apache.juneau.internal.ClassUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018import static org.apache.juneau.internal.StringUtils.*; 019 020import java.io.*; 021import java.lang.annotation.*; 022import java.lang.reflect.*; 023import java.util.*; 024import java.util.concurrent.*; 025 026import org.apache.juneau.annotation.*; 027import org.apache.juneau.collections.*; 028import org.apache.juneau.json.*; 029import org.apache.juneau.reflect.*; 030import org.apache.juneau.serializer.*; 031import org.apache.juneau.transform.*; 032import org.apache.juneau.utils.*; 033 034/** 035 * Core class of the Juneau architecture. 036 * 037 * <p> 038 * This class servers multiple purposes: 039 * <ul class='spaced-list'> 040 * <li> 041 * Provides the ability to wrap beans inside {@link Map} interfaces. 042 * <li> 043 * Serves as a repository for metadata on POJOs, such as associated {@link BeanFilter BeanFilters}, 044 * {@link PropertyNamer PropertyNamers}, etc... which are used to tailor how POJOs are serialized and parsed. 045 * </ul> 046 * 047 * <p> 048 * All serializers and parsers extend from this context so that they can handle POJOs using a common framework. 049 * 050 * <h5 class='topic'>Bean Contexts</h5> 051 * 052 * Bean contexts are created through the {@link BeanContext#create() BeanContext.create()} and {@link BeanContextBuilder#build()} methods. 053 * <br>These context objects are read-only, reusable, and thread-safe. 054 * 055 * <p> 056 * Each bean context maintains a cache of {@link ClassMeta} objects that describe information about classes encountered. 057 * These <c>ClassMeta</c> objects are time-consuming to construct. 058 * Therefore, instances of {@link BeanContext} that share the same <js>"BeanContext.*"</js> property values share 059 * the same cache. This allows for efficient reuse of <c>ClassMeta</c> objects so that the information about 060 * classes only needs to be calculated once. 061 * Because of this, many of the properties defined on the {@link BeanContext} class cannot be overridden on the session. 062 * 063 * <h5 class='topic'>Bean Sessions</h5> 064 * 065 * Whereas <c>BeanContext</c> objects are permanent, unchangeable, cached, and thread-safe, 066 * {@link BeanSession} objects are ephemeral and not thread-safe. 067 * They are meant to be used as quickly-constructed scratchpads for creating bean maps. 068 * {@link BeanMap} objects can only be created through the session. 069 * 070 * <h5 class='topic'>BeanContext configuration properties</h5> 071 * 072 * <c>BeanContexts</c> have several configuration properties that can be used to tweak behavior on how beans are 073 * handled. These are denoted as the static <jsf>BEAN_*</jsf> fields on this class. 074 * 075 * <p> 076 * Some settings (e.g. {@link #BEAN_beansRequireDefaultConstructor}) are used to differentiate between bean 077 * and non-bean classes. 078 * Attempting to create a bean map around one of these objects will throw a {@link BeanRuntimeException}. 079 * The purpose for this behavior is so that the serializers can identify these non-bean classes and convert them to 080 * plain strings using the {@link Object#toString()} method. 081 * 082 * <p> 083 * Some settings (e.g. {@link #BEAN_beanFieldVisibility}) are used to determine what kinds of properties are 084 * detected on beans. 085 * 086 * <p> 087 * Some settings (e.g. {@link #BEAN_beanMapPutReturnsOldValue}) change the runtime behavior of bean maps. 088 * 089 * <p> 090 * Settings are specified using the {@link BeanContextBuilder#set(String, Object)} method and related convenience 091 * methods. 092 * 093 * <h5 class='section'>Example:</h5> 094 * 095 * <p class='bcode w800'> 096 * <jc>// Construct a context from scratch.</jc> 097 * BeanContext beanContext = BeanContext 098 * .<jsm>create</jsm>() 099 * .set(BeanContext.<jsf>BEAN_beansRequireDefaultConstructor</jsf>, <jk>true</jk>) 100 * .notBeanClasses(Foo.<jk>class</jk>) 101 * .build(); 102 * </p> 103 * 104 * <h5 class='topic'>Bean Maps</h5> 105 * 106 * {@link BeanMap BeanMaps} are wrappers around Java beans that allow properties to be retrieved and 107 * set using the common {@link Map#put(Object,Object)} and {@link Map#get(Object)} methods. 108 * 109 * <p> 110 * Bean maps are created in two ways... 111 * <ol> 112 * <li>{@link BeanSession#toBeanMap(Object) BeanSession.toBeanMap()} - Wraps an existing bean inside a {@code Map} 113 * wrapper. 114 * <li>{@link BeanSession#newBeanMap(Class) BeanSession.newBeanMap()} - Create a new bean instance wrapped in a 115 * {@code Map} wrapper. 116 * </ol> 117 * 118 * <h5 class='section'>Example:</h5> 119 * 120 * <p class='bcode w800'> 121 * <jc>// A sample bean class</jc> 122 * <jk>public class</jk> Person { 123 * <jk>public</jk> String getName(); 124 * <jk>public void</jk> setName(String name); 125 * <jk>public int</jk> getAge(); 126 * <jk>public void</jk> setAge(<jk>int</jk> age); 127 * } 128 * 129 * <jc>// Create a new bean session</jc> 130 * BeanSession session = BeanContext.<jsf>DEFAULT</jsf>.createSession(); 131 * 132 * <jc>// Wrap an existing bean in a new bean map</jc> 133 * BeanMap<Person> m1 = session.toBeanMap(<jk>new</jk> Person()); 134 * m1.put(<js>"name"</js>, <js>"John Smith"</js>); 135 * m1.put(<js>"age"</js>, 45); 136 * 137 * <jc>// Create a new bean instance wrapped in a new bean map</jc> 138 * BeanMap<Person> m2 = session.newBeanMap(Person.<jk>class</jk>); 139 * m2.put(<js>"name"</js>, <js>"John Smith"</js>); 140 * m2.put(<js>"age"</js>, 45); 141 * Person p = m2.getBean(); <jc>// Get the bean instance that was created.</jc> 142 * </p> 143 * 144 * <ul class='seealso'> 145 * <li class='link'>{@doc ContextsBuildersSessionsPropertyStores} 146 * </ul> 147 */ 148@SuppressWarnings({"unchecked","rawtypes"}) 149@ConfigurableContext 150public class BeanContext extends Context implements MetaProvider { 151 152 static final String PREFIX = "BeanContext"; 153 154 /** 155 * Configuration property: Annotations. 156 * 157 * <h5 class='section'>Property:</h5> 158 * <ul class='spaced-list'> 159 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_annotations BEAN_annotations} 160 * <li><b>Name:</b> <js>"BeanContext.annotations.lo"</js> 161 * <li><b>Data type:</b> <c>List<{@link java.lang.annotation.Annotation}></c> 162 * <li><b>Default:</b> Empty list. 163 * <li><b>Annotations:</b> 164 * <ul> 165 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#applyBean()} 166 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#applyBeanp()} 167 * </ul> 168 * <li><b>Methods:</b> 169 * <ul> 170 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#annotations(Annotation...)} 171 * </ul> 172 * </ul> 173 * 174 * <h5 class='section'>Description:</h5> 175 * 176 * <p> 177 * Defines annotations to apply to specific classes and methods. 178 * 179 * <p> 180 * Allows you to dynamically apply Juneau annotations typically applied directly to classes and methods. 181 * Useful in cases where you want to use the functionality of the annotation on beans and bean properties but 182 * do not have access to the code to do so. 183 * 184 * <p> 185 * As a rule, any Juneau annotation with an <c>on()</c> method can be used with this property. 186 * 187 * <p> 188 * The following example shows the equivalent methods for applying the {@link Bean @Bean} annotation: 189 * <p class='bcode w800'> 190 * <jc>// Class with explicit annotation.</jc> 191 * <ja>@Bean</ja>(bpi=<js>"street,city,state"</js>) 192 * <jk>public class</jk> A {...} 193 * 194 * <jc>// Class with annotation applied via @BeanConfig</jc> 195 * <jk>public class</jk> B {...} 196 * 197 * <jc>// Java REST method with @BeanConfig annotation.</jc> 198 * <ja>@RestMethod</ja>(...) 199 * <ja>@BeanConfig</ja>( 200 * annotations={ 201 * <ja>@Bean</ja>(on=<js>"B"</js>, bpi=<js>"street,city,state"</js>) 202 * } 203 * ) 204 * <jk>public void</jk> doFoo() {...} 205 * </p> 206 * 207 * <p> 208 * In general, the underlying framework uses this method when it finds dynamically applied annotations on 209 * config annotations. However, concrete implementations of annotations are also provided that can be passed 210 * directly into builder classes like so: 211 * <p class='bcode w800'> 212 * <jc>// Create a concrete @Bean annotation.</jc> 213 * BeanAnnotation a = <jk>new</jk> BeanAnnotation(<js>"B"</js>).bpi(<js>"street,city,state"</js>); 214 * 215 * <jc>// Apply it to a serializer.</jc> 216 * WriterSerializer ws = JsonSerializer.<jsm>create</jsm>().annotations(a).build(); 217 * 218 * <jc>// Serialize a bean with the dynamically applied annotation.</jc> 219 * String json = ws.serialize(<jk>new</jk> B()); 220 * </p> 221 * 222 * <p> 223 * The following is the list of concrete annotations provided that can be constructed and passed into the builder 224 * class: 225 * <ul class='javatree'> 226 * <li class='ja'>{@link org.apache.juneau.annotation.BeanAnnotation} 227 * <li class='ja'>{@link org.apache.juneau.annotation.BeancAnnotation} 228 * <li class='ja'>{@link org.apache.juneau.annotation.BeanIgnoreAnnotation} 229 * <li class='ja'>{@link org.apache.juneau.annotation.BeanpAnnotation} 230 * <li class='ja'>{@link org.apache.juneau.annotation.ExampleAnnotation} 231 * <li class='ja'>{@link org.apache.juneau.annotation.NamePropertyAnnotation} 232 * <li class='ja'>{@link org.apache.juneau.annotation.ParentPropertyAnnotation} 233 * <li class='ja'>{@link org.apache.juneau.annotation.SwapAnnotation} 234 * <li class='ja'>{@link org.apache.juneau.annotation.UriAnnotation} 235 * <li class='ja'>{@link org.apache.juneau.csv.annotation.CsvAnnotation} 236 * <li class='ja'>{@link org.apache.juneau.html.annotation.HtmlAnnotation} 237 * <li class='ja'>{@link org.apache.juneau.jso.annotation.JsoAnnotation} 238 * <li class='ja'>{@link org.apache.juneau.json.annotation.JsonAnnotation} 239 * <li class='ja'>{@link org.apache.juneau.jsonschema.annotation.SchemaAnnotation} 240 * <li class='ja'>{@link org.apache.juneau.msgpack.annotation.MsgPackAnnotation} 241 * <li class='ja'>{@link org.apache.juneau.oapi.annotation.OpenApiAnnotation} 242 * <li class='ja'>{@link org.apache.juneau.plaintext.annotation.PlainTextAnnotation} 243 * <li class='ja'>{@link org.apache.juneau.soap.annotation.SoapXmlAnnotation} 244 * <li class='ja'>{@link org.apache.juneau.uon.annotation.UonAnnotation} 245 * <li class='ja'>{@link org.apache.juneau.urlencoding.annotation.UrlEncodingAnnotation} 246 * <li class='ja'>{@link org.apache.juneau.xml.annotation.XmlAnnotation} 247 * </ul> 248 * 249 * <p> 250 * The syntax for the <l>on()</l> pattern match parameter depends on whether it applies to a class, method, field, or constructor. 251 * The valid pattern matches are: 252 * <ul class='spaced-list'> 253 * <li>Classes: 254 * <ul> 255 * <li>Fully qualified: 256 * <ul> 257 * <li><js>"com.foo.MyClass"</js> 258 * </ul> 259 * <li>Fully qualified inner class: 260 * <ul> 261 * <li><js>"com.foo.MyClass$Inner1$Inner2"</js> 262 * </ul> 263 * <li>Simple: 264 * <ul> 265 * <li><js>"MyClass"</js> 266 * </ul> 267 * <li>Simple inner: 268 * <ul> 269 * <li><js>"MyClass$Inner1$Inner2"</js> 270 * <li><js>"Inner1$Inner2"</js> 271 * <li><js>"Inner2"</js> 272 * </ul> 273 * </ul> 274 * <li>Methods: 275 * <ul> 276 * <li>Fully qualified with args: 277 * <ul> 278 * <li><js>"com.foo.MyClass.myMethod(String,int)"</js> 279 * <li><js>"com.foo.MyClass.myMethod(java.lang.String,int)"</js> 280 * <li><js>"com.foo.MyClass.myMethod()"</js> 281 * </ul> 282 * <li>Fully qualified: 283 * <ul> 284 * <li><js>"com.foo.MyClass.myMethod"</js> 285 * </ul> 286 * <li>Simple with args: 287 * <ul> 288 * <li><js>"MyClass.myMethod(String,int)"</js> 289 * <li><js>"MyClass.myMethod(java.lang.String,int)"</js> 290 * <li><js>"MyClass.myMethod()"</js> 291 * </ul> 292 * <li>Simple: 293 * <ul> 294 * <li><js>"MyClass.myMethod"</js> 295 * </ul> 296 * <li>Simple inner class: 297 * <ul> 298 * <li><js>"MyClass$Inner1$Inner2.myMethod"</js> 299 * <li><js>"Inner1$Inner2.myMethod"</js> 300 * <li><js>"Inner2.myMethod"</js> 301 * </ul> 302 * </ul> 303 * <li>Fields: 304 * <ul> 305 * <li>Fully qualified: 306 * <ul> 307 * <li><js>"com.foo.MyClass.myField"</js> 308 * </ul> 309 * <li>Simple: 310 * <ul> 311 * <li><js>"MyClass.myField"</js> 312 * </ul> 313 * <li>Simple inner class: 314 * <ul> 315 * <li><js>"MyClass$Inner1$Inner2.myField"</js> 316 * <li><js>"Inner1$Inner2.myField"</js> 317 * <li><js>"Inner2.myField"</js> 318 * </ul> 319 * </ul> 320 * <li>Constructors: 321 * <ul> 322 * <li>Fully qualified with args: 323 * <ul> 324 * <li><js>"com.foo.MyClass(String,int)"</js> 325 * <li><js>"com.foo.MyClass(java.lang.String,int)"</js> 326 * <li><js>"com.foo.MyClass()"</js> 327 * </ul> 328 * <li>Simple with args: 329 * <ul> 330 * <li><js>"MyClass(String,int)"</js> 331 * <li><js>"MyClass(java.lang.String,int)"</js> 332 * <li><js>"MyClass()"</js> 333 * </ul> 334 * <li>Simple inner class: 335 * <ul> 336 * <li><js>"MyClass$Inner1$Inner2()"</js> 337 * <li><js>"Inner1$Inner2()"</js> 338 * <li><js>"Inner2()"</js> 339 * </ul> 340 * </ul> 341 * <li>A comma-delimited list of anything on this list. 342 * </ul> 343 */ 344 public static final String BEAN_annotations = PREFIX + ".annotations.lo"; 345 346 /** 347 * Configuration property: Minimum bean class visibility. 348 * 349 * <h5 class='section'>Property:</h5> 350 * <ul class='spaced-list'> 351 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beanClassVisibility BEAN_beanClassVisibility} 352 * <li><b>Name:</b> <js>"BeanContext.beanClassVisibility.s"</js> 353 * <li><b>Data type:</b> {@link org.apache.juneau.Visibility} 354 * <li><b>System property:</b> <c>BeanContext.beanClassVisibility</c> 355 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANCLASSVISIBILITY</c> 356 * <li><b>Default:</b> {@link org.apache.juneau.Visibility#PUBLIC} 357 * <li><b>Session property:</b> <jk>false</jk> 358 * <li><b>Annotations:</b> 359 * <ul> 360 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanClassVisibility()} 361 * </ul> 362 * <li><b>Methods:</b> 363 * <ul> 364 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanClassVisibility(Visibility)} 365 * </ul> 366 * </ul> 367 * 368 * <h5 class='section'>Description:</h5> 369 * 370 * <p> 371 * Classes are not considered beans unless they meet the minimum visibility requirements. 372 * For example, if the visibility is <jsf>PUBLIC</jsf> and the bean class is <jk>protected</jk>, then the class 373 * will not be interpreted as a bean class and be serialized as a string. 374 * Use this setting to reduce the visibility requirement. 375 * 376 * <h5 class='section'>Example:</h5> 377 * <p class='bcode w800'> 378 * <jc>// A bean with a protected class and one field.</jc> 379 * <jk>protected class</jk> MyBean { 380 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 381 * } 382 * 383 * <jc>// Create a serializer that's capable of serializing the class.</jc> 384 * WriterSerializer s = JsonSerializer 385 * .<jsm>create</jsm>() 386 * .beanClassVisibility(<jsf>PROTECTED</jsf>) 387 * .build(); 388 * 389 * <jc>// Same, but use property.</jc> 390 * WriterSerializer s = JsonSerializer 391 * .<jsm>create</jsm>() 392 * .set(<jsf>BEAN_beanClassVisibility</jsf>, <js>"PROTECTED"</js>) 393 * .build(); 394 * 395 * <jc>// Produces: {"foo","bar"}</jc> 396 * String json = w.serialize(<jk>new</jk> MyBean()); 397 * </p> 398 * 399 * <ul class='notes'> 400 * <li>The {@link Bean @Bean} annotation can be used on a non-public bean class to override this setting. 401 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean class to ignore it as a bean. 402 * </ul> 403 */ 404 public static final String BEAN_beanClassVisibility = PREFIX + ".beanClassVisibility.s"; 405 406 /** 407 * Configuration property: Minimum bean constructor visibility. 408 * 409 * <h5 class='section'>Property:</h5> 410 * <ul class='spaced-list'> 411 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beanConstructorVisibility BEAN_beanConstructorVisibility} 412 * <li><b>Name:</b> <js>"BeanContext.beanConstructorVisibility.s"</js> 413 * <li><b>Data type:</b> {@link org.apache.juneau.Visibility} 414 * <li><b>System property:</b> <c>BeanContext.beanConstructorVisibility</c> 415 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANCONSTRUCTORVISIBILITY</c> 416 * <li><b>Default:</b> {@link org.apache.juneau.Visibility#PUBLIC} 417 * <li><b>Session property:</b> <jk>false</jk> 418 * <li><b>Annotations:</b> 419 * <ul> 420 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanConstructorVisibility()} 421 * </ul> 422 * <li><b>Methods:</b> 423 * <ul> 424 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanConstructorVisibility(Visibility)} 425 * </ul> 426 * </ul> 427 * 428 * <h5 class='section'>Description:</h5> 429 * 430 * <p> 431 * Only look for constructors with the specified minimum visibility. 432 * 433 * <p> 434 * This setting affects the logic for finding no-arg constructors for bean. Normally, only <jk>public</jk> no-arg 435 * constructors are used. Use this setting if you want to reduce the visibility requirement. 436 * 437 * <h5 class='section'>Example:</h5> 438 * <p class='bcode w800'> 439 * <jc>// A bean with a protected constructor and one field.</jc> 440 * <jk>public class</jk> MyBean { 441 * <jk>public</jk> String <jf>foo</jf>; 442 * 443 * <jk>protected</jk> MyBean() {} 444 * } 445 * 446 * <jc>// Create a parser capable of calling the protected constructor.</jc> 447 * ReaderParser p = ReaderParser 448 * .<jsm>create</jsm>() 449 * .beanConstructorVisibility(<jsf>PROTECTED</jsf>) 450 * .build(); 451 * 452 * <jc>// Same, but use property.</jc> 453 * ReaderParser p = JsonParser 454 * .<jsm>create</jsm>() 455 * .set(<jsf>BEAN_beanConstructorVisibility</jsf>, <js>"PROTECTED"</js>) 456 * .build(); 457 * 458 * <jc>// Use it.</jc> 459 * MyBean c = r.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>); 460 * </p> 461 * 462 * <ul class='notes'> 463 * <li>The {@link Beanc @Beanc} annotation can also be used to expose a non-public constructor. 464 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean constructor to ignore it. 465 * </ul> 466 */ 467 public static final String BEAN_beanConstructorVisibility = PREFIX + ".beanConstructorVisibility.s"; 468 469 /** 470 * Configuration property: Bean dictionary. 471 * 472 * <h5 class='section'>Property:</h5> 473 * <ul class='spaced-list'> 474 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beanDictionary BEAN_beanDictionary} 475 * <li><b>Name:</b> <js>"BeanContext.beanDictionary.lc"</js> 476 * <li><b>Data type:</b> <c>List<Class></c> 477 * <li><b>Default:</b> empty list 478 * <li><b>Session property:</b> <jk>false</jk> 479 * <li><b>Annotations:</b> 480 * <ul> 481 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#dictionary()} 482 * <li class='ja'>{@link org.apache.juneau.annotation.Beanp#dictionary()} 483 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#dictionary()} 484 * </ul> 485 * <li><b>Methods:</b> 486 * <ul> 487 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#dictionary(Object...)} 488 * <li class='jm'>{@link org.apache.juneau.transform.BeanFilterBuilder#dictionary(Class...)} 489 * </ul> 490 * </ul> 491 * 492 * <h5 class='section'>Description:</h5> 493 * 494 * <p> 495 * The list of classes that make up the bean dictionary in this bean context. 496 * 497 * <p> 498 * A dictionary is a name/class mapping used to find class types during parsing when they cannot be inferred 499 * through reflection. The names are defined through the {@link Bean#typeName() @Bean(typeName)} annotation defined 500 * on the bean class. For example, if a class <c>Foo</c> has a type-name of <js>"myfoo"</js>, then it would end up 501 * serialized as <js>"{_type:'myfoo',...}"</js> in JSON (depending on <l>addBeanTypes</l>/<l>addRootType</l> properties) 502 * or <js>"<myfoo>...</myfoo>"</js> in XML. 503 * 504 * <p> 505 * This setting tells the parsers which classes to look for when resolving <js>"_type"</js> attributes. 506 * 507 * <p> 508 * Values can consist of any of the following types: 509 * <ul> 510 * <li>Any bean class that specifies a value for {@link Bean#typeName() @Bean(typeName)}. 511 * <li>Any subclass of {@link BeanDictionaryList} containing a collection of bean classes with type name annotations. 512 * <li>Any subclass of {@link BeanDictionaryMap} containing a mapping of type names to classes without type name annotations. 513 * <li>Any array or collection of the objects above. 514 * </ul> 515 * 516 * <h5 class='section'>Example:</h5> 517 * <p class='bcode w800'> 518 * <jc>// POJOs with @Bean(name) annotations.</jc> 519 * <ja>@Bean</ja>(typeName=<js>"foo"</js>) 520 * <jk>public class</jk> Foo {...} 521 * <ja>@Bean</ja>(typeName=<js>"bar"</js>) 522 * <jk>public class</jk> Bar {...} 523 * 524 * <jc>// Create a parser and tell it which classes to try to resolve.</jc> 525 * ReaderParser p = JsonParser 526 * .<jsm>create</jsm>() 527 * .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>) 528 * .build(); 529 * 530 * <jc>// Same, but use property.</jc> 531 * ReaderParser p = JsonParser 532 * .<jsm>create</jsm>() 533 * .addTo(<jsf>BEAN_beanDictionary</jsf>, Foo.<jk>class</jk>) 534 * .addTo(<jsf>BEAN_beanDictionary</jsf>, Bar.<jk>class</jk>) 535 * .build(); 536 * 537 * <jc>// A bean with a field with an indeterminate type.</jc> 538 * <jk>public class</jk> MyBean { 539 * <jk>public</jk> Object <jf>mySimpleField</jf>; 540 * } 541 * 542 * <jc>// Parse bean.</jc> 543 * MyBean b = p.parse(<js>"{mySimpleField:{_type:'foo',...}}"</js>, MyBean.<jk>class</jk>); 544 * </p> 545 * 546 * <p> 547 * Another option is to use the {@link Bean#dictionary()} annotation on the POJO class itself: 548 * 549 * <p class='bcode w800'> 550 * <jc>// Instead of by parser, define a bean dictionary on a class through an annotation.</jc> 551 * <jc>// This applies to all properties on this class and all subclasses.</jc> 552 * <ja>@Bean</ja>(dictionary={Foo.<jk>class</jk>,Bar.<jk>class</jk>}) 553 * <jk>public class</jk> MyBean { 554 * <jk>public</jk> Object <jf>mySimpleField</jf>; <jc>// May contain Foo or Bar object.</jc> 555 * <jk>public</jk> Map<String,Object> <jf>myMapField</jf>; <jc>// May contain Foo or Bar objects.</jc> 556 * } 557 * </p> 558 * 559 * <p> 560 * A typical usage is to allow for HTML documents to be parsed back into HTML beans: 561 * <p class='bcode w800'> 562 * <jc>// Use the predefined HTML5 bean dictionary which is a BeanDictionaryList.</jc> 563 * ReaderParser p = HtmlParser 564 * .<jsm>create</jsm>() 565 * .dictionary(HtmlBeanDictionary.<jk>class</jk>) 566 * .build(); 567 * 568 * <jc>// Parse an HTML body into HTML beans.</jc> 569 * Body body = p.parse(<js>"<body><ul><li>foo</li><li>bar</li></ul>"</js>, Body.<jk>class</jk>); 570 * </p> 571 * 572 * <ul class='seealso'> 573 * <li class='link'>{@doc BeanDictionaries} 574 * </ul> 575 */ 576 public static final String BEAN_beanDictionary = PREFIX + ".beanDictionary.lc"; 577 578 /** 579 * Configuration property: Add to bean dictionary. 580 */ 581 public static final String BEAN_beanDictionary_add = PREFIX + ".beanDictionary.lc/add"; 582 583 /** 584 * Configuration property: Remove from bean dictionary. 585 */ 586 public static final String BEAN_beanDictionary_remove = PREFIX + ".beanDictionary.lc/remove"; 587 588 /** 589 * Configuration property: Minimum bean field visibility. 590 * 591 * <h5 class='section'>Property:</h5> 592 * <ul class='spaced-list'> 593 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beanFieldVisibility BEAN_beanFieldVisibility} 594 * <li><b>Name:</b> <js>"BeanContext.beanFieldVisibility.s"</js> 595 * <li><b>Data type:</b> {@link org.apache.juneau.Visibility} 596 * <li><b>System property:</b> <c>BeanContext.beanFieldVisibility</c> 597 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANFIELDVISIBILITY</c> 598 * <li><b>Default:</b> {@link org.apache.juneau.Visibility#PUBLIC} 599 * <li><b>Session property:</b> <jk>false</jk> 600 * <li><b>Annotations:</b> 601 * <ul> 602 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanFieldVisibility()} 603 * </ul> 604 * <li><b>Methods:</b> 605 * <ul> 606 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanFieldVisibility(Visibility)} 607 * </ul> 608 * </ul> 609 * 610 * <h5 class='section'>Description:</h5> 611 * 612 * <p> 613 * Only look for bean fields with the specified minimum visibility. 614 * 615 * <p> 616 * This affects which fields on a bean class are considered bean properties. Normally only <jk>public</jk> fields are considered. 617 * Use this setting if you want to reduce the visibility requirement. 618 * 619 * <h5 class='section'>Example:</h5> 620 * <p class='bcode w800'> 621 * <jc>// A bean with a protected field.</jc> 622 * <jk>public class</jk> MyBean { 623 * <jk>protected</jk> String <jf>foo</jf> = <js>"bar"</js>; 624 * } 625 * 626 * <jc>// Create a serializer that recognizes the protected field.</jc> 627 * WriterSerializer s = JsonSerializer 628 * .<jsm>create</jsm>() 629 * .beanFieldVisibility(<jsf>PROTECTED</jsf>) 630 * .build(); 631 * 632 * <jc>// Same, but use property.</jc> 633 * WriterSerializer s = JsonSerializer 634 * .<jsm>create</jsm>() 635 * .set(<jsf>BEAN_beanFieldVisibility</jsf>, <js>"PROTECTED"</js>) 636 * .build(); 637 * 638 * <jc>// Produces: {"foo":"bar"}</jc> 639 * String json = s.serialize(<jk>new</jk> MyBean()); 640 * </p> 641 * 642 * <p> 643 * Bean fields can be ignored as properties entirely by setting the value to {@link Visibility#NONE} 644 * 645 * <p class='bcode w800'> 646 * <jc>// Disable using fields as properties entirely.</jc> 647 * WriterSerializer s = JsonSerializer 648 * .<jsm>create</jsm>() 649 * .beanFieldVisibility(<jsf>NONE</jsf>) 650 * .build(); 651 * </p> 652 * 653 * <ul class='notes'> 654 * <li>The {@link Beanp @Beanp} annotation can also be used to expose a non-public field. 655 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean field to ignore it as a bean property. 656 * </ul> 657 */ 658 public static final String BEAN_beanFieldVisibility = PREFIX + ".beanFieldVisibility.s"; 659 660 /** 661 * Configuration property: Bean filters. 662 * 663 * <div class='warn'> 664 * <b>Deprecated</b> - Use {@link BeanConfig#interfaces()} and other methods. 665 * </div> 666 */ 667 @Deprecated 668 public static final String BEAN_beanFilters = PREFIX + ".beanFilters.lo"; 669 670 /** 671 * Configuration property: Add to bean filters. 672 * 673 * <div class='warn'> 674 * <b>Deprecated</b> - Use {@link BeanConfig#interfaces()} and other methods. 675 * </div> 676 */ 677 @Deprecated 678 public static final String BEAN_beanFilters_add = PREFIX + ".beanFilters.lo/add"; 679 680 /** 681 * Configuration property: Remove from bean filters. 682 * 683 * <div class='warn'> 684 * <b>Deprecated</b> - Use {@link BeanConfig#interfaces()} and other methods. 685 * </div> 686 */ 687 @Deprecated 688 public static final String BEAN_beanFilters_remove = PREFIX + ".beanFilters.lo/remove"; 689 690 /** 691 * Configuration property: BeanMap.put() returns old property value. 692 * 693 * <h5 class='section'>Property:</h5> 694 * <ul class='spaced-list'> 695 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beanMapPutReturnsOldValue BEAN_beanMapPutReturnsOldValue} 696 * <li><b>Name:</b> <js>"BeanContext.beanMapPutReturnsOldValue.b"</js> 697 * <li><b>Data type:</b> <jk>boolean</jk> 698 * <li><b>System property:</b> <c>BeanContext.beanMapPutReturnsOldValue</c> 699 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANMAPPUTRETURNSOLDVALUE</c> 700 * <li><b>Default:</b> <jk>false</jk> 701 * <li><b>Session property:</b> <jk>false</jk> 702 * <li><b>Annotations:</b> 703 * <ul> 704 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanMapPutReturnsOldValue()} 705 * </ul> 706 * <li><b>Methods:</b> 707 * <ul> 708 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanMapPutReturnsOldValue()} 709 * </ul> 710 * </ul> 711 * 712 * <h5 class='section'>Description:</h5> 713 * 714 * <p> 715 * When enabled, then the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property 716 * values. Otherwise, it returns <jk>null</jk>. 717 * 718 * <p> 719 * Disabled by default because it introduces a slight performance penalty during serialization. 720 * 721 * <h5 class='section'>Example:</h5> 722 * <p class='bcode w800'> 723 * <jc>// Create a serializer that creates BeanMaps with normal put() behavior.</jc> 724 * WriterSerializer s = JsonSerializer 725 * .<jsm>create</jsm>() 726 * .beanMapPutReturnsOldValue() 727 * .build(); 728 * 729 * <jc>// Same, but use property.</jc> 730 * WriterSerializer s = JsonSerializer 731 * .<jsm>create</jsm>() 732 * .set(<jsf>BEAN_beanMapPutReturnsOldValue</jsf>, <jk>true</jk>) 733 * .build(); 734 * 735 * BeanMap<MyBean> bm = s.createSession().toBeanMap(<jk>new</jk> MyBean()); 736 * bm.put(<js>"foo"</js>, <js>"bar"</js>); 737 * Object oldValue = bm.put(<js>"foo"</js>, <js>"baz"</js>); <jc>// oldValue == "bar"</jc> 738 * </p> 739 */ 740 public static final String BEAN_beanMapPutReturnsOldValue = PREFIX + ".beanMapPutReturnsOldValue.b"; 741 742 /** 743 * Configuration property: Minimum bean method visibility. 744 * 745 * <h5 class='section'>Property:</h5> 746 * <ul class='spaced-list'> 747 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beanMethodVisibility BEAN_beanMethodVisibility} 748 * <li><b>Name:</b> <js>"BeanContext.beanMethodVisibility.s"</js> 749 * <li><b>Data type:</b> {@link org.apache.juneau.Visibility} 750 * <li><b>System property:</b> <c>BeanContext.beanMethodVisibility</c> 751 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANMETHODVISIBILITY</c> 752 * <li><b>Default:</b> {@link org.apache.juneau.Visibility#PUBLIC} 753 * <li><b>Session property:</b> <jk>false</jk> 754 * <li><b>Annotations:</b> 755 * <ul> 756 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beanMethodVisibility()} 757 * </ul> 758 * <li><b>Methods:</b> 759 * <ul> 760 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beanMethodVisibility(Visibility)} 761 * </ul> 762 * </ul> 763 * 764 * <h5 class='section'>Description:</h5> 765 * 766 * <p> 767 * Only look for bean methods with the specified minimum visibility. 768 * 769 * <p> 770 * This affects which methods are detected as getters and setters on a bean class. Normally only <jk>public</jk> getters and setters are considered. 771 * Use this setting if you want to reduce the visibility requirement. 772 * 773 * <h5 class='section'>Example:</h5> 774 * <p class='bcode w800'> 775 * <jc>// A bean with a protected getter.</jc> 776 * <jk>public class</jk> MyBean { 777 * <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; } 778 * <jk>protected</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; } 779 * } 780 * 781 * <jc>// Create a serializer that looks for protected getters and setters.</jc> 782 * WriterSerializer s = JsonSerializer 783 * .<jsm>create</jsm>() 784 * .beanMethodVisibility(<jsf>PROTECTED</jsf>) 785 * .build(); 786 * 787 * <jc>// Same, but use property.</jc> 788 * WriterSerializer s = JsonSerializer 789 * .<jsm>create</jsm>() 790 * .set(<jsf>BEAN_beanMethodVisibility</jsf>, <js>"PROTECTED"</js>) 791 * .build(); 792 * 793 * <jc>// Produces: {"foo":"foo","bar":"bar"}</jc> 794 * String json = s.serialize(<jk>new</jk> MyBean()); 795 * </p> 796 * 797 * <ul class='notes'> 798 * <li>The {@link Beanp @Beanp} annotation can also be used to expose a non-public method. 799 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a public bean getter/setter to ignore it as a bean property. 800 * </ul> 801 */ 802 public static final String BEAN_beanMethodVisibility = PREFIX + ".beanMethodVisibility.s"; 803 804 /** 805 * Configuration property: Beans require no-arg constructors. 806 * 807 * <h5 class='section'>Property:</h5> 808 * <ul class='spaced-list'> 809 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beansRequireDefaultConstructor BEAN_beansRequireDefaultConstructor} 810 * <li><b>Name:</b> <js>"BeanContext.beansRequireDefaultConstructor.b"</js> 811 * <li><b>Data type:</b> <jk>boolean</jk> 812 * <li><b>System property:</b> <c>BeanContext.beansRequireDefaultConstructor</c> 813 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANSREQUIREDEFAULTCONSTRUCTOR</c> 814 * <li><b>Default:</b> <jk>false</jk> 815 * <li><b>Session property:</b> <jk>false</jk> 816 * <li><b>Annotations:</b> 817 * <ul> 818 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireDefaultConstructor()} 819 * </ul> 820 * <li><b>Methods:</b> 821 * <ul> 822 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beansRequireDefaultConstructor()} 823 * </ul> 824 * </ul> 825 * 826 * <h5 class='section'>Description:</h5> 827 * 828 * <p> 829 * When enabled, a Java class must implement a default no-arg constructor to be considered a bean. 830 * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 831 * 832 * <h5 class='section'>Example:</h5> 833 * <p class='bcode w800'> 834 * <jc>// A bean without a no-arg constructor.</jc> 835 * <jk>public class</jk> MyBean { 836 * 837 * <jc>// A property method.</jc> 838 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 839 * 840 * <jc>// A no-arg constructor</jc> 841 * <jk>public</jk> MyBean(String foo) { 842 * <jk>this</jk>.<jf>foo</jf> = foo; 843 * } 844 * 845 * <ja>@Override</ja> 846 * <jk>public</jk> String toString() { 847 * <jk>return</jk> <js>"bar"</js>; 848 * } 849 * } 850 * 851 * <jc>// Create a serializer that ignores beans without default constructors.</jc> 852 * WriterSerializer s = JsonSerializer 853 * .<jsm>create</jsm>() 854 * .beansRequireDefaultConstructor() 855 * .build(); 856 * 857 * <jc>// Same, but use property.</jc> 858 * WriterSerializer s = JsonSerializer 859 * .<jsm>create</jsm>() 860 * .set(<jsf>BEAN_beansRequireDefaultConstructor</jsf>, <jk>true</jk>) 861 * .build(); 862 * 863 * <jc>// Produces: "bar"</jc> 864 * String json = s.serialize(<jk>new</jk> MyBean()); 865 * </p> 866 * 867 * <ul class='notes'> 868 * <li>The {@link Bean @Bean} annotation can be used on a bean class to override this setting. 869 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean. 870 * </ul> 871 */ 872 public static final String BEAN_beansRequireDefaultConstructor = PREFIX + ".beansRequireDefaultConstructor.b"; 873 874 /** 875 * Configuration property: Beans require Serializable interface. 876 * 877 * <h5 class='section'>Property:</h5> 878 * <ul class='spaced-list'> 879 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beansRequireSerializable BEAN_beansRequireSerializable} 880 * <li><b>Name:</b> <js>"BeanContext.beansRequireSerializable.b"</js> 881 * <li><b>Data type:</b> <jk>boolean</jk> 882 * <li><b>System property:</b> <c>BeanContext.beansRequireSerializable</c> 883 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANSREQUIRESERIALIZABLE</c> 884 * <li><b>Default:</b> <jk>false</jk> 885 * <li><b>Session property:</b> <jk>false</jk> 886 * <li><b>Annotations:</b> 887 * <ul> 888 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireSerializable()} 889 * </ul> 890 * <li><b>Methods:</b> 891 * <ul> 892 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beansRequireSerializable()} 893 * </ul> 894 * </ul> 895 * 896 * <h5 class='section'>Description:</h5> 897 * 898 * <p> 899 * When enabled, a Java class must implement the {@link Serializable} interface to be considered a bean. 900 * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 901 * 902 * <h5 class='section'>Example:</h5> 903 * <p class='bcode w800'> 904 * <jc>// A bean without a Serializable interface.</jc> 905 * <jk>public class</jk> MyBean { 906 * 907 * <jc>// A property method.</jc> 908 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 909 * 910 * <ja>@Override</ja> 911 * <jk>public</jk> String toString() { 912 * <jk>return</jk> <js>"bar"</js>; 913 * } 914 * } 915 * 916 * <jc>// Create a serializer that ignores beans not implementing Serializable.</jc> 917 * WriterSerializer s = JsonSerializer 918 * .<jsm>create</jsm>() 919 * .beansRequireSerializable() 920 * .build(); 921 * 922 * <jc>// Same, but use property.</jc> 923 * WriterSerializer s = JsonSerializer 924 * .<jsm>create</jsm>() 925 * .set(<jsf>BEAN_beansRequireSerializable</jsf>, <jk>true</jk>) 926 * .build(); 927 * 928 * <jc>// Produces: "bar"</jc> 929 * String json = s.serialize(<jk>new</jk> MyBean()); 930 * </p> 931 * 932 * <ul class='notes'> 933 * <li>The {@link Bean @Bean} annotation can be used on a bean class to override this setting. 934 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on a class to ignore it as a bean. 935 * </ul> 936 */ 937 public static final String BEAN_beansRequireSerializable = PREFIX + ".beansRequireSerializable.b"; 938 939 /** 940 * Configuration property: Beans require setters for getters. 941 * 942 * <h5 class='section'>Property:</h5> 943 * <ul class='spaced-list'> 944 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beansRequireSettersForGetters BEAN_beansRequireSettersForGetters} 945 * <li><b>Name:</b> <js>"BeanContext.beansRequireSettersForGetters.b"</js> 946 * <li><b>Data type:</b> <jk>boolean</jk> 947 * <li><b>System property:</b> <c>BeanContext.beansRequireSettersForGetters</c> 948 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANSREQUIRESETTERSFORGETTERS</c> 949 * <li><b>Default:</b> <jk>false</jk> 950 * <li><b>Session property:</b> <jk>false</jk> 951 * <li><b>Annotations:</b> 952 * <ul> 953 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireSettersForGetters()} 954 * </ul> 955 * <li><b>Methods:</b> 956 * <ul> 957 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beansRequireSettersForGetters()} 958 * </ul> 959 * </ul> 960 * 961 * <h5 class='section'>Description:</h5> 962 * 963 * <p> 964 * When enabled, ignore read-only properties (properties with getters but not setters). 965 * 966 * <h5 class='section'>Example:</h5> 967 * <p class='bcode w800'> 968 * <jc>// A bean without a Serializable interface.</jc> 969 * <jk>public class</jk> MyBean { 970 * 971 * <jc>// A read/write property.</jc> 972 * <jk>public</jk> String getFoo() { <jk>return</jk> <js>"foo"</js>; } 973 * <jk>public void</jk> setFoo(String foo) { ... } 974 * 975 * <jc>// A read-only property.</jc> 976 * <jk>public</jk> String getBar() { <jk>return</jk> <js>"bar"</js>; } 977 * } 978 * 979 * <jc>// Create a serializer that ignores bean properties without setters.</jc> 980 * WriterSerializer s = JsonSerializer 981 * .<jsm>create</jsm>() 982 * .beansRequireSettersForGetters() 983 * .build(); 984 * 985 * <jc>// Same, but use property.</jc> 986 * WriterSerializer s = JsonSerializer 987 * .<jsm>create</jsm>() 988 * .set(<jsf>BEAN_beansRequireSettersForGetters</jsf>, <jk>true</jk>) 989 * .build(); 990 * 991 * <jc>// Produces: {"foo":"foo"}</jc> 992 * String json = s.serialize(<jk>new</jk> MyBean()); 993 * </p> 994 * 995 * <ul class='notes'> 996 * <li>The {@link Beanp @Beanp} annotation can be used on the getter to override this setting. 997 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters to ignore them as bean properties. 998 * </ul> 999 */ 1000 public static final String BEAN_beansRequireSettersForGetters = PREFIX + ".beansRequireSettersForGetters.b"; 1001 1002 /** 1003 * Configuration property: Beans require at least one property. 1004 * 1005 * <h5 class='section'>Property:</h5> 1006 * <ul class='spaced-list'> 1007 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_beansRequireSomeProperties BEAN_beansRequireSomeProperties} 1008 * <li><b>Name:</b> <js>"BeanContext.beansRequireSomeProperties.b"</js> 1009 * <li><b>Data type:</b> <jk>boolean</jk> 1010 * <li><b>System property:</b> <c>BeanContext.beansRequireSomeProperties</c> 1011 * <li><b>Environment variable:</b> <c>BEANCONTEXT_BEANSREQUIRESOMEPROPERTIES</c> 1012 * <li><b>Default:</b> <jk>true</jk> 1013 * <li><b>Session property:</b> <jk>false</jk> 1014 * <li><b>Annotations:</b> 1015 * <ul> 1016 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#beansRequireSomeProperties()} 1017 * </ul> 1018 * <li><b>Methods:</b> 1019 * <ul> 1020 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#beansDontRequireSomeProperties()} 1021 * </ul> 1022 * </ul> 1023 * 1024 * <h5 class='section'>Description:</h5> 1025 * 1026 * <p> 1027 * When enabled, then a Java class must contain at least 1 property to be considered a bean. 1028 * Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 1029 * 1030 * <p> 1031 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>. 1032 * 1033 * <h5 class='section'>Example:</h5> 1034 * <p class='bcode w800'> 1035 * <jc>// A bean with no properties.</jc> 1036 * <jk>public class</jk> MyBean { 1037 * } 1038 * 1039 * <jc>// Create a serializer that serializes beans even if they have zero properties.</jc> 1040 * WriterSerializer s = JsonSerializer 1041 * .<jsm>create</jsm>() 1042 * .beansDontRequireSomeProperties() 1043 * .build(); 1044 * 1045 * <jc>// Same, but use property.</jc> 1046 * WriterSerializer s = JsonSerializer 1047 * .<jsm>create</jsm>() 1048 * .set(<jsf>BEAN_beansRequireSomeProperties</jsf>, <jk>false</jk>) 1049 * .build(); 1050 * 1051 * <jc>// Produces: {}</jc> 1052 * String json = s.serialize(<jk>new</jk> MyBean()); 1053 * </p> 1054 * 1055 * <ul class='notes'> 1056 * <li>The {@link Bean @Bean} annotation can be used on the class to force it to be recognized as a bean class 1057 * even if it has no properties. 1058 * </ul> 1059 */ 1060 public static final String BEAN_beansRequireSomeProperties = PREFIX + ".beansRequireSomeProperties.b"; 1061 1062 /** 1063 * Configuration property: Bean type property name. 1064 * 1065 * <h5 class='section'>Property:</h5> 1066 * <ul class='spaced-list'> 1067 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_typePropertyName BEAN_typePropertyName} 1068 * <li><b>Name:</b> <js>"BeanContext.typePropertyName.s"</js> 1069 * <li><b>Data type:</b> <c>String</c> 1070 * <li><b>System property:</b> <c>BeanContext.typePropertyName</c> 1071 * <li><b>Environment variable:</b> <c>BEANCONTEXT_TYPEPROPERTYNAME</c> 1072 * <li><b>Default:</b> <js>"_type"</js> 1073 * <li><b>Session property:</b> <jk>false</jk> 1074 * <li><b>Annotations:</b> 1075 * <ul> 1076 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#typePropertyName()} 1077 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#typePropertyName()} 1078 * </ul> 1079 * <li><b>Methods:</b> 1080 * <ul> 1081 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#typePropertyName(String)} 1082 * </ul> 1083 * </ul> 1084 * 1085 * <h5 class='section'>Description:</h5> 1086 * 1087 * <p> 1088 * This specifies the name of the bean property used to store the dictionary name of a bean type so that the 1089 * parser knows the data type to reconstruct. 1090 * 1091 * <h5 class='section'>Example:</h5> 1092 * <p class='bcode w800'> 1093 * <jc>// POJOs with @Bean(name) annotations.</jc> 1094 * <ja>@Bean</ja>(typeName=<js>"foo"</js>) 1095 * <jk>public class</jk> Foo {...} 1096 * <ja>@Bean</ja>(typeName=<js>"bar"</js>) 1097 * <jk>public class</jk> Bar {...} 1098 * 1099 * <jc>// Create a serializer that uses 't' instead of '_type' for dictionary names.</jc> 1100 * WriterSerializer s = JsonSerializer 1101 * .<jsm>create</jsm>() 1102 * .typePropertyName(<js>"t"</js>) 1103 * .dictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>) 1104 * .build(); 1105 * 1106 * <jc>// Same, but use property.</jc> 1107 * WriterSerializer s = JsonSerializer 1108 * .<jsm>create</jsm>() 1109 * .set(<jsf>BEAN_typePropertyName</jsf>, <js>"t"</js>) 1110 * .addTo(<jsf>BEAN_beanDictionary</jsf>, Foo.<jk>class</jk>) 1111 * .addTo(<jsf>BEAN_beanDictionary</jsf>, Bar.<jk>class</jk>) 1112 * .build(); 1113 * 1114 * <jc>// A bean with a field with an indeterminate type.</jc> 1115 * <jk>public class</jk> MyBean { 1116 * <jk>public</jk> Object <jf>mySimpleField</jf>; 1117 * } 1118 * 1119 * <jc>// Parse bean.</jc> 1120 * MyBean b = p.parse(<js>"{mySimpleField:{t:'foo',...}}"</js>, MyBean.<jk>class</jk>); 1121 * </p> 1122 * 1123 * <ul class='seealso'> 1124 * <li class='link'>{@doc BeanDictionaries} 1125 * </ul> 1126 */ 1127 public static final String BEAN_typePropertyName = PREFIX + ".typePropertyName.s"; 1128 1129 /** 1130 * Configuration property: Bean property includes. 1131 * 1132 * <div class='warn'> 1133 * <b>Deprecated</b> - Use {@link Bean#bpi()} and {@link BeanConfig#bpi()} 1134 * </div> 1135 */ 1136 @Deprecated 1137 public static final String BEAN_bpi = PREFIX + ".bpi.sms"; 1138 1139 /** 1140 * Configuration property: Bean property excludes. 1141 * 1142 * <div class='warn'> 1143 * <b>Deprecated</b> - Use {@link Bean#bpx()} and {@link BeanConfig#bpx()} 1144 * </div> 1145 */ 1146 @Deprecated 1147 public static final String BEAN_bpx = PREFIX + ".bpx.sms"; 1148 1149 /** 1150 * Configuration property: Read-only bean properties. 1151 * 1152 * <div class='warn'> 1153 * <b>Deprecated</b> - Use {@link Bean#bpro()} and {@link BeanConfig#bpro()} 1154 * </div> 1155 */ 1156 @Deprecated 1157 public static final String BEAN_bpro = PREFIX + ".bpro.sms"; 1158 1159 /** 1160 * Configuration property: Write-only bean properties. 1161 * 1162 * <div class='warn'> 1163 * <b>Deprecated</b> - Use {@link Bean#bpwo()} and {@link BeanConfig#bpwo()} 1164 * </div> 1165 */ 1166 @Deprecated 1167 public static final String BEAN_bpwo = PREFIX + ".bpwo.sms"; 1168 1169 /** 1170 * Configuration property: POJO examples. 1171 * 1172 * <h5 class='section'>Property:</h5> 1173 * <ul class='spaced-list'> 1174 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_examples BEAN_examples} 1175 * <li><b>Name:</b> <js>"BeanContext.examples.smo"</js> 1176 * <li><b>Data type:</b> <c>Map<String,Object></c> 1177 * <li><b>Default:</b> <c>{}</c> 1178 * <li><b>Session property:</b> <jk>false</jk> 1179 * <li><b>Annotations:</b> 1180 * <ul> 1181 * <li class='ja'>{@link org.apache.juneau.annotation.Example} 1182 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#example()} 1183 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#examples()} 1184 * </ul> 1185 * <li><b>Methods:</b> 1186 * <ul> 1187 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#example(Class,Object)} 1188 * </ul> 1189 * </ul> 1190 * 1191 * <h5 class='section'>Description:</h5> 1192 * 1193 * <p> 1194 * Specifies an example of the specified class. 1195 * 1196 * <p> 1197 * Examples are used in cases such as POJO examples in Swagger documents. 1198 * 1199 * <p> 1200 * Setting applies to specified class and all subclasses. 1201 * 1202 * <h5 class='section'>Example:</h5> 1203 * <p class='bcode w800'> 1204 * <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc> 1205 * WriterSerializer s = JsonSerializer 1206 * .<jsm>create</jsm>() 1207 * .example(MyBean.<jk>class</jk>, <jk>new</jk> MyBean().foo(<js>"foo"</js>).bar(123)) 1208 * .build(); 1209 * 1210 * <jc>// Same, but use property.</jc> 1211 * WriterSerializer s = JsonSerializer 1212 * .<jsm>create</jsm>() 1213 * .addTo(<jsf>BEAN_examples</jsf>, MyBean.<jk>class</jk>.getName(), <jk>new</jk> MyBean().foo(<js>"foo"</js>).bar(123)) 1214 * .build(); 1215 * </p> 1216 * 1217 * <p> 1218 * POJO examples can also be defined on classes via the following: 1219 * <ul class='spaced-list'> 1220 * <li>A static field annotated with {@link Example @Example}. 1221 * <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link BeanSession} argument. 1222 * <li>A static method with name <c>example</c> with no arguments or one {@link BeanSession} argument. 1223 * </ul> 1224 */ 1225 public static final String BEAN_examples = PREFIX + ".examples.smo"; 1226 1227 /** 1228 * Configuration property: Bean property excludes. 1229 * 1230 * <div class='warn'> 1231 * <b>Deprecated</b> - Use {@link #BEAN_bpx} 1232 * </div> 1233 */ 1234 @Deprecated public static final String BEAN_excludeProperties = BEAN_bpx; 1235 1236 /** 1237 * Configuration property: Find fluent setters. 1238 * 1239 * <h5 class='section'>Property:</h5> 1240 * <ul class='spaced-list'> 1241 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_fluentSetters BEAN_fluentSetters} 1242 * <li><b>Name:</b> <js>"BeanContext.fluentSetters.b"</js> 1243 * <li><b>Data type:</b> <jk>boolean</jk> 1244 * <li><b>System property:</b> <c>BeanContext.fluentSetters</c> 1245 * <li><b>Environment variable:</b> <c>BEANCONTEXT_FLUENTSETTERS</c> 1246 * <li><b>Default:</b> <jk>false</jk> 1247 * <li><b>Session property:</b> <jk>false</jk> 1248 * <li><b>Annotations:</b> 1249 * <ul> 1250 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#fluentSetters()} 1251 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#fluentSetters()} 1252 * </ul> 1253 * <li><b>Methods:</b> 1254 * <ul> 1255 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#fluentSetters()} 1256 * <li class='jm'>{@link org.apache.juneau.transform.BeanFilterBuilder#fluentSetters(boolean)} 1257 * <li class='jm'>{@link org.apache.juneau.transform.BeanFilterBuilder#fluentSetters()} 1258 * </ul> 1259 * </ul> 1260 * 1261 * <h5 class='section'>Description:</h5> 1262 * 1263 * <p> 1264 * When enabled, fluent setters are detected on beans during parsing. 1265 * 1266 * <p> 1267 * Fluent setters must have the following attributes: 1268 * <ul> 1269 * <li>Public. 1270 * <li>Not static. 1271 * <li>Take in one parameter. 1272 * <li>Return the bean itself. 1273 * </ul> 1274 * 1275 * <h5 class='section'>Example:</h5> 1276 * <p class='bcode w800'> 1277 * <jc>// A bean with a fluent setter.</jc> 1278 * <jk>public class</jk> MyBean { 1279 * <jk>public</jk> MyBean foo(String value) {...} 1280 * } 1281 * 1282 * <jc>// Create a parser that finds fluent setters.</jc> 1283 * ReaderParser p = JsonParser 1284 * .<jsm>create</jsm>() 1285 * .fluentSetters() 1286 * .build(); 1287 * 1288 * <jc>// Same, but use property.</jc> 1289 * ReaderParser p = JsonParser 1290 * .<jsm>create</jsm>() 1291 * .set(<jsf>BEAN_fluentSetters</jsf>, <jk>true</jk>) 1292 * .build(); 1293 * 1294 * <jc>// Parse into bean using fluent setter.</jc> 1295 * MyBean b = p.parse(<js>"{foo:'bar'}"</js>); 1296 * </p> 1297 * 1298 * <ul class='notes'> 1299 * <li>The {@link Beanp @Beanp} annotation can also be used on methods to individually identify them as fluent setters. 1300 * <li>The {@link Bean#fluentSetters() @Bean.fluentSetters()} annotation can also be used on classes to specify to look for fluent setters. 1301 * </ul> 1302 */ 1303 public static final String BEAN_fluentSetters = PREFIX + ".fluentSetters.b"; 1304 1305 /** 1306 * Configuration property: Ignore invocation errors on getters. 1307 * 1308 * <h5 class='section'>Property:</h5> 1309 * <ul class='spaced-list'> 1310 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnGetters BEAN_ignoreInvocationExceptionsOnGetters} 1311 * <li><b>Name:</b> <js>"BeanContext.ignoreInvocationExceptionsOnGetters.b"</js> 1312 * <li><b>Data type:</b> <jk>boolean</jk> 1313 * <li><b>System property:</b> <c>BeanContext.ignoreInvocationExceptionsOnGetters</c> 1314 * <li><b>Environment variable:</b> <c>BEANCONTEXT_IGNOREINVOCATIONEXCEPTIONONGETTERS</c> 1315 * <li><b>Default:</b> <jk>false</jk> 1316 * <li><b>Session property:</b> <jk>false</jk> 1317 * <li><b>Annotations:</b> 1318 * <ul> 1319 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreInvocationExceptionsOnGetters()} 1320 * </ul> 1321 * <li><b>Methods:</b> 1322 * <ul> 1323 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#ignoreInvocationExceptionsOnGetters()} 1324 * </ul> 1325 * </ul> 1326 * 1327 * <h5 class='section'>Description:</h5> 1328 * 1329 * <p> 1330 * When enabled, errors thrown when calling bean getter methods will silently be ignored. 1331 * Otherwise, a {@code BeanRuntimeException} is thrown. 1332 * 1333 * <h5 class='section'>Example:</h5> 1334 * <p class='bcode w800'> 1335 * <jc>// A bean with a property that throws an exception.</jc> 1336 * <jk>public class</jk> MyBean { 1337 * <jk>public</jk> String getFoo() { 1338 * <jk>throw new</jk> RuntimeException(<js>"foo"</js>); 1339 * } 1340 * } 1341 * 1342 * <jc>// Create a serializer that ignores bean getter exceptions.</jc> 1343 * WriterSerializer s = JsonSerializer 1344 * .<jsm>create</jsm>() 1345 * .ingoreInvocationExceptionsOnGetters() 1346 * .build(); 1347 * 1348 * <jc>// Same, but use property.</jc> 1349 * WriterSerializer s = JsonSerializer 1350 * .<jsm>create</jsm>() 1351 * .set(<jsf>BEAN_ignoreInvocationExceptionsOnGetters</jsf>, <jk>true</jk>) 1352 * .build(); 1353 * 1354 * <jc>// Exception is ignored.</jc> 1355 * String json = s.serialize(<jk>new</jk> MyBean()); 1356 * </p> 1357 */ 1358 public static final String BEAN_ignoreInvocationExceptionsOnGetters = PREFIX + ".ignoreInvocationExceptionsOnGetters.b"; 1359 1360 /** 1361 * Configuration property: Ignore invocation errors on setters. 1362 * 1363 * <h5 class='section'>Property:</h5> 1364 * <ul class='spaced-list'> 1365 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_ignoreInvocationExceptionsOnSetters BEAN_ignoreInvocationExceptionsOnSetters} 1366 * <li><b>Name:</b> <js>"BeanContext.ignoreInvocationExceptionsOnSetters.b"</js> 1367 * <li><b>Data type:</b> <jk>boolean</jk> 1368 * <li><b>System property:</b> <c>BeanContext.ignoreInvocationExceptionsOnSetters</c> 1369 * <li><b>Environment variable:</b> <c>BEANCONTEXT_IGNOREINVOCATIONEXCEPTIONSONSETTERS</c> 1370 * <li><b>Default:</b> <jk>false</jk> 1371 * <li><b>Session property:</b> <jk>false</jk> 1372 * <li><b>Annotations:</b> 1373 * <ul> 1374 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreInvocationExceptionsOnSetters()} 1375 * </ul> 1376 * <li><b>Methods:</b> 1377 * <ul> 1378 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#ignoreInvocationExceptionsOnSetters()} 1379 * </ul> 1380 * </ul> 1381 * 1382 * <h5 class='section'>Description:</h5> 1383 * 1384 * <p> 1385 * When enabled, errors thrown when calling bean setter methods will silently be ignored. 1386 * Otherwise, a {@code BeanRuntimeException} is thrown. 1387 * 1388 * <h5 class='section'>Example:</h5> 1389 * <p class='bcode w800'> 1390 * <jc>// A bean with a property that throws an exception.</jc> 1391 * <jk>public class</jk> MyBean { 1392 * <jk>public void</jk> setFoo(String foo) { 1393 * <jk>throw new</jk> RuntimeException(<js>"foo"</js>); 1394 * } 1395 * } 1396 * 1397 * <jc>// Create a parser that ignores bean setter exceptions.</jc> 1398 * ReaderParser p = JsonParser 1399 * .<jsm>create</jsm>() 1400 * .ignoreInvocationExceptionsOnSetters() 1401 * .build(); 1402 * 1403 * <jc>// Same, but use property.</jc> 1404 * ReaderParser p = JsonParser 1405 * .<jsm>create</jsm>() 1406 * .set(<jsf>BEAN_ignoreInvocationExceptionsOnSetters</jsf>, <jk>true</jk>) 1407 * .build(); 1408 * 1409 * <jc>// Exception is ignored.</jc> 1410 * MyBean b = p.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>); 1411 * </p> 1412 */ 1413 public static final String BEAN_ignoreInvocationExceptionsOnSetters = PREFIX + ".ignoreInvocationExceptionsOnSetters.b"; 1414 1415 /** 1416 * Configuration property: Ignore properties without setters. 1417 * 1418 * <h5 class='section'>Property:</h5> 1419 * <ul class='spaced-list'> 1420 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_ignorePropertiesWithoutSetters BEAN_ignorePropertiesWithoutSetters} 1421 * <li><b>Name:</b> <js>"BeanContext.ignorePropertiesWithoutSetters.b"</js> 1422 * <li><b>Data type:</b> <jk>boolean</jk> 1423 * <li><b>System property:</b> <c>BeanContext.ignorePropertiesWithoutSetters</c> 1424 * <li><b>Environment variable:</b> <c>BEANCONTEXT_IGNOREPROPERTIESWITHOUTSETTERS</c> 1425 * <li><b>Default:</b> <jk>true</jk> 1426 * <li><b>Session property:</b> <jk>false</jk> 1427 * <li><b>Annotations:</b> 1428 * <ul> 1429 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignorePropertiesWithoutSetters()} 1430 * </ul> 1431 * <li><b>Methods:</b> 1432 * <ul> 1433 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#dontIgnorePropertiesWithoutSetters()} 1434 * </ul> 1435 * </ul> 1436 * 1437 * <h5 class='section'>Description:</h5> 1438 * 1439 * <p> 1440 * When enabled, trying to set a value on a bean property without a setter will silently be ignored. 1441 * Otherwise, a {@code BeanRuntimeException} is thrown. 1442 * 1443 * <h5 class='section'>Example:</h5> 1444 * <p class='bcode w800'> 1445 * <jc>// A bean with a property with a getter but not a setter.</jc> 1446 * <jk>public class</jk> MyBean { 1447 * <jk>public void</jk> getFoo() { 1448 * <jk>return</jk> <js>"foo"</js>; 1449 * } 1450 * } 1451 * 1452 * <jc>// Create a parser that throws an exception if a setter is not found but a getter is.</jc> 1453 * ReaderParser p = JsonParser 1454 * .<jsm>create</jsm>() 1455 * .dontIgnorePropertiesWithoutSetters() 1456 * .build(); 1457 * 1458 * <jc>// Same, but use property.</jc> 1459 * ReaderParser p = JsonParser 1460 * .<jsm>create</jsm>() 1461 * .set(<jsf>BEAN_ignorePropertiesWithoutSetters</jsf>, <jk>false</jk>) 1462 * .build(); 1463 * 1464 * <jc>// Throws a ParseException.</jc> 1465 * MyBean b = p.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>); 1466 * </p> 1467 * 1468 * <ul class='notes'> 1469 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on getters and fields to ignore them. 1470 * </ul> 1471 */ 1472 public static final String BEAN_ignorePropertiesWithoutSetters = PREFIX + ".ignorePropertiesWithoutSetters.b"; 1473 1474 /** 1475 * Configuration property: Ignore transient fields. 1476 * 1477 * <h5 class='section'>Property:</h5> 1478 * <ul class='spaced-list'> 1479 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_ignoreTransientFields BEAN_ignoreTransientFields} 1480 * <li><b>Name:</b> <js>"BeanContext.ignoreTransientFields.b"</js> 1481 * <li><b>Data type:</b> <jk>boolean</jk> 1482 * <li><b>System property:</b> <c>BeanContext.ignoreTransientFields</c> 1483 * <li><b>Environment variable:</b> <c>BEANCONTEXT_IGNORETRANSIENTFIELDS</c> 1484 * <li><b>Default:</b> <jk>true</jk> 1485 * <li><b>Session property:</b> <jk>false</jk> 1486 * <li><b>Annotations:</b> 1487 * <ul> 1488 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreTransientFields()} 1489 * </ul> 1490 * <li><b>Methods:</b> 1491 * <ul> 1492 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#dontIgnoreTransientFields()} 1493 * </ul> 1494 * </ul> 1495 * 1496 * <h5 class='section'>Description:</h5> 1497 * 1498 * <p> 1499 * When enabled, methods and fields marked as <jk>transient</jk> will be ignored as bean properties. 1500 * 1501 * <h5 class='section'>Example:</h5> 1502 * <p class='bcode w800'> 1503 * <jc>// A bean with a transient field.</jc> 1504 * <jk>public class</jk> MyBean { 1505 * <jk>public transient</jk> String foo = <js>"foo"</js>; 1506 * } 1507 * 1508 * <jc>// Create a parser that doesn't ignore transient fields.</jc> 1509 * ReaderParser p = JsonParser 1510 * .<jsm>create</jsm>() 1511 * .dontIgnoreTransientFields() 1512 * .build(); 1513 * 1514 * <jc>// Same, but use property.</jc> 1515 * ReaderParser p = JsonParser 1516 * .<jsm>create</jsm>() 1517 * .set(<jsf>BEAN_ignoreTransientFields</jsf>, <jk>false</jk>) 1518 * .build(); 1519 * 1520 * <jc>// Produces: {"foo":"foo"}</jc> 1521 * String json = s.serialize(<jk>new</jk> MyBean()); 1522 * </p> 1523 * 1524 * <ul class='notes'> 1525 * <li>The {@link Beanp @Beanp} annotation can also be used on transient fields to keep them from being ignored. 1526 * </ul> 1527 */ 1528 public static final String BEAN_ignoreTransientFields = PREFIX + ".ignoreTransientFields.b"; 1529 1530 /** 1531 * Configuration property: Ignore unknown properties. 1532 * 1533 * <h5 class='section'>Property:</h5> 1534 * <ul class='spaced-list'> 1535 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownBeanProperties BEAN_ignoreUnknownBeanProperties} 1536 * <li><b>Name:</b> <js>"BeanContext.ignoreUnknownBeanProperties.b"</js> 1537 * <li><b>Data type:</b> <jk>boolean</jk> 1538 * <li><b>System property:</b> <c>BeanContext.ignoreUnknownBeanProperties</c> 1539 * <li><b>Environment variable:</b> <c>BEANCONTEXT_IGNOREUNKNOWNBEANPROPERTIES</c> 1540 * <li><b>Default:</b> <jk>false</jk> 1541 * <li><b>Session property:</b> <jk>false</jk> 1542 * <li><b>Annotations:</b> 1543 * <ul> 1544 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreUnknownBeanProperties()} 1545 * </ul> 1546 * <li><b>Methods:</b> 1547 * <ul> 1548 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#ignoreUnknownBeanProperties()} 1549 * </ul> 1550 * </ul> 1551 * 1552 * <h5 class='section'>Description:</h5> 1553 * 1554 * <p> 1555 * When enabled, trying to set a value on a non-existent bean property will silently be ignored. 1556 * Otherwise, a {@code BeanRuntimeException} is thrown. 1557 * 1558 * <h5 class='section'>Example:</h5> 1559 * <p class='bcode w800'> 1560 * <jc>// A bean with a single property.</jc> 1561 * <jk>public class</jk> MyBean { 1562 * <jk>public</jk> String foo; 1563 * } 1564 * 1565 * <jc>// Create a parser that ignores missing bean properties.</jc> 1566 * ReaderParser p = JsonParser 1567 * .<jsm>create</jsm>() 1568 * .ignoreUnknownBeanProperties() 1569 * .build(); 1570 * 1571 * <jc>// Same, but use property.</jc> 1572 * ReaderParser p = JsonParser 1573 * .<jsm>create</jsm>() 1574 * .set(<jsf>BEAN_ignoreUnknownBeanProperties</jsf>, <jk>true</jk>) 1575 * .build(); 1576 * 1577 * <jc>// Doesn't throw an exception on unknown 'bar' property.</jc> 1578 * MyBean b = p.parse(<js>"{foo:'foo',bar:'bar'}"</js>, MyBean.<jk>class</jk>); 1579 * </p> 1580 */ 1581 public static final String BEAN_ignoreUnknownBeanProperties = PREFIX + ".ignoreUnknownBeanProperties.b"; 1582 1583 /** 1584 * Configuration property: Ignore unknown properties with null values. 1585 * 1586 * <h5 class='section'>Property:</h5> 1587 * <ul class='spaced-list'> 1588 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_ignoreUnknownNullBeanProperties BEAN_ignoreUnknownNullBeanProperties} 1589 * <li><b>Name:</b> <js>"BeanContext.ignoreUnknownNullBeanProperties.b"</js> 1590 * <li><b>Data type:</b> <jk>boolean</jk> 1591 * <li><b>System property:</b> <c>BeanContext.ignoreUnknownNullBeanProperties</c> 1592 * <li><b>Environment variable:</b> <c>BEANCONTEXT_IGNOREUNKNOWNNULLBEANPROPERTIES</c> 1593 * <li><b>Default:</b> <jk>true</jk> 1594 * <li><b>Session property:</b> <jk>false</jk> 1595 * <li><b>Annotations:</b> 1596 * <ul> 1597 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#ignoreUnknownNullBeanProperties()} 1598 * </ul> 1599 * <li><b>Methods:</b> 1600 * <ul> 1601 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#dontIgnoreUnknownNullBeanProperties()} 1602 * </ul> 1603 * </ul> 1604 * 1605 * <h5 class='section'>Description:</h5> 1606 * 1607 * <p> 1608 * When enabled, trying to set a <jk>null</jk> value on a non-existent bean property will silently be ignored. 1609 * Otherwise, a {@code BeanRuntimeException} is thrown. 1610 * 1611 * <h5 class='section'>Example:</h5> 1612 * <p class='bcode w800'> 1613 * <jc>// A bean with a single property.</jc> 1614 * <jk>public class</jk> MyBean { 1615 * <jk>public</jk> String foo; 1616 * } 1617 * 1618 * <jc>// Create a parser that throws an exception on an unknown property even if the value being set is null.</jc> 1619 * ReaderParser p = JsonParser 1620 * .<jsm>create</jsm>() 1621 * .dontIgnoreUnknownNullBeanProperties() 1622 * .build(); 1623 * 1624 * <jc>// Same, but use property.</jc> 1625 * ReaderParser p = JsonParser 1626 * .<jsm>create</jsm>() 1627 * .set(<jsf>BEAN_ignoreUnknownNullBeanProperties</jsf>, <jk>false</jk>) 1628 * .build(); 1629 * 1630 * <jc>// Throws a BeanRuntimeException wrapped in a ParseException on the unknown 'bar' property.</jc> 1631 * MyBean b = p.parse(<js>"{foo:'foo',bar:null}"</js>, MyBean.<jk>class</jk>); 1632 * </p> 1633 */ 1634 public static final String BEAN_ignoreUnknownNullBeanProperties = PREFIX + ".ignoreUnknownNullBeanProperties.b"; 1635 1636 /** 1637 * Configuration property: Implementation classes. 1638 * 1639 * <h5 class='section'>Property:</h5> 1640 * <ul class='spaced-list'> 1641 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_implClasses BEAN_implClasses} 1642 * <li><b>Name:</b> <js>"BeanContext.implClasses.smc"</js> 1643 * <li><b>Data type:</b> <c>Map<String,Class></c> 1644 * <li><b>Default:</b> empty map 1645 * <li><b>Session property:</b> <jk>false</jk> 1646 * <li><b>Annotations:</b> 1647 * <ul> 1648 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#implClasses()} 1649 * </ul> 1650 * <li><b>Methods:</b> 1651 * <ul> 1652 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#implClasses(Map)} 1653 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#implClass(Class, Class)} 1654 * </ul> 1655 * </ul> 1656 * 1657 * <h5 class='section'>Description:</h5> 1658 * 1659 * <p> 1660 * For interfaces and abstract classes this method can be used to specify an implementation class for the 1661 * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a 1662 * parse). 1663 * 1664 * <h5 class='section'>Example:</h5> 1665 * <p class='bcode w800'> 1666 * <jc>// A bean interface.</jc> 1667 * <jk>public interface</jk> MyBean { 1668 * ... 1669 * } 1670 * 1671 * <jc>// A bean implementation.</jc> 1672 * <jk>public class</jk> MyBeanImpl <jk>implements</jk> MyBean { 1673 * ... 1674 * } 1675 1676 * <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeans.</jc> 1677 * ReaderParser p = JsonParser 1678 * .<jsm>create</jsm>() 1679 * .implClass(MyBean.<jk>class</jk>, MyBeanImpl.<jk>class</jk>) 1680 * .build(); 1681 * 1682 * <jc>// Same, but use property.</jc> 1683 * ReaderParser p = JsonParser 1684 * .<jsm>create</jsm>() 1685 * .addTo(<jsf>BEAN_implClasses</jsf>, MyBean.<jk>class</jk>.getName(), MyBeanImpl.<jk>class</jk>) 1686 * .build(); 1687 * 1688 * <jc>// Instantiates a MyBeanImpl,</jc> 1689 * MyBean b = p.parse(<js>"..."</js>, MyBean.<jk>class</jk>); 1690 * </p> 1691 */ 1692 public static final String BEAN_implClasses = PREFIX + ".implClasses.smc"; 1693 1694 /** 1695 * Configuration property: Bean property includes. 1696 * 1697 * <div class='warn'> 1698 * <b>Deprecated</b> - Use {@link #BEAN_bpi} 1699 * </div> 1700 */ 1701 @Deprecated public static final String BEAN_includeProperties = BEAN_bpi; 1702 1703 /** 1704 * Configuration property: Bean class exclusions. 1705 * 1706 * <h5 class='section'>Property:</h5> 1707 * <ul class='spaced-list'> 1708 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_notBeanClasses BEAN_notBeanClasses} 1709 * <li><b>Name:</b> <js>"BeanContext.notBeanClasses.sc"</js> 1710 * <li><b>Data type:</b> <c>Set<Class></c> 1711 * <li><b>Default:</b> empty set 1712 * <li><b>Session property:</b> <jk>false</jk> 1713 * <li><b>Annotations:</b> 1714 * <ul> 1715 * <li class='ja'>{@link org.apache.juneau.annotation.BeanIgnore} 1716 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#notBeanClasses()} 1717 * </ul> 1718 * <li><b>Methods:</b> 1719 * <ul> 1720 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#notBeanClasses(Object...)} 1721 * </ul> 1722 * </ul> 1723 * 1724 * <h5 class='section'>Description:</h5> 1725 * 1726 * <p> 1727 * List of classes that should not be treated as beans even if they appear to be bean-like. 1728 * Not-bean classes are converted to <c>Strings</c> during serialization. 1729 * 1730 * <p> 1731 * Values can consist of any of the following types: 1732 * <ul> 1733 * <li>Classes. 1734 * <li>Arrays and collections of classes. 1735 * </ul> 1736 * 1737 * <h5 class='section'>Example:</h5> 1738 * <p class='bcode w800'> 1739 * <jc>// A bean with a single property.</jc> 1740 * <jk>public class</jk> MyBean { 1741 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 1742 * 1743 * <jk>public</jk> String toString() { 1744 * <jk>return</jk> <js>"baz"</js>; 1745 * } 1746 * } 1747 * 1748 * <jc>// Create a serializer that doesn't treat MyBean as a bean class.</jc> 1749 * WriterSerializer s = JsonSerializer 1750 * .<jsm>create</jsm>() 1751 * .notBeanClasses(MyBean.<jk>class</jk>) 1752 * .build(); 1753 * 1754 * <jc>// Same, but use property.</jc> 1755 * WriterSerializer s = JsonSerializer 1756 * .<jsm>create</jsm>() 1757 * .addTo(<jsf>BEAN_notBeanClasses</jsf>, MyBean.<jk>class</jk>) 1758 * .build(); 1759 * 1760 * <jc>// Produces "baz" instead of {"foo":"bar"}</jc> 1761 * String json = s.serialize(<jk>new</jk> MyBean()); 1762 * </p> 1763 * 1764 * <ul class='notes'> 1765 * <li>The {@link BeanIgnore @BeanIgnore} annotation can also be used on classes to prevent them from being recognized as beans. 1766 * </ul> 1767 */ 1768 public static final String BEAN_notBeanClasses = PREFIX + ".notBeanClasses.sc"; 1769 1770 /** 1771 * Configuration property: Add to classes that should not be considered beans. 1772 */ 1773 public static final String BEAN_notBeanClasses_add = PREFIX + ".notBeanClasses.sc/add"; 1774 1775 /** 1776 * Configuration property: Remove from classes that should not be considered beans. 1777 */ 1778 public static final String BEAN_notBeanClasses_remove = PREFIX + ".notBeanClasses.sc/remove"; 1779 1780 /** 1781 * Configuration property: Bean package exclusions. 1782 * 1783 * <h5 class='section'>Property:</h5> 1784 * <ul class='spaced-list'> 1785 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_notBeanPackages BEAN_notBeanPackages} 1786 * <li><b>Name:</b> <js>"BeanContext.notBeanPackages.ss"</js> 1787 * <li><b>Data type:</b> <c>Set<String></c> 1788 * <li><b>System property:</b> <c>BeanContext.notBeanPackages</c> 1789 * <li><b>Environment variable:</b> <c>BEANCONTEXT_NOTBEANPACKAGES</c> 1790 * <li><b>Default:</b> 1791 * <ul> 1792 * <li><c>java.lang</c> 1793 * <li><c>java.lang.annotation</c> 1794 * <li><c>java.lang.ref</c> 1795 * <li><c>java.lang.reflect</c> 1796 * <li><c>java.io</c> 1797 * <li><c>java.net</c> 1798 * <li><c>java.nio.*</c> 1799 * <li><c>java.util.*</c> 1800 * </ul> 1801 * <li><b>Session property:</b> <jk>false</jk> 1802 * <li><b>Annotations:</b> 1803 * <ul> 1804 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#notBeanPackages()} 1805 * </ul> 1806 * <li><b>Methods:</b> 1807 * <ul> 1808 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#notBeanPackages(Object...)} 1809 * </ul> 1810 * </ul> 1811 * 1812 * <h5 class='section'>Description:</h5> 1813 * 1814 * <p> 1815 * Used as a convenient way of defining the {@link #BEAN_notBeanClasses} property for entire packages. 1816 * Any classes within these packages will be serialized to strings using {@link Object#toString()}. 1817 * 1818 * <p> 1819 * Note that you can specify suffix patterns to include all subpackages. 1820 * 1821 * <p> 1822 * Values can consist of any of the following types: 1823 * <ul> 1824 * <li>Strings. 1825 * <li>Arrays and collections of strings. 1826 * </ul> 1827 * 1828 * <h5 class='section'>Example:</h5> 1829 * <p class='bcode w800'> 1830 * <jc>// Create a serializer that ignores beans in the specified packages.</jc> 1831 * WriterSerializer s = JsonSerializer 1832 * .<jsm>create</jsm>() 1833 * .notBeanPackages(<js>"org.apache.foo"</js>, <js>"org.apache.bar.*"</js>) 1834 * .build(); 1835 * 1836 * <jc>// Same, but use property.</jc> 1837 * WriterSerializer s = JsonSerializer 1838 * .<jsm>create</jsm>() 1839 * .addTo(<jsf>BEAN_notBeanPackages</jsf>, <js>"org.apache.foo"</js>) 1840 * .addTo(<jsf>BEAN_notBeanPackages</jsf>, <js>"org.apache.bar.*"</js>) 1841 * .build(); 1842 * </p> 1843 */ 1844 public static final String BEAN_notBeanPackages = PREFIX + ".notBeanPackages.ss"; 1845 1846 /** 1847 * Configuration property: Add to packages whose classes should not be considered beans. 1848 */ 1849 public static final String BEAN_notBeanPackages_add = PREFIX + ".notBeanPackages.ss/add"; 1850 1851 /** 1852 * Configuration property: Remove from packages whose classes should not be considered beans. 1853 */ 1854 public static final String BEAN_notBeanPackages_remove = PREFIX + ".notBeanPackages.ss/remove"; 1855 1856 /** 1857 * Configuration property: POJO swaps. 1858 * 1859 * <div class='warn'> 1860 * <b>Deprecated</b> - Use {@link #BEAN_swaps} 1861 * </div> 1862 */ 1863 @Deprecated 1864 public static final String BEAN_pojoSwaps = PREFIX + ".pojoSwaps.lo"; 1865 1866 /** 1867 * Configuration property: Add to POJO swap classes. 1868 * 1869 * <div class='warn'> 1870 * <b>Deprecated</b> - Use {@link #BEAN_swaps_add} 1871 * </div> 1872 */ 1873 @Deprecated 1874 public static final String BEAN_pojoSwaps_add = PREFIX + ".pojoSwaps.lo/add"; 1875 1876 /** 1877 * Configuration property: Remove from POJO swap classes. 1878 * 1879 * <div class='warn'> 1880 * <b>Deprecated</b> - Use {@link #BEAN_swaps_remove} 1881 * </div> 1882 */ 1883 @Deprecated 1884 public static final String BEAN_pojoSwaps_remove = PREFIX + ".pojoSwaps.lo/remove"; 1885 1886 /** 1887 * Configuration property: Bean property namer. 1888 * 1889 * <h5 class='section'>Property:</h5> 1890 * <ul class='spaced-list'> 1891 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_propertyNamer BEAN_propertyNamer} 1892 * <li><b>Name:</b> <js>"BeanContext.propertyNamer.c"</js> 1893 * <li><b>Data type:</b> <code>Class<{@link org.apache.juneau.PropertyNamer}></code> 1894 * <li><b>Default:</b> {@link org.apache.juneau.PropertyNamerDefault} 1895 * <li><b>Session property:</b> <jk>false</jk> 1896 * <li><b>Annotations:</b> 1897 * <ul> 1898 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#propertyNamer()} 1899 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#propertyNamer()} 1900 * </ul> 1901 * <li><b>Methods:</b> 1902 * <ul> 1903 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#propertyNamer(Class)} 1904 * <li class='jm'>{@link org.apache.juneau.transform.BeanFilterBuilder#propertyNamer(Class)} 1905 * </ul> 1906 * </ul> 1907 * 1908 * <h5 class='section'>Description:</h5> 1909 * 1910 * <p> 1911 * The class to use for calculating bean property names. 1912 * 1913 * <p> 1914 * Predefined classes: 1915 * <ul> 1916 * <li>{@link PropertyNamerDefault} - Default. 1917 * <li>{@link PropertyNamerDLC} - Dashed-lower-case names. 1918 * <li>{@link PropertyNamerULC} - Dashed-upper-case names. 1919 * </ul> 1920 * 1921 * <h5 class='section'>Example:</h5> 1922 * <p class='bcode w800'> 1923 * <jc>// A bean with a single property.</jc> 1924 * <jk>public class</jk> MyBean { 1925 * <jk>public</jk> String <jf>fooBarBaz</jf> = <js>"fooBarBaz"</js>; 1926 * } 1927 * 1928 * <jc>// Create a serializer that uses Dashed-Lower-Case property names.</jc> 1929 * <jc>// (e.g. "foo-bar-baz" instead of "fooBarBaz")</jc> 1930 * WriterSerializer s = JsonSerializer 1931 * .<jsm>create</jsm>() 1932 * .propertyNamer(PropertyNamerDLC.<jk>class</jk>) 1933 * .build(); 1934 * 1935 * <jc>// Same, but use property.</jc> 1936 * WriterSerializer s = JsonSerializer 1937 * .<jsm>create</jsm>() 1938 * .set(<jsf>BEAN_propertyNamer</jsf>, PropertyNamerDLC.<jk>class</jk>) 1939 * .build(); 1940 * 1941 * <jc>// Produces: {"foo-bar-baz":"fooBarBaz"}</jc> 1942 * String json = s.serialize(<jk>new</jk> MyBean()); 1943 * </p> 1944 */ 1945 public static final String BEAN_propertyNamer = PREFIX + ".propertyNamer.c"; 1946 1947 /** 1948 * Configuration property: Sort bean properties. 1949 * 1950 * <h5 class='section'>Property:</h5> 1951 * <ul class='spaced-list'> 1952 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_sortProperties BEAN_sortProperties} 1953 * <li><b>Name:</b> <js>"BeanContext.sortProperties.b"</js> 1954 * <li><b>Data type:</b> <jk>boolean</jk> 1955 * <li><b>System property:</b> <c>BeanContext.sortProperties</c> 1956 * <li><b>Environment variable:</b> <c>BEANCONTEXT_SORTPROPERTIES</c> 1957 * <li><b>Default:</b> <jk>false</jk> 1958 * <li><b>Session property:</b> <jk>false</jk> 1959 * <li><b>Annotations:</b> 1960 * <ul> 1961 * <li class='ja'>{@link org.apache.juneau.annotation.Bean#sort()} 1962 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#sortProperties()} 1963 * </ul> 1964 * <li><b>Methods:</b> 1965 * <ul> 1966 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#sortProperties()} 1967 * <li class='jm'>{@link org.apache.juneau.transform.BeanFilterBuilder#sortProperties(boolean)} 1968 * <li class='jm'>{@link org.apache.juneau.transform.BeanFilterBuilder#sortProperties()} 1969 * </ul> 1970 * </ul> 1971 * 1972 * <h5 class='section'>Description:</h5> 1973 * 1974 * <p> 1975 * When enabled, all bean properties will be serialized and access in alphabetical order. 1976 * Otherwise, the natural order of the bean properties is used which is dependent on the JVM vendor. 1977 * On IBM JVMs, the bean properties are ordered based on their ordering in the Java file. 1978 * On Oracle JVMs, the bean properties are not ordered (which follows the official JVM specs). 1979 * 1980 * <p> 1981 * This property is disabled by default so that IBM JVM users don't have to use {@link Bean @Bean} annotations 1982 * to force bean properties to be in a particular order and can just alter the order of the fields/methods 1983 * in the Java file. 1984 * 1985 * <h5 class='section'>Example:</h5> 1986 * <p class='bcode w800'> 1987 * <jc>// A bean with 3 properties.</jc> 1988 * <jk>public class</jk> MyBean { 1989 * <jk>public</jk> String <jf>c</jf> = <js>"1"</js>; 1990 * <jk>public</jk> String <jf>b</jf> = <js>"2"</js>; 1991 * <jk>public</jk> String <jf>a</jf> = <js>"3"</js>; 1992 * } 1993 * 1994 * <jc>// Create a serializer that sorts bean properties.</jc> 1995 * WriterSerializer s = JsonSerializer 1996 * .<jsm>create</jsm>() 1997 * .sortProperties() 1998 * .build(); 1999 * 2000 * <jc>// Same, but use property.</jc> 2001 * WriterSerializer s = JsonSerializer 2002 * .<jsm>create</jsm>() 2003 * .set(<jsf>BEAN_sortProperties</jsf>, <jk>true</jk>) 2004 * .build(); 2005 * 2006 * <jc>// Produces: {"a":"3","b":"2","c":"1"}</jc> 2007 * String json = s.serialize(<jk>new</jk> MyBean()); 2008 * </p> 2009 * 2010 * <ul class='notes'> 2011 * <li>The {@link Bean#sort() @Bean.sort()} annotation can also be used to sort properties on just a single class. 2012 * </ul> 2013 */ 2014 public static final String BEAN_sortProperties = PREFIX + ".sortProperties.b"; 2015 2016 /** 2017 * Configuration property: Java object swaps. 2018 * 2019 * <h5 class='section'>Property:</h5> 2020 * <ul class='spaced-list'> 2021 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_swaps BEAN_swaps} 2022 * <li><b>Name:</b> <js>"BeanContext.swaps.lo"</js> 2023 * <li><b>Data type:</b> <c>List<Object></c> 2024 * <li><b>Default:</b> empty list 2025 * <li><b>Session property:</b> <jk>false</jk> 2026 * <li><b>Annotations:</b> 2027 * <ul> 2028 * <li class='ja'>{@link org.apache.juneau.annotation.Swap} 2029 * <li class='ja'>{@link org.apache.juneau.annotation.Swaps} 2030 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#swaps()} 2031 * </ul> 2032 * <li><b>Methods:</b> 2033 * <ul> 2034 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#swaps(Object...)} 2035 * </ul> 2036 * </ul> 2037 * 2038 * <h5 class='section'>Description:</h5> 2039 * 2040 * <p> 2041 * Swaps are used to "swap out" non-serializable classes with serializable equivalents during serialization, 2042 * and "swap in" the non-serializable class during parsing. 2043 * 2044 * <p> 2045 * An example of a swap would be a <c>Calendar</c> object that gets swapped out for an ISO8601 string. 2046 * 2047 * <p> 2048 * Multiple swaps can be associated with a single class. 2049 * When multiple swaps are applicable to the same class, the media type pattern defined by 2050 * {@link PojoSwap#forMediaTypes()} or {@link Swap#mediaTypes() @Swap(mediaTypes)} are used to come up with the best match. 2051 * 2052 * <p> 2053 * Values can consist of any of the following types: 2054 * <ul> 2055 * <li>Any subclass of {@link PojoSwap}. 2056 * <li>Any instance of {@link PojoSwap}. 2057 * <li>Any surrogate class. A shortcut for defining a {@link SurrogateSwap}. 2058 * <li>Any array or collection of the objects above. 2059 * </ul> 2060 * 2061 * <h5 class='section'>Example:</h5> 2062 * <p class='bcode w800'> 2063 * <jc>// Sample swap for converting Dates to ISO8601 strings.</jc> 2064 * <jk>public class</jk> MyDateSwap <jk>extends</jk> StringSwap<Date> { 2065 * <jc>// ISO8601 formatter.</jc> 2066 * <jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>); 2067 * 2068 * <ja>@Override</ja> 2069 * <jk>public</jk> String swap(BeanSession session, Date o) { 2070 * <jk>return</jk> <jf>format</jf>.format(o); 2071 * } 2072 * 2073 * <ja>@Override</ja> 2074 * <jk>public</jk> Date unswap(BeanSession session, String o, ClassMeta hint) <jk>throws</jk> Exception { 2075 * <jk>return</jk> <jf>format</jf>.parse(o); 2076 * } 2077 * } 2078 * 2079 * <jc>// Sample bean with a Date field.</jc> 2080 * <jk>public class</jk> MyBean { 2081 * <jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6); 2082 * } 2083 * 2084 * <jc>// Create a serializer that uses our date swap.</jc> 2085 * WriterSerializer s = JsonSerializer 2086 * .<jsm>create</jsm>() 2087 * .swaps(MyDateSwap.<jk>class</jk>) 2088 * .build(); 2089 * 2090 * <jc>// Same, but use property.</jc> 2091 * WriterSerializer s = JsonSerializer 2092 * .<jsm>create</jsm>() 2093 * .addTo(<jsf>BEAN_swaps</jsf>, MyDateSwap.<jk>class</jk>) 2094 * .build(); 2095 * 2096 * <jc>// Produces: {"date":"2012-03-03T04:05:06-0500"}</jc> 2097 * String json = s.serialize(<jk>new</jk> MyBean()); 2098 * 2099 * <jc>// Create a serializer that uses our date swap.</jc> 2100 * ReaderParser p = JsonParser 2101 * .<jsm>create</jsm>() 2102 * .swaps(MyDateSwap.<jk>class</jk>) 2103 * .build(); 2104 * 2105 * <jc>// Use our parser to parse a bean.</jc> 2106 * MyBean bean = p.parse(json, MyBean.<jk>class</jk>); 2107 * </p> 2108 * 2109 * <ul class='notes'> 2110 * <li>The {@link Swap @Swap} annotation can also be used on classes to identify swaps for the class. 2111 * <li>The {@link Swap @Swap} annotation can also be used on bean methods and fields to identify swaps for values of those bean properties. 2112 * </ul> 2113 * 2114 * <ul class='seealso'> 2115 * <li class='link'>{@doc PojoSwaps} 2116 * <li class='link'>{@doc PerMediaTypePojoSwaps} 2117 * <li class='link'>{@doc OneWayPojoSwaps} 2118 * <li class='link'>{@doc SwapAnnotation} 2119 * <li class='link'>{@doc AutoPojoSwaps} 2120 * <li class='link'>{@doc SurrogateClasses} 2121 * </ul> 2122 */ 2123 public static final String BEAN_swaps = PREFIX + ".swaps.lo"; 2124 2125 /** 2126 * Configuration property: Add to swap classes. 2127 */ 2128 public static final String BEAN_swaps_add = PREFIX + ".swaps.lo/add"; 2129 2130 /** 2131 * Configuration property: Remove from swap classes. 2132 */ 2133 public static final String BEAN_swaps_remove = PREFIX + ".swaps.lo/remove"; 2134 2135 /** 2136 * Configuration property: Use enum names. 2137 * 2138 * <h5 class='section'>Property:</h5> 2139 * <ul class='spaced-list'> 2140 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_useEnumNames BEAN_useEnumNames} 2141 * <li><b>Name:</b> <js>"BeanContext.useEnumNames.b"</js> 2142 * <li><b>Data type:</b> <jk>boolean</jk> 2143 * <li><b>System property:</b> <c>BeanContext.useEnumNames</c> 2144 * <li><b>Environment variable:</b> <c>BEANCONTEXT_USEENUMNAMES</c> 2145 * <li><b>Default:</b> <jk>false</jk> 2146 * <li><b>Session property:</b> <jk>false</jk> 2147 * <li><b>Annotations:</b> 2148 * <ul> 2149 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#useEnumNames()} 2150 * </ul> 2151 * <li><b>Methods:</b> 2152 * <ul> 2153 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#useEnumNames()} 2154 * </ul> 2155 * </ul> 2156 * 2157 * <h5 class='section'>Description:</h5> 2158 * 2159 * <p> 2160 * When enabled, enums are always serialized by name, not using {@link Object#toString()}. 2161 * 2162 * <h5 class='section'>Example:</h5> 2163 * <p class='bcode w800'> 2164 * <jc>// Create a serializer with debug enabled.</jc> 2165 * WriterSerializer s = JsonSerializer 2166 * .<jsm>create</jsm>() 2167 * .useEnumNames() 2168 * .build(); 2169 * 2170 * <jc>// Same, but use property.</jc> 2171 * WriterSerializer s = JsonSerializer 2172 * .<jsm>create</jsm>() 2173 * .set(<jsf>BEAN_useEnumNames</jsf>, <jk>true</jk>) 2174 * .build(); 2175 * 2176 * <jc>// Enum with overridden toString().</jc> 2177 * <jc>// Will be serialized as ONE/TWO/THREE even though there's a toString() method.</jc> 2178 * <jk>public enum</jk> Option { 2179 * <jsf>ONE</jsf>(1), 2180 * <jsf>TWO</jsf>(2), 2181 * <jsf>THREE</jsf>(3); 2182 * 2183 * <jk>private int</jk> <jf>i</jf>; 2184 * 2185 * Option(<jk>int</jk> i) { 2186 * <jk>this</jk>.<jf>i</jf> = i; 2187 * } 2188 * 2189 * <ja>@Override</ja> 2190 * <jk>public</jk> String toString() { 2191 * <jk>return</jk> String.<jsm>valueOf</jsm>(<jf>i</jf>); 2192 * } 2193 * } 2194 * </p> 2195 */ 2196 public static final String BEAN_useEnumNames = PREFIX + ".useEnumNames.b"; 2197 2198 /** 2199 * Configuration property: Use interface proxies. 2200 * 2201 * <h5 class='section'>Property:</h5> 2202 * <ul class='spaced-list'> 2203 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_useInterfaceProxies BEAN_useInterfaceProxies} 2204 * <li><b>Name:</b> <js>"BeanContext.useInterfaceProxies.b"</js> 2205 * <li><b>Data type:</b> <jk>boolean</jk> 2206 * <li><b>System property:</b> <c>BeanContext.useInterfaceProxies</c> 2207 * <li><b>Environment variable:</b> <c>BEANCONTEXT_USEINTERFACEPROXIES</c> 2208 * <li><b>Default:</b> <jk>true</jk> 2209 * <li><b>Session property:</b> <jk>false</jk> 2210 * <li><b>Annotations:</b> 2211 * <ul> 2212 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#useInterfaceProxies()} 2213 * </ul> 2214 * <li><b>Methods:</b> 2215 * <ul> 2216 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#dontUseInterfaceProxies()} 2217 * </ul> 2218 * </ul> 2219 * 2220 * <h5 class='section'>Description:</h5> 2221 * 2222 * <p> 2223 * When enabled, interfaces will be instantiated as proxy classes through the use of an 2224 * {@link InvocationHandler} if there is no other way of instantiating them. 2225 * Otherwise, throws a {@link BeanRuntimeException}. 2226 * 2227 * <h5 class='section'>Example:</h5> 2228 * <p class='bcode w800'> 2229 * <jc>// An interface with a single getter.</jc> 2230 * <jk>public interface</jk> MyBean { 2231 * String getFoo(); 2232 * <jk>void</jk> setFoo(String foo); 2233 * } 2234 * 2235 * <jc>// Create a parser that uses interface proxies.</jc> 2236 * ReaderParser p = JsonParser 2237 * .<jsm>create</jsm>() 2238 * .build(); 2239 * 2240 * <jc>// Same, but use property.</jc> 2241 * ReaderParser p = JsonParser 2242 * .<jsm>create</jsm>() 2243 * .set(<jsf>BEAN_useInterfaceProxies</jsf>, <jk>true</jk>) 2244 * .build(); 2245 * 2246 * <jc>// Creates a proxy implementation of a MyBean interface.</jc> 2247 * MyBean b = p.parse(<js>"{foo:'bar'}"</js>, MyBean.<jk>class</jk>); 2248 * </p> 2249 */ 2250 public static final String BEAN_useInterfaceProxies = PREFIX + ".useInterfaceProxies.b"; 2251 2252 /** 2253 * Configuration property: Use Java Introspector. 2254 * 2255 * <h5 class='section'>Property:</h5> 2256 * <ul class='spaced-list'> 2257 * <li><b>ID:</b> {@link org.apache.juneau.BeanContext#BEAN_useJavaBeanIntrospector BEAN_useJavaBeanIntrospector} 2258 * <li><b>Name:</b> <js>"BeanContext.useJavaBeanIntrospector.b"</js> 2259 * <li><b>Data type:</b> <jk>boolean</jk> 2260 * <li><b>System property:</b> <c>BeanContext.useJavaBeanIntrospector</c> 2261 * <li><b>Environment variable:</b> <c>BEANCONTEXT_USEJAVABEANINTROSPECTOR</c> 2262 * <li><b>Default:</b> <jk>false</jk> 2263 * <li><b>Session property:</b> <jk>false</jk> 2264 * <li><b>Annotations:</b> 2265 * <ul> 2266 * <li class='ja'>{@link org.apache.juneau.annotation.BeanConfig#useJavaBeanIntrospector()} 2267 * </ul> 2268 * <li><b>Methods:</b> 2269 * <ul> 2270 * <li class='jm'>{@link org.apache.juneau.BeanContextBuilder#useJavaBeanIntrospector()} 2271 * </ul> 2272 * </ul> 2273 * 2274 * <h5 class='section'>Description:</h5> 2275 * 2276 * <p> 2277 * Using the built-in Java bean introspector will not pick up fields or non-standard getters/setters. 2278 * <br>Most {@link Bean @Bean} annotations will be ignored. 2279 * 2280 * <h5 class='section'>Example:</h5> 2281 * <p class='bcode w800'> 2282 * <jc>// Create a serializer that only uses the built-in java bean introspector for finding properties.</jc> 2283 * WriterSerializer s = JsonSerializer 2284 * .<jsm>create</jsm>() 2285 * .useJavaBeanIntrospector() 2286 * .build(); 2287 * 2288 * <jc>// Same, but use property.</jc> 2289 * WriterSerializer s = JsonSerializer 2290 * .<jsm>create</jsm>() 2291 * .set(<jsf>BEAN_useJavaBeanIntrospector</jsf>, <jk>true</jk>) 2292 * .build(); 2293 * </p> 2294 */ 2295 public static final String BEAN_useJavaBeanIntrospector = PREFIX + ".useJavaBeanIntrospector.b"; 2296 2297 /* 2298 * The default package pattern exclusion list. 2299 * Any beans in packages in this list will not be considered beans. 2300 */ 2301 private static final String[] DEFAULT_NOTBEAN_PACKAGES = { 2302 "java.lang", 2303 "java.lang.annotation", 2304 "java.lang.ref", 2305 "java.lang.reflect", 2306 "java.io", 2307 "java.net", 2308 "java.nio.*", 2309 "java.util.*" 2310 }; 2311 2312 /* 2313 * The default bean class exclusion list. 2314 * Anything in this list will not be considered beans. 2315 */ 2316 private static final Class<?>[] DEFAULT_NOTBEAN_CLASSES = { 2317 Map.class, 2318 Collection.class, 2319 Reader.class, 2320 Writer.class, 2321 InputStream.class, 2322 OutputStream.class, 2323 Throwable.class 2324 }; 2325 2326 2327 // This map is important! 2328 // We may have many Context objects that have identical BeanContext properties. 2329 // This map ensures that if the BeanContext properties in the Context are the same, 2330 // then we reuse the same Class->ClassMeta cache map. 2331 // This significantly reduces the number of times we need to construct ClassMeta objects which can be expensive. 2332 private static final ConcurrentHashMap<Integer,Map<Class,ClassMeta>> cmCacheCache 2333 = new ConcurrentHashMap<>(); 2334 2335 /** Default config. All default settings. */ 2336 public static final BeanContext DEFAULT = BeanContext.create().build(); 2337 2338 /** Default config. All default settings except sort bean properties. */ 2339 public static final BeanContext DEFAULT_SORTED = BeanContext.create().sortProperties().build(); 2340 2341 private final boolean 2342 beansRequireDefaultConstructor, 2343 beansRequireSerializable, 2344 beansRequireSettersForGetters, 2345 beansRequireSomeProperties, 2346 beanMapPutReturnsOldValue, 2347 useInterfaceProxies, 2348 ignoreUnknownBeanProperties, 2349 ignoreUnknownNullBeanProperties, 2350 ignorePropertiesWithoutSetters, 2351 ignoreTransientFields, 2352 ignoreInvocationExceptionsOnGetters, 2353 ignoreInvocationExceptionsOnSetters, 2354 useJavaBeanIntrospector, 2355 useEnumNames, 2356 sortProperties, 2357 fluentSetters; 2358 2359 private final Visibility 2360 beanConstructorVisibility, 2361 beanClassVisibility, 2362 beanMethodVisibility, 2363 beanFieldVisibility; 2364 2365 private final Class<?>[] notBeanClasses; 2366 private final List<Class<?>> beanDictionaryClasses; 2367 private final String[] notBeanPackageNames, notBeanPackagePrefixes; 2368 private final BeanFilter[] beanFilters; 2369 private final PojoSwap<?,?>[] swaps; 2370 private final Map<String,?> examples; 2371 private final BeanRegistry beanRegistry; 2372 private final Map<String,ClassInfo> implClasses; 2373 private final Map<String,Set<String>> bpi, bpx, bpro, bpwo; 2374 private final PropertyNamer propertyNamer; 2375 private final String typePropertyName; 2376 private final int beanHashCode; 2377 private final ReflectionMap<Annotation> annotations; 2378 2379 final Map<Class,ClassMeta> cmCache; 2380 private final ClassMeta<Object> cmObject; // Reusable ClassMeta that represents general Objects. 2381 private final ClassMeta<String> cmString; // Reusable ClassMeta that represents general Strings. 2382 private final ClassMeta<Class> cmClass; // Reusable ClassMeta that represents general Classes. 2383 2384 private volatile WriterSerializer beanToStringSerializer; 2385 2386 /** 2387 * Constructor. 2388 * 2389 * <p> 2390 * Typically only called from {@link ContextBuilder#build(Class)} method. 2391 * 2392 * @param ps The property store containing the unmodifiable configuration for this bean context. 2393 */ 2394 public BeanContext(PropertyStore ps) { 2395 super(ps, true); 2396 2397 if (ps == null) 2398 ps = PropertyStore.DEFAULT; 2399 2400 2401 ReflectionMap.Builder<Annotation> rmb = ReflectionMap.create(Annotation.class); 2402 for (Annotation a : ps.getListProperty(BEAN_annotations, Annotation.class)) { 2403 try { 2404 Method m = a.getClass().getMethod("on"); 2405 m.setAccessible(true); 2406 String on = (String)m.invoke(a); 2407 rmb.append(on, a); 2408 } catch (NoSuchMethodException e) { 2409 throw new ConfigException("Invalid annotation @{0} used in BEAN_annotations property. Annotation must define an on() method.", a.getClass().getSimpleName()); 2410 } catch (Exception e) { 2411 throw new ConfigException(e, "Invalid annotation @{0} used in BEAN_annotations property.", a.getClass().getName()); 2412 } 2413 } 2414 this.annotations = rmb.build(); 2415 2416 beanHashCode = ps.hashCode("BeanContext"); 2417 2418 beansRequireDefaultConstructor = getBooleanProperty(BEAN_beansRequireDefaultConstructor, false); 2419 beansRequireSerializable = getBooleanProperty(BEAN_beansRequireSerializable, false); 2420 beansRequireSettersForGetters = getBooleanProperty(BEAN_beansRequireSettersForGetters, false); 2421 beansRequireSomeProperties = getBooleanProperty(BEAN_beansRequireSomeProperties, true); 2422 beanMapPutReturnsOldValue = getBooleanProperty(BEAN_beanMapPutReturnsOldValue, false); 2423 useEnumNames = getBooleanProperty(BEAN_useEnumNames, false); 2424 useInterfaceProxies = getBooleanProperty(BEAN_useInterfaceProxies, true); 2425 ignoreUnknownBeanProperties = getBooleanProperty(BEAN_ignoreUnknownBeanProperties, false); 2426 ignoreUnknownNullBeanProperties = getBooleanProperty(BEAN_ignoreUnknownNullBeanProperties, true); 2427 ignorePropertiesWithoutSetters = getBooleanProperty(BEAN_ignorePropertiesWithoutSetters, true); 2428 ignoreTransientFields = getBooleanProperty(BEAN_ignoreTransientFields, true); 2429 ignoreInvocationExceptionsOnGetters = getBooleanProperty(BEAN_ignoreInvocationExceptionsOnGetters, false); 2430 ignoreInvocationExceptionsOnSetters = getBooleanProperty(BEAN_ignoreInvocationExceptionsOnSetters, false); 2431 useJavaBeanIntrospector = getBooleanProperty(BEAN_useJavaBeanIntrospector, false); 2432 sortProperties = getBooleanProperty(BEAN_sortProperties, false); 2433 fluentSetters = getBooleanProperty(BEAN_fluentSetters, false); 2434 typePropertyName = getStringProperty(BEAN_typePropertyName, "_type"); 2435 2436 beanConstructorVisibility = getProperty(BEAN_beanConstructorVisibility, Visibility.class, PUBLIC); 2437 beanClassVisibility = getProperty(BEAN_beanClassVisibility, Visibility.class, PUBLIC); 2438 beanMethodVisibility = getProperty(BEAN_beanMethodVisibility, Visibility.class, PUBLIC); 2439 beanFieldVisibility = getProperty(BEAN_beanFieldVisibility, Visibility.class, PUBLIC); 2440 2441 notBeanClasses = getClassArrayProperty(BEAN_notBeanClasses, DEFAULT_NOTBEAN_CLASSES); 2442 2443 propertyNamer = getInstanceProperty(BEAN_propertyNamer, PropertyNamer.class, PropertyNamerDefault.class); 2444 2445 List<String> l1 = new LinkedList<>(); 2446 List<String> l2 = new LinkedList<>(); 2447 for (String s : getArrayProperty(BEAN_notBeanPackages, String.class, DEFAULT_NOTBEAN_PACKAGES)) { 2448 if (s.endsWith(".*")) 2449 l2.add(s.substring(0, s.length()-2)); 2450 else 2451 l1.add(s); 2452 } 2453 notBeanPackageNames = l1.toArray(new String[l1.size()]); 2454 notBeanPackagePrefixes = l2.toArray(new String[l2.size()]); 2455 2456 LinkedList<BeanFilter> lbf = new LinkedList<>(); 2457 for (Object o : getListProperty(BEAN_beanFilters, Object[].class)) { 2458 ClassInfo ci = o instanceof Class ? ClassInfo.of((Class)o) : ClassInfo.of(o); 2459 if (ci.isChildOf(BeanFilter.class)) 2460 lbf.add(castOrCreate(BeanFilter.class, o)); 2461 else if (ci.isChildOf(BeanFilterBuilder.class)) 2462 lbf.add(castOrCreate(BeanFilterBuilder.class, o).build()); 2463 else if (o instanceof Class) 2464 lbf.add(new InterfaceBeanFilterBuilder((Class<?>)o, this).build()); 2465 } 2466 beanFilters = lbf.toArray(new BeanFilter[0]); 2467 2468 LinkedList<PojoSwap<?,?>> lpf = new LinkedList<>(); 2469 for (Object o : getListProperty(BEAN_pojoSwaps, Object.class)) { 2470 if (o instanceof Class) { 2471 ClassInfo ci = ClassInfo.of((Class<?>)o); 2472 if (ci.isChildOf(PojoSwap.class)) 2473 lpf.add(castOrCreate(PojoSwap.class, ci.inner())); 2474 else if (ci.isChildOf(Surrogate.class)) 2475 lpf.addAll(SurrogateSwap.findPojoSwaps(ci.inner(), this)); 2476 else 2477 throw new BasicRuntimeException("Invalid class {0} specified in BeanContext.pojoSwaps property. Must be a subclass of PojoSwap or Surrogate.", ci.inner()); 2478 } else if (o instanceof PojoSwap) { 2479 lpf.add((PojoSwap)o); 2480 } 2481 } 2482 for (Object o : getListProperty(BEAN_swaps, Object.class)) { 2483 if (o instanceof Class) { 2484 ClassInfo ci = ClassInfo.of((Class<?>)o); 2485 if (ci.isChildOf(PojoSwap.class)) 2486 lpf.add(castOrCreate(PojoSwap.class, ci.inner())); 2487 else if (ci.isChildOf(Surrogate.class)) 2488 lpf.addAll(SurrogateSwap.findPojoSwaps(ci.inner(), this)); 2489 else 2490 throw new BasicRuntimeException("Invalid class {0} specified in BeanContext.swaps property. Must be a subclass of PojoSwap or Surrogate.", ci.inner()); 2491 } else if (o instanceof PojoSwap) { 2492 lpf.add((PojoSwap)o); 2493 } 2494 } 2495 swaps = lpf.toArray(new PojoSwap[lpf.size()]); 2496 2497 examples = getMapProperty(BEAN_examples, Object.class); 2498 2499 AMap<String,ClassInfo> icm = AMap.of(); 2500 for (Map.Entry<String,Class<?>> e : getClassMapProperty(BEAN_implClasses).entrySet()) 2501 icm.put(e.getKey(), ClassInfo.of(e.getValue())); 2502 implClasses = icm.unmodifiable(); 2503 2504 AMap<String,Set<String>> m2 = AMap.of(); 2505 for (Map.Entry<String,String> e : getMapProperty(BEAN_bpi, String.class).entrySet()) 2506 m2.put(e.getKey(), ASet.of(split(e.getValue())).unmodifiable()); 2507 bpi = m2.unmodifiable(); 2508 2509 m2 = AMap.of(); 2510 for (Map.Entry<String,String> e : getMapProperty(BEAN_bpx, String.class).entrySet()) 2511 m2.put(e.getKey(), ASet.of(split(e.getValue())).unmodifiable()); 2512 bpx = m2.unmodifiable(); 2513 2514 m2 = AMap.of(); 2515 for (Map.Entry<String,String> e : getMapProperty(BEAN_bpro, String.class).entrySet()) 2516 m2.put(e.getKey(), ASet.of(split(e.getValue())).unmodifiable()); 2517 bpro = m2.unmodifiable(); 2518 2519 m2 = AMap.of(); 2520 for (Map.Entry<String,String> e : getMapProperty(BEAN_bpwo, String.class).entrySet()) 2521 m2.put(e.getKey(), ASet.of(split(e.getValue())).unmodifiable()); 2522 bpwo = m2.unmodifiable(); 2523 2524 2525 if (! cmCacheCache.containsKey(beanHashCode)) { 2526 ConcurrentHashMap<Class,ClassMeta> cm = new ConcurrentHashMap<>(); 2527 cm.putIfAbsent(String.class, new ClassMeta(String.class, this, null, null, findPojoSwaps(String.class), findChildPojoSwaps(String.class), findExample(String.class))); 2528 cm.putIfAbsent(Object.class, new ClassMeta(Object.class, this, null, null, findPojoSwaps(Object.class), findChildPojoSwaps(Object.class), findExample(Object.class))); 2529 cmCacheCache.putIfAbsent(beanHashCode, cm); 2530 } 2531 cmCache = cmCacheCache.get(beanHashCode); 2532 cmString = cmCache.get(String.class); 2533 cmObject = cmCache.get(Object.class); 2534 cmClass = cmCache.get(Class.class); 2535 2536 beanDictionaryClasses = AList.unmodifiable(getClassArrayProperty(BEAN_beanDictionary)); 2537 beanRegistry = new BeanRegistry(this, null); 2538 } 2539 2540 @Override /* Context */ 2541 public BeanContextBuilder builder() { 2542 return new BeanContextBuilder(getPropertyStore()); 2543 } 2544 2545 /** 2546 * Instantiates a new clean-slate {@link BeanContextBuilder} object. 2547 * 2548 * <p> 2549 * This is equivalent to simply calling <code><jk>new</jk> BeanContextBuilder()</code>. 2550 * 2551 * @return A new {@link JsonSerializerBuilder} object. 2552 */ 2553 public static BeanContextBuilder create() { 2554 return new BeanContextBuilder(); 2555 } 2556 2557 /** 2558 * Create a new bean session based on the properties defined on this context. 2559 * 2560 * <p> 2561 * Use this method for creating sessions if you don't need to override any 2562 * properties or locale/timezone currently set on this context. 2563 * 2564 * @return A new session object. 2565 */ 2566 @Override /* Context */ 2567 public BeanSession createSession() { 2568 return createBeanSession(createDefaultSessionArgs()); 2569 } 2570 2571 /** 2572 * Create a new bean session based on the properties defined on this context combined with the specified 2573 * runtime args. 2574 * 2575 * <p> 2576 * Use this method for creating sessions if you don't need to override any 2577 * properties or locale/timezone currently set on this context. 2578 * 2579 * @param args 2580 * The session arguments. 2581 * @return A new session object. 2582 */ 2583 public BeanSession createSession(BeanSessionArgs args) { 2584 return createBeanSession(args); 2585 } 2586 2587 @Override /* Context */ 2588 public final Session createSession(SessionArgs args) { 2589 throw new NoSuchMethodError(); 2590 } 2591 2592 /** 2593 * Same as {@link #createSession(BeanSessionArgs)} except always returns a {@link BeanSession} object unlike {@link #createSession(BeanSessionArgs)} 2594 * which is meant to be overridden by subclasses. 2595 * 2596 * @param args The session arguments. 2597 * @return A new session object. 2598 */ 2599 public final BeanSession createBeanSession(BeanSessionArgs args) { 2600 return new BeanSession(this, args); 2601 } 2602 2603 /** 2604 * Same as {@link #createSession()} except always returns a {@link BeanSession} object unlike {@link #createSession()} 2605 * which is meant to be overridden by subclasses. 2606 * 2607 * @return A new session object. 2608 */ 2609 public final BeanSession createBeanSession() { 2610 return new BeanSession(this, createDefaultBeanSessionArgs()); 2611 } 2612 2613 @Override /* Context */ 2614 public BeanSessionArgs createDefaultSessionArgs() { 2615 return createDefaultBeanSessionArgs(); 2616 } 2617 2618 /** 2619 * Same as {@link #createDefaultSessionArgs()} except always returns a {@link BeanSessionArgs} unlike 2620 * {@link #createDefaultBeanSessionArgs()} which is meant to be overridden by subclasses. 2621 * 2622 * @return A new session arguments object. 2623 */ 2624 public final BeanSessionArgs createDefaultBeanSessionArgs() { 2625 return new BeanSessionArgs(); 2626 } 2627 2628 /** 2629 * Returns <jk>true</jk> if the specified bean context shares the same cache as this bean context. 2630 * 2631 * <p> 2632 * Useful for testing purposes. 2633 * 2634 * @param bc The bean context to compare to. 2635 * @return <jk>true</jk> if the bean contexts have equivalent settings and thus share caches. 2636 */ 2637 public final boolean hasSameCache(BeanContext bc) { 2638 return bc.cmCache == this.cmCache; 2639 } 2640 2641 /** 2642 * Determines whether the specified class is ignored as a bean class based on the various exclusion parameters 2643 * specified on this context class. 2644 * 2645 * @param c The class type being tested. 2646 * @return <jk>true</jk> if the specified class matches any of the exclusion parameters. 2647 */ 2648 protected final boolean isNotABean(Class<?> c) { 2649 if (c.isArray() || c.isPrimitive() || c.isEnum() || c.isAnnotation()) 2650 return true; 2651 Package p = c.getPackage(); 2652 if (p != null) { 2653 for (String p2 : notBeanPackageNames) 2654 if (p.getName().equals(p2)) 2655 return true; 2656 for (String p2 : notBeanPackagePrefixes) 2657 if (p.getName().startsWith(p2)) 2658 return true; 2659 } 2660 ClassInfo ci = ClassInfo.of(c); 2661 for (Class exclude : notBeanClasses) 2662 if (ci.isChildOf(exclude)) 2663 return true; 2664 return false; 2665 } 2666 2667 /** 2668 * Returns <jk>true</jk> if the specified object is a bean. 2669 * 2670 * @param o The object to test. 2671 * @return <jk>true</jk> if the specified object is a bean. <jk>false</jk> if the bean is <jk>null</jk>. 2672 */ 2673 public boolean isBean(Object o) { 2674 if (o == null) 2675 return false; 2676 return getClassMetaForObject(o).isBean(); 2677 } 2678 2679 /** 2680 * Prints meta cache statistics to <c>System.out</c>. 2681 */ 2682 protected static void dumpCacheStats() { 2683 try { 2684 int ctCount = 0; 2685 for (Map<Class,ClassMeta> cm : cmCacheCache.values()) 2686 ctCount += cm.size(); 2687 System.out.println(format("ClassMeta cache: {0} instances in {1} caches", ctCount, cmCacheCache.size())); // NOT DEBUG 2688 } catch (Exception e) { 2689 e.printStackTrace(); 2690 } 2691 } 2692 2693 /** 2694 * Returns the {@link BeanMeta} class for the specified class. 2695 * 2696 * @param <T> The class type to get the meta-data on. 2697 * @param c The class to get the meta-data on. 2698 * @return 2699 * The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class is not a bean per the settings on 2700 * this context. 2701 */ 2702 public final <T> BeanMeta<T> getBeanMeta(Class<T> c) { 2703 if (c == null) 2704 return null; 2705 return getClassMeta(c).getBeanMeta(); 2706 } 2707 2708 /** 2709 * Construct a {@code ClassMeta} wrapper around a {@link Class} object. 2710 * 2711 * @param <T> The class type being wrapped. 2712 * @param type The class to resolve. 2713 * @return 2714 * If the class is not an array, returns a cached {@link ClassMeta} object. 2715 * Otherwise, returns a new {@link ClassMeta} object every time. 2716 */ 2717 public final <T> ClassMeta<T> getClassMeta(Class<T> type) { 2718 return getClassMeta(type, true); 2719 } 2720 2721 /** 2722 * Construct a {@code ClassMeta} wrapper around a {@link Class} object. 2723 * 2724 * @param <T> The class type being wrapped. 2725 * @param type The class to resolve. 2726 * @param waitForInit 2727 * When enabled, wait for the ClassMeta constructor to finish before returning. 2728 * @return 2729 * If the class is not an array, returns a cached {@link ClassMeta} object. 2730 * Otherwise, returns a new {@link ClassMeta} object every time. 2731 */ 2732 final <T> ClassMeta<T> getClassMeta(Class<T> type, boolean waitForInit) { 2733 2734 // This can happen if we have transforms defined against String or Object. 2735 if (cmCache == null) 2736 return null; 2737 2738 ClassMeta<T> cm = cmCache.get(type); 2739 if (cm == null) { 2740 2741 synchronized (this) { 2742 // Make sure someone didn't already set it while this thread was blocked. 2743 cm = cmCache.get(type); 2744 if (cm == null) 2745 cm = new ClassMeta<>(type, this, findImplClass(type), findBeanFilter(type), findPojoSwaps(type), findChildPojoSwaps(type), findExample(type)); 2746 } 2747 } 2748 if (waitForInit) 2749 cm.waitForInit(); 2750 return cm; 2751 } 2752 2753 /** 2754 * Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have 2755 * <c>ClassMeta</c> values that themselves could be collections or maps. 2756 * 2757 * <p> 2758 * <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the element type. 2759 * 2760 * <p> 2761 * <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value types. 2762 * 2763 * <p> 2764 * The array can be arbitrarily long to indicate arbitrarily complex data structures. 2765 * 2766 * <h5 class='section'>Examples:</h5> 2767 * <ul> 2768 * <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type. 2769 * <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects. 2770 * <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings. 2771 * <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing 2772 * strings. 2773 * <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - 2774 * A linked-list containing linked-lists of strings. 2775 * <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values. 2776 * <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map 2777 * containing string keys/values. 2778 * <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> - 2779 * A map containing string keys and values of lists containing beans. 2780 * </ul> 2781 * 2782 * @param type 2783 * The class to resolve. 2784 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 2785 * @param args 2786 * The type arguments of the class if it's a collection or map. 2787 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 2788 * <br>Ignored if the main type is not a map or collection. 2789 * @return The resolved class meta. 2790 */ 2791 public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) { 2792 if (type == null) 2793 return null; 2794 ClassMeta<T> cm = type instanceof Class ? getClassMeta((Class)type) : resolveClassMeta(type, null); 2795 if (args.length == 0) 2796 return cm; 2797 ClassMeta<?>[] cma = new ClassMeta[args.length+1]; 2798 cma[0] = cm; 2799 for (int i = 0; i < Array.getLength(args); i++) { 2800 Type arg = (Type)Array.get(args, i); 2801 cma[i+1] = arg instanceof Class ? getClassMeta((Class)arg) : resolveClassMeta(arg, null); 2802 } 2803 return (ClassMeta<T>) getTypedClassMeta(cma, 0); 2804 } 2805 2806 /* 2807 * Resolves the 'genericized' class meta at the specified position in the ClassMeta array. 2808 */ 2809 private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) { 2810 ClassMeta<?> cm = c[pos++]; 2811 if (cm.isCollection() || cm.isOptional()) { 2812 ClassMeta<?> ce = c.length == pos ? object() : getTypedClassMeta(c, pos); 2813 return (ce.isObject() ? cm : new ClassMeta(cm, null, null, ce)); 2814 } else if (cm.isMap()) { 2815 ClassMeta<?> ck = c.length == pos ? object() : c[pos++]; 2816 ClassMeta<?> cv = c.length == pos ? object() : getTypedClassMeta(c, pos); 2817 return (ck.isObject() && cv.isObject() ? cm : new ClassMeta(cm, ck, cv, null)); 2818 } 2819 return cm; 2820 } 2821 2822 final ClassMeta resolveClassMeta(Type o, Map<Class<?>,Class<?>[]> typeVarImpls) { 2823 if (o == null) 2824 return null; 2825 2826 if (o instanceof ClassMeta) { 2827 ClassMeta<?> cm = (ClassMeta)o; 2828 2829 // This classmeta could have been created by a different context. 2830 // Need to re-resolve it to pick up PojoSwaps and stuff on this context. 2831 if (cm.getBeanContext() == this) 2832 return cm; 2833 if (cm.isMap()) 2834 return getClassMeta(cm.innerClass, cm.getKeyType(), cm.getValueType()); 2835 if (cm.isCollection() || cm.isOptional()) 2836 return getClassMeta(cm.innerClass, cm.getElementType()); 2837 return getClassMeta(cm.innerClass); 2838 } 2839 2840 Class c = resolve(o, typeVarImpls); 2841 2842 // This can happen when trying to resolve the "E getFirst()" method on LinkedList, whose type is a TypeVariable 2843 // These should just resolve to Object. 2844 if (c == null) 2845 return object(); 2846 2847 ClassMeta rawType = getClassMeta(c); 2848 2849 // If this is a Map or Collection, and the parameter types aren't part 2850 // of the class definition itself (e.g. class AddressBook extends List<Person>), 2851 // then we need to figure out the parameters. 2852 if (rawType.isMap() || rawType.isCollection() || rawType.isOptional()) { 2853 ClassMeta[] params = findParameters(o, c); 2854 if (params == null) 2855 return rawType; 2856 if (rawType.isMap()) { 2857 if (params.length != 2) 2858 return rawType; 2859 if (params[0].isObject() && params[1].isObject()) 2860 return rawType; 2861 return new ClassMeta(rawType, params[0], params[1], null); 2862 } 2863 if (rawType.isCollection() || rawType.isOptional()) { 2864 if (params.length != 1) 2865 return rawType; 2866 if (params[0].isObject()) 2867 return rawType; 2868 return new ClassMeta(rawType, null, null, params[0]); 2869 } 2870 } 2871 2872 if (rawType.isArray()) { 2873 if (o instanceof GenericArrayType) { 2874 GenericArrayType gat = (GenericArrayType)o; 2875 ClassMeta elementType = resolveClassMeta(gat.getGenericComponentType(), typeVarImpls); 2876 return new ClassMeta(rawType, null, null, elementType); 2877 } 2878 } 2879 2880 return rawType; 2881 } 2882 2883 /** 2884 * Convert a Type to a Class if possible. 2885 * Return null if not possible. 2886 */ 2887 final Class resolve(Type t, Map<Class<?>,Class<?>[]> typeVarImpls) { 2888 2889 if (t instanceof Class) 2890 return (Class)t; 2891 2892 if (t instanceof ParameterizedType) 2893 // A parameter (e.g. <String>. 2894 return (Class)((ParameterizedType)t).getRawType(); 2895 2896 if (t instanceof GenericArrayType) { 2897 // An array parameter (e.g. <byte[]>). 2898 Type gatct = ((GenericArrayType)t).getGenericComponentType(); 2899 2900 if (gatct instanceof Class) 2901 return Array.newInstance((Class)gatct, 0).getClass(); 2902 2903 if (gatct instanceof ParameterizedType) 2904 return Array.newInstance((Class)((ParameterizedType)gatct).getRawType(), 0).getClass(); 2905 2906 if (gatct instanceof GenericArrayType) 2907 return Array.newInstance(resolve(gatct, typeVarImpls), 0).getClass(); 2908 2909 return null; 2910 2911 } else if (t instanceof TypeVariable) { 2912 if (typeVarImpls != null) { 2913 TypeVariable tv = (TypeVariable)t; 2914 String varName = tv.getName(); 2915 int varIndex = -1; 2916 Class gc = (Class)tv.getGenericDeclaration(); 2917 TypeVariable[] tvv = gc.getTypeParameters(); 2918 for (int i = 0; i < tvv.length; i++) { 2919 if (tvv[i].getName().equals(varName)) { 2920 varIndex = i; 2921 } 2922 } 2923 if (varIndex != -1) { 2924 2925 // If we couldn't find a type variable implementation, that means 2926 // the type was defined at runtime (e.g. Bean b = new Bean<Foo>();) 2927 // in which case the type is lost through erasure. 2928 // Assume java.lang.Object as the type. 2929 if (! typeVarImpls.containsKey(gc)) 2930 return null; 2931 2932 return typeVarImpls.get(gc)[varIndex]; 2933 } 2934 } 2935 } 2936 return null; 2937 } 2938 2939 final ClassMeta[] findParameters(Type o, Class c) { 2940 if (o == null) 2941 o = c; 2942 2943 // Loop until we find a ParameterizedType 2944 if (! (o instanceof ParameterizedType)) { 2945 loop: do { 2946 o = c.getGenericSuperclass(); 2947 if (o instanceof ParameterizedType) 2948 break loop; 2949 for (Type t : c.getGenericInterfaces()) { 2950 o = t; 2951 if (o instanceof ParameterizedType) 2952 break loop; 2953 } 2954 c = c.getSuperclass(); 2955 } while (c != null); 2956 } 2957 2958 if (o instanceof ParameterizedType) { 2959 ParameterizedType pt = (ParameterizedType)o; 2960 if (! pt.getRawType().equals(Enum.class)) { 2961 List<ClassMeta<?>> l = new LinkedList<>(); 2962 for (Type pt2 : pt.getActualTypeArguments()) { 2963 if (pt2 instanceof WildcardType || pt2 instanceof TypeVariable) 2964 return null; 2965 l.add(resolveClassMeta(pt2, null)); 2966 } 2967 if (l.isEmpty()) 2968 return null; 2969 return l.toArray(new ClassMeta[l.size()]); 2970 } 2971 } 2972 2973 return null; 2974 } 2975 2976 /** 2977 * Shortcut for calling {@code getClassMeta(o.getClass())}. 2978 * 2979 * @param <T> The class of the object being passed in. 2980 * @param o The class to find the class type for. 2981 * @return The ClassMeta object, or <jk>null</jk> if {@code o} is <jk>null</jk>. 2982 */ 2983 public final <T> ClassMeta<T> getClassMetaForObject(T o) { 2984 if (o == null) 2985 return null; 2986 return (ClassMeta<T>)getClassMeta(o.getClass()); 2987 } 2988 2989 2990 /** 2991 * Used for determining the class type on a method or field where a {@code @Beanp} annotation may be present. 2992 * 2993 * @param <T> The class type we're wrapping. 2994 * @param px The property annotation on the type if there is one. 2995 * @param p The property annotation on the type if there is one. 2996 * @param t The type. 2997 * @param typeVarImpls 2998 * Contains known resolved type parameters on the specified class so that we can result 2999 * {@code ParameterizedTypes} and {@code TypeVariables}. 3000 * Can be <jk>null</jk> if the information is not known. 3001 * @return The new {@code ClassMeta} object wrapped around the {@code Type} object. 3002 */ 3003 @SuppressWarnings("deprecation") 3004 protected final <T> ClassMeta<T> resolveClassMeta(BeanProperty px, Beanp p, Type t, Map<Class<?>,Class<?>[]> typeVarImpls) { 3005 ClassMeta<T> cm = resolveClassMeta(t, typeVarImpls); 3006 ClassMeta<T> cm2 = cm; 3007 if (px != null) { 3008 3009 if (px.type() != Object.class) 3010 cm2 = resolveClassMeta(px.type(), typeVarImpls); 3011 3012 if (cm2.isMap()) { 3013 Class<?>[] pParams = (px.params().length == 0 ? new Class[]{Object.class, Object.class} : px.params()); 3014 if (pParams.length != 2) 3015 throw new BasicRuntimeException("Invalid number of parameters specified for Map (must be 2): {0}", pParams.length); 3016 ClassMeta<?> keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType()); 3017 ClassMeta<?> valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType()); 3018 if (keyType.isObject() && valueType.isObject()) 3019 return cm2; 3020 return new ClassMeta<>(cm2, keyType, valueType, null); 3021 } 3022 3023 if (cm2.isCollection() || cm2.isOptional()) { 3024 Class<?>[] pParams = (px.params().length == 0 ? new Class[]{Object.class} : px.params()); 3025 if (pParams.length != 1) 3026 throw new BasicRuntimeException("Invalid number of parameters specified for "+(cm2.isCollection() ? "Collection" : cm2.isOptional() ? "Optional" : "Array")+" (must be 1): {0}", pParams.length); 3027 ClassMeta<?> elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType()); 3028 if (elementType.isObject()) 3029 return cm2; 3030 return new ClassMeta<>(cm2, null, null, elementType); 3031 } 3032 3033 return cm2; 3034 } 3035 3036 if (p != null) { 3037 3038 if (p.type() != Object.class) 3039 cm2 = resolveClassMeta(p.type(), typeVarImpls); 3040 3041 if (cm2.isMap()) { 3042 Class<?>[] pParams = (p.params().length == 0 ? new Class[]{Object.class, Object.class} : p.params()); 3043 if (pParams.length != 2) 3044 throw new BasicRuntimeException("Invalid number of parameters specified for Map (must be 2): {0}", pParams.length); 3045 ClassMeta<?> keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType()); 3046 ClassMeta<?> valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType()); 3047 if (keyType.isObject() && valueType.isObject()) 3048 return cm2; 3049 return new ClassMeta<>(cm2, keyType, valueType, null); 3050 } 3051 3052 if (cm2.isCollection() || cm2.isOptional()) { 3053 Class<?>[] pParams = (p.params().length == 0 ? new Class[]{Object.class} : p.params()); 3054 if (pParams.length != 1) 3055 throw new BasicRuntimeException("Invalid number of parameters specified for "+(cm2.isCollection() ? "Collection" : cm2.isOptional() ? "Optional" : "Array")+" (must be 1): {0}", pParams.length); 3056 ClassMeta<?> elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType()); 3057 if (elementType.isObject()) 3058 return cm2; 3059 return new ClassMeta<>(cm2, null, null, elementType); 3060 } 3061 3062 return cm2; 3063 } 3064 3065 return cm; 3066 } 3067 3068 private ClassMeta<?> resolveType(Type...t) { 3069 for (Type tt : t) { 3070 if (tt != null) { 3071 ClassMeta<?> cm = getClassMeta(tt); 3072 if (tt != cmObject) 3073 return cm; 3074 } 3075 } 3076 return cmObject; 3077 } 3078 3079 /** 3080 * Returns the {@link PojoSwap} associated with the specified class, or <jk>null</jk> if there is no POJO swap 3081 * associated with the class. 3082 * 3083 * @param <T> The class associated with the swap. 3084 * @param c The class associated with the swap. 3085 * @return The swap associated with the class, or null if there is no association. 3086 */ 3087 private final <T> PojoSwap[] findPojoSwaps(Class<T> c) { 3088 // Note: On first 3089 if (c != null) { 3090 List<PojoSwap> l = new ArrayList<>(); 3091 for (PojoSwap f : swaps) 3092 if (f.getNormalClass().isParentOf(c)) 3093 l.add(f); 3094 return l.size() == 0 ? null : l.toArray(new PojoSwap[l.size()]); 3095 } 3096 return null; 3097 } 3098 3099 private final Object findExample(Class<?> c) { 3100 if (c != null) { 3101 Object o = examples.get(c.getName()); 3102 if (o != null) 3103 return o; 3104 o = examples.get(c.getSimpleName()); 3105 if (o != null) 3106 return o; 3107 Class<?> c2 = findImplClass(c); 3108 if (c2 == null) 3109 return null; 3110 o = examples.get(c2.getName()); 3111 if (o != null) 3112 return o; 3113 o = examples.get(c2.getSimpleName()); 3114 return o; 3115 } 3116 return null; 3117 } 3118 3119 /** 3120 * Checks whether a class has a {@link PojoSwap} associated with it in this bean context. 3121 * 3122 * @param c The class to check. 3123 * @return <jk>true</jk> if the specified class or one of its subclasses has a {@link PojoSwap} associated with it. 3124 */ 3125 private final PojoSwap[] findChildPojoSwaps(Class<?> c) { 3126 if (c == null || swaps.length == 0) 3127 return null; 3128 List<PojoSwap> l = null; 3129 for (PojoSwap f : swaps) { 3130 if (f.getNormalClass().isChildOf(c)) { 3131 if (l == null) 3132 l = new ArrayList<>(); 3133 l.add(f); 3134 } 3135 } 3136 return l == null ? null : l.toArray(new PojoSwap[l.size()]); 3137 } 3138 3139 /** 3140 * Returns the {@link BeanFilter} associated with the specified class, or <jk>null</jk> if there is no bean filter 3141 * associated with the class. 3142 * 3143 * @param <T> The class associated with the bean filter. 3144 * @param c The class associated with the bean filter. 3145 * @return The bean filter associated with the class, or null if there is no association. 3146 */ 3147 private final <T> BeanFilter findBeanFilter(Class<T> c) { 3148 if (c != null) 3149 for (BeanFilter f : beanFilters) 3150 if (ClassInfo.of(f.getBeanClass()).isParentOf(c)) 3151 return f; 3152 return null; 3153 } 3154 3155 /** 3156 * Gets the no-arg constructor for the specified class. 3157 * 3158 * @param <T> The class to check. 3159 * @param c The class to check. 3160 * @param v The minimum visibility for the constructor. 3161 * @return The no arg constructor, or <jk>null</jk> if the class has no no-arg constructor. 3162 */ 3163 protected final <T> ConstructorInfo getImplClassConstructor(Class<T> c, Visibility v) { 3164 if (implClasses.isEmpty()) 3165 return null; 3166 Class cc = c; 3167 while (cc != null) { 3168 ClassInfo implClass = implClasses.get(cc.getName()); 3169 if (implClass != null) 3170 return implClass.getNoArgConstructor(v); 3171 for (Class ic : cc.getInterfaces()) { 3172 implClass = implClasses.get(ic.getName()); 3173 if (implClass != null) 3174 return implClass.getNoArgConstructor(v); 3175 } 3176 cc = cc.getSuperclass(); 3177 } 3178 return null; 3179 } 3180 3181 private final <T> Class<T> findImplClass(Class<T> c) { 3182 if (implClasses.isEmpty()) 3183 return null; 3184 Class cc = c; 3185 while (cc != null) { 3186 ClassInfo implClass = implClasses.get(cc.getName()); 3187 if (implClass != null) 3188 return implClass.<T>inner(); 3189 for (Class ic : cc.getInterfaces()) { 3190 implClass = implClasses.get(ic.getName()); 3191 if (implClass != null) 3192 return implClass.<T>inner(); 3193 } 3194 cc = cc.getSuperclass(); 3195 } 3196 return null; 3197 } 3198 3199 /** 3200 * Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>. 3201 * 3202 * <p> 3203 * This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known. 3204 * 3205 * <p> 3206 * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to 3207 * avoid a hashmap lookup. 3208 * 3209 * @return The {@link ClassMeta} object associated with the <c>Object</c> class. 3210 */ 3211 protected final ClassMeta<Object> object() { 3212 return cmObject; 3213 } 3214 3215 /** 3216 * Returns a reusable {@link ClassMeta} representation for the class <c>String</c>. 3217 * 3218 * <p> 3219 * This <c>ClassMeta</c> is often used to represent key types in maps. 3220 * 3221 * <p> 3222 * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to 3223 * avoid a hashmap lookup. 3224 * 3225 * @return The {@link ClassMeta} object associated with the <c>String</c> class. 3226 */ 3227 protected final ClassMeta<String> string() { 3228 return cmString; 3229 } 3230 3231 /** 3232 * Returns a reusable {@link ClassMeta} representation for the class <c>Class</c>. 3233 * 3234 * <p> 3235 * This <c>ClassMeta</c> is often used to represent key types in maps. 3236 * 3237 * <p> 3238 * This method is identical to calling <code>getClassMeta(Class.<jk>class</jk>)</code> but uses a cached copy to 3239 * avoid a hashmap lookup. 3240 * 3241 * @return The {@link ClassMeta} object associated with the <c>String</c> class. 3242 */ 3243 protected final ClassMeta<Class> _class() { 3244 return cmClass; 3245 } 3246 3247 /** 3248 * Returns the lookup table for resolving bean types by name. 3249 * 3250 * @return The lookup table for resolving bean types by name. 3251 */ 3252 protected final BeanRegistry getBeanRegistry() { 3253 return beanRegistry; 3254 } 3255 3256 //----------------------------------------------------------------------------------------------------------------- 3257 // MetaProvider methods 3258 //----------------------------------------------------------------------------------------------------------------- 3259 3260 private static final boolean DISABLE_ANNOTATION_CACHING = ! Boolean.getBoolean("juneau.disableAnnotationCaching"); 3261 3262 private TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,List<Annotation>> classAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING); 3263 private TwoKeyConcurrentCache<Class<?>,Class<? extends Annotation>,List<Annotation>> declaredClassAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING); 3264 private TwoKeyConcurrentCache<Method,Class<? extends Annotation>,List<Annotation>> methodAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING); 3265 private TwoKeyConcurrentCache<Field,Class<? extends Annotation>,List<Annotation>> fieldAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING); 3266 private TwoKeyConcurrentCache<Constructor<?>,Class<? extends Annotation>,List<Annotation>> constructorAnnotationCache = new TwoKeyConcurrentCache<>(DISABLE_ANNOTATION_CACHING); 3267 3268 /** 3269 * Finds the specified annotations on the specified class. 3270 * 3271 * @param <A> The annotation type to find. 3272 * @param a The annotation type to find. 3273 * @param c The class to search on. 3274 * @return The annotations in an unmodifiable list, or an empty list if not found. 3275 */ 3276 @Override /* MetaProvider */ 3277 public <A extends Annotation> List<A> getAnnotations(Class<A> a, Class<?> c) { 3278 if (a == null || c == null) 3279 return emptyList(); 3280 List<Annotation> aa = classAnnotationCache.get(c, a); 3281 if (aa == null) { 3282 A x = c.getAnnotation(a); 3283 AList<Annotation> l = new AList<>(x == null ? 0 : 1); 3284 l.aifnn(x); 3285 annotations.appendAll(c, a, l); 3286 aa = l.unmodifiable(); 3287 classAnnotationCache.put(c, a, aa); 3288 } 3289 return (List<A>)aa; 3290 } 3291 3292 /** 3293 * Finds the specified annotations on the specified class. 3294 * 3295 * @param <A> The annotation type to find. 3296 * @param a The annotation type to find. 3297 * @param c The class to search on. 3298 * @return The annotations in an unmodifiable list, or an empty list if not found. 3299 */ 3300 public <A extends Annotation> List<A> getAnnotations(Class<A> a, ClassInfo c) { 3301 return getAnnotations(a, c == null ? null : c.inner()); 3302 } 3303 3304 /** 3305 * Finds the last specified annotations on the specified class. 3306 * 3307 * @param <A> The annotation type to find. 3308 * @param a The annotation type to find. 3309 * @param c The class to search on. 3310 * @return The annotation, or <jk>null</jk> if not found. 3311 */ 3312 public <A extends Annotation> A getLastAnnotation(Class<A> a, Class<?> c) { 3313 return last(getAnnotations(a, c)); 3314 } 3315 3316 /** 3317 * Finds the last specified annotations on the specified class. 3318 * 3319 * @param <A> The annotation type to find. 3320 * @param a The annotation type to find. 3321 * @param c The class to search on. 3322 * @return The annotation, or <jk>null</jk> if not found. 3323 */ 3324 public <A extends Annotation> A getLastAnnotation(Class<A> a, ClassInfo c) { 3325 return last(getAnnotations(a, c)); 3326 } 3327 3328 /** 3329 * Finds the specified declared annotations on the specified class. 3330 * 3331 * @param <A> The annotation type to find. 3332 * @param a The annotation type to find. 3333 * @param c The class to search on. 3334 * @return The annotations in an unmodifiable list, or an empty list if not found. 3335 */ 3336 @Override /* MetaProvider */ 3337 public <A extends Annotation> List<A> getDeclaredAnnotations(Class<A> a, Class<?> c) { 3338 if (a == null || c == null) 3339 return emptyList(); 3340 List<Annotation> aa = declaredClassAnnotationCache.get(c, a); 3341 if (aa == null) { 3342 A x = c.getDeclaredAnnotation(a); 3343 AList<Annotation> l = new AList<>(x == null ? 0 : 1); 3344 l.aifnn(x); 3345 annotations.appendAll(c, a, l); 3346 aa = l.unmodifiable(); 3347 declaredClassAnnotationCache.put(c, a, aa); 3348 } 3349 return (List<A>)aa; 3350 } 3351 3352 /** 3353 * Finds the specified declared annotation on the specified class. 3354 * 3355 * @param <A> The annotation type to find. 3356 * @param a The annotation type to find. 3357 * @param c The class to search on. 3358 * @return The annotations in an unmodifiable list, or an empty list if not found. 3359 */ 3360 public <A extends Annotation> List<A> getDeclaredAnnotations(Class<A> a, ClassInfo c) { 3361 return getDeclaredAnnotations(a, c == null ? null : c.inner()); 3362 } 3363 3364 3365 /** 3366 * Finds the last specified declared annotations on the specified class. 3367 * 3368 * @param <A> The annotation type to find. 3369 * @param a The annotation type to find. 3370 * @param c The class to search on. 3371 * @return The annotation, or <jk>null</jk> if not found. 3372 */ 3373 public <A extends Annotation> A getLastDeclaredAnnotation(Class<A> a, Class<?> c) { 3374 return last(getDeclaredAnnotations(a, c)); 3375 } 3376 3377 /** 3378 * Finds the last specified declared annotations on the specified class. 3379 * 3380 * @param <A> The annotation type to find. 3381 * @param a The annotation type to find. 3382 * @param c The class to search on. 3383 * @return The annotation, or <jk>null</jk> if not found. 3384 */ 3385 public <A extends Annotation> A getLastDeclaredAnnotation(Class<A> a, ClassInfo c) { 3386 return last(getDeclaredAnnotations(a, c)); 3387 } 3388 3389 /** 3390 * Finds the specified annotations on the specified method. 3391 * 3392 * @param <A> The annotation type to find. 3393 * @param a The annotation type to find. 3394 * @param m The method to search on. 3395 * @return The annotations in an unmodifiable list, or an empty list if not found. 3396 */ 3397 @Override /* MetaProvider */ 3398 public <A extends Annotation> List<A> getAnnotations(Class<A> a, Method m) { 3399 if (a == null || m == null) 3400 return emptyList(); 3401 List<Annotation> aa = methodAnnotationCache.get(m, a); 3402 if (aa == null) { 3403 A x = m.getAnnotation(a); 3404 AList<Annotation> l = new AList<>(x == null ? 0 : 1); 3405 l.aifnn(x); 3406 annotations.appendAll(m, a, l); 3407 aa = l.unmodifiable(); 3408 methodAnnotationCache.put(m, a, aa); 3409 } 3410 return (List<A>)aa; 3411 } 3412 3413 /** 3414 * Finds the specified annotations on the specified method. 3415 * 3416 * @param <A> The annotation type to find. 3417 * @param a The annotation type to find. 3418 * @param m The method to search on. 3419 * @return The annotations in an unmodifiable list, or an empty list if not found. 3420 */ 3421 public <A extends Annotation> List<A> getAnnotations(Class<A> a, MethodInfo m) { 3422 return getAnnotations(a, m == null ? null : m.inner()); 3423 } 3424 3425 /** 3426 * Finds the last specified annotations on the specified method. 3427 * 3428 * @param <A> The annotation type to find. 3429 * @param a The annotation type to find. 3430 * @param m The method to search on. 3431 * @return The annotation, or <jk>null</jk> if not found. 3432 */ 3433 public <A extends Annotation> A getLastAnnotation(Class<A> a, Method m) { 3434 return last(getAnnotations(a, m)); 3435 } 3436 3437 /** 3438 * Finds the last specified annotations on the specified method. 3439 * 3440 * @param <A> The annotation type to find. 3441 * @param a The annotation type to find. 3442 * @param m The method to search on. 3443 * @return The annotation, or <jk>null</jk> if not found. 3444 */ 3445 public <A extends Annotation> A getLastAnnotation(Class<A> a, MethodInfo m) { 3446 return last(getAnnotations(a, m)); 3447 } 3448 3449 /** 3450 * Finds the specified annotations on the specified field. 3451 * 3452 * @param <A> The annotation type to find. 3453 * @param a The annotation type to find. 3454 * @param f The field to search on. 3455 * @return The annotations in an unmodifiable list, or an empty list if not found. 3456 */ 3457 @Override /* MetaProvider */ 3458 public <A extends Annotation> List<A> getAnnotations(Class<A> a, Field f) { 3459 if (a == null || f == null) 3460 return emptyList(); 3461 List<Annotation> aa = fieldAnnotationCache.get(f, a); 3462 if (aa == null) { 3463 A x = f.getAnnotation(a); 3464 AList<Annotation> l = new AList<>(x == null ? 0 : 1); 3465 l.aifnn(x); 3466 annotations.appendAll(f, a, l); 3467 aa = l.unmodifiable(); 3468 fieldAnnotationCache.put(f, a, aa); 3469 } 3470 return (List<A>)aa; 3471 } 3472 3473 /** 3474 * Finds the specified annotations on the specified field. 3475 * 3476 * @param <A> The annotation type to find. 3477 * @param a The annotation type to find. 3478 * @param f The field to search on. 3479 * @return The annotations in an unmodifiable list, or an empty list if not found. 3480 */ 3481 public <A extends Annotation> List<A> getAnnotations(Class<A> a, FieldInfo f) { 3482 return getAnnotations(a, f == null ? null: f.inner()); 3483 } 3484 3485 /** 3486 * Finds the last specified annotations on the specified field. 3487 * 3488 * @param <A> The annotation type to find. 3489 * @param a The annotation type to find. 3490 * @param f The field to search on. 3491 * @return The annotation, or <jk>null</jk> if not found. 3492 */ 3493 public <A extends Annotation> A getLastAnnotation(Class<A> a, Field f) { 3494 return last(getAnnotations(a, f)); 3495 } 3496 3497 /** 3498 * Finds the last specified annotations on the specified field. 3499 * 3500 * @param <A> The annotation type to find. 3501 * @param a The annotation type to find. 3502 * @param f The field to search on. 3503 * @return The annotation, or <jk>null</jk> if not found. 3504 */ 3505 public <A extends Annotation> A getLastAnnotation(Class<A> a, FieldInfo f) { 3506 return last(getAnnotations(a, f)); 3507 } 3508 3509 /** 3510 * Finds the specified annotations on the specified constructor. 3511 * 3512 * @param <A> The annotation type to find. 3513 * @param a The annotation type to find. 3514 * @param c The constructor to search on. 3515 * @return The annotations in an unmodifiable list, or an empty list if not found. 3516 */ 3517 @Override /* MetaProvider */ 3518 public <A extends Annotation> List<A> getAnnotations(Class<A> a, Constructor<?> c) { 3519 if (a == null || c == null) 3520 return emptyList(); 3521 List<Annotation> aa = constructorAnnotationCache.get(c, a); 3522 if (aa == null) { 3523 A x = c.getAnnotation(a); 3524 AList<Annotation> l = new AList(x == null ? 0 : 1); 3525 l.aifnn(x); 3526 annotations.appendAll(c, a, l); 3527 aa = l.unmodifiable(); 3528 constructorAnnotationCache.put(c, a, l); 3529 } 3530 return (List<A>)aa; 3531 } 3532 3533 /** 3534 * Finds the specified annotations on the specified constructor. 3535 * 3536 * @param <A> The annotation type to find. 3537 * @param a The annotation type to find. 3538 * @param c The constructor to search on. 3539 * @return The annotations in an unmodifiable list, or an empty list if not found. 3540 */ 3541 public <A extends Annotation> List<A> getAnnotations(Class<A> a, ConstructorInfo c) { 3542 return getAnnotations(a, c == null ? null : c.inner()); 3543 } 3544 3545 /** 3546 * Finds the last specified annotations on the specified constructor. 3547 * 3548 * @param <A> The annotation type to find. 3549 * @param a The annotation type to find. 3550 * @param c The constructor to search on. 3551 * @return The annotation, or <jk>null</jk> if not found. 3552 */ 3553 public <A extends Annotation> A getLastAnnotation(Class<A> a, Constructor<?> c) { 3554 return last(getAnnotations(a, c)); 3555 } 3556 3557 /** 3558 * Finds the last specified annotations on the specified constructor. 3559 * 3560 * @param <A> The annotation type to find. 3561 * @param a The annotation type to find. 3562 * @param c The constructor to search on. 3563 * @return The annotation, or <jk>null</jk> if not found. 3564 */ 3565 public <A extends Annotation> A getLastAnnotation(Class<A> a, ConstructorInfo c) { 3566 return last(getAnnotations(a, c)); 3567 } 3568 3569 /** 3570 * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value. 3571 * 3572 * @param a The annotation being checked for. 3573 * @param c The class being checked on. 3574 * @return <jk>true</jk> if the annotation exists on the specified class. 3575 */ 3576 public <A extends Annotation> boolean hasAnnotation(Class<A> a, Class<?> c) { 3577 return getAnnotations(a, c).size() > 0; 3578 } 3579 3580 /** 3581 * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value. 3582 * 3583 * @param a The annotation being checked for. 3584 * @param c The class being checked on. 3585 * @return <jk>true</jk> if the annotation exists on the specified class. 3586 */ 3587 public <A extends Annotation> boolean hasAnnotation(Class<A> a, ClassInfo c) { 3588 return getAnnotations(a, c == null ? null : c.inner()).size() > 0; 3589 } 3590 3591 /** 3592 * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value. 3593 * 3594 * @param a The annotation being checked for. 3595 * @param c The class being checked on. 3596 * @return <jk>true</jk> if the annotation exists on the specified class. 3597 */ 3598 public <A extends Annotation> boolean hasDeclaredAnnotation(Class<A> a, Class<?> c) { 3599 return getDeclaredAnnotations(a, c).size() > 0; 3600 } 3601 3602 /** 3603 * Returns <jk>true</jk> if <c>getDeclaredAnnotation(a,c)</c> returns a non-null value. 3604 * 3605 * @param a The annotation being checked for. 3606 * @param c The class being checked on. 3607 * @return <jk>true</jk> if the annotation exists on the specified class. 3608 */ 3609 public <A extends Annotation> boolean hasDeclaredAnnotation(Class<A> a, ClassInfo c) { 3610 return getDeclaredAnnotations(a, c == null ? null : c.inner()).size() > 0; 3611 } 3612 3613 /** 3614 * Returns <jk>true</jk> if <c>getAnnotation(a,m)</c> returns a non-null value. 3615 * 3616 * @param a The annotation being checked for. 3617 * @param m The method being checked on. 3618 * @return <jk>true</jk> if the annotation exists on the specified method. 3619 */ 3620 public <A extends Annotation> boolean hasAnnotation(Class<A> a, Method m) { 3621 return getAnnotations(a, m).size() > 0; 3622 } 3623 3624 /** 3625 * Returns <jk>true</jk> if <c>getAnnotation(a,m)</c> returns a non-null value. 3626 * 3627 * @param a The annotation being checked for. 3628 * @param m The method being checked on. 3629 * @return <jk>true</jk> if the annotation exists on the specified method. 3630 */ 3631 public <A extends Annotation> boolean hasAnnotation(Class<A> a, MethodInfo m) { 3632 return getAnnotations(a, m == null ? null : m.inner()).size() > 0; 3633 } 3634 3635 /** 3636 * Returns <jk>true</jk> if <c>getAnnotation(a,f)</c> returns a non-null value. 3637 * 3638 * @param a The annotation being checked for. 3639 * @param f The field being checked on. 3640 * @return <jk>true</jk> if the annotation exists on the specified field. 3641 */ 3642 public <A extends Annotation> boolean hasAnnotation(Class<A> a, Field f) { 3643 return getAnnotations(a, f).size() > 0; 3644 } 3645 3646 /** 3647 * Returns <jk>true</jk> if <c>getAnnotation(a,f)</c> returns a non-null value. 3648 * 3649 * @param a The annotation being checked for. 3650 * @param f The field being checked on. 3651 * @return <jk>true</jk> if the annotation exists on the specified field. 3652 */ 3653 public <A extends Annotation> boolean hasAnnotation(Class<A> a, FieldInfo f) { 3654 return getAnnotations(a, f == null ? null : f.inner()).size() > 0; 3655 } 3656 3657 /** 3658 * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value. 3659 * 3660 * @param a The annotation being checked for. 3661 * @param c The constructor being checked on. 3662 * @return <jk>true</jk> if the annotation exists on the specified constructor. 3663 */ 3664 public <A extends Annotation> boolean hasAnnotation(Class<A> a, Constructor<?> c) { 3665 return getAnnotations(a, c).size() > 0; 3666 } 3667 3668 /** 3669 * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value. 3670 * 3671 * @param a The annotation being checked for. 3672 * @param c The constructor being checked on. 3673 * @return <jk>true</jk> if the annotation exists on the specified constructor. 3674 */ 3675 public <A extends Annotation> boolean hasAnnotation(Class<A> a, ConstructorInfo c) { 3676 return getAnnotations(a, c == null ? null : c.inner()).size() > 0; 3677 } 3678 3679 //----------------------------------------------------------------------------------------------------------------- 3680 // Properties 3681 //----------------------------------------------------------------------------------------------------------------- 3682 3683 /** 3684 * Minimum bean class visibility. 3685 * 3686 * @see #BEAN_beanClassVisibility 3687 * @return 3688 * Classes are not considered beans unless they meet the minimum visibility requirements. 3689 */ 3690 public final Visibility getBeanClassVisibility() { 3691 return beanClassVisibility; 3692 } 3693 3694 /** 3695 * Minimum bean constructor visibility. 3696 * 3697 * @see #BEAN_beanConstructorVisibility 3698 * @return 3699 * Only look for constructors with this specified minimum visibility. 3700 */ 3701 public final Visibility getBeanConstructorVisibility() { 3702 return beanConstructorVisibility; 3703 } 3704 3705 /** 3706 * Bean dictionary. 3707 * 3708 * @see #BEAN_beanDictionary 3709 * @return 3710 * The list of classes that make up the bean dictionary in this bean context. 3711 */ 3712 protected final List<Class<?>> getBeanDictionaryClasses() { 3713 return beanDictionaryClasses; 3714 } 3715 3716 /** 3717 * Minimum bean field visibility. 3718 * 3719 * 3720 * @see #BEAN_beanFieldVisibility 3721 * @return 3722 * Only look for bean fields with this specified minimum visibility. 3723 */ 3724 public final Visibility getBeanFieldVisibility() { 3725 return beanFieldVisibility; 3726 } 3727 3728 /** 3729 * Bean filters. 3730 * 3731 * 3732 * @see BeanContext#BEAN_beanFilters 3733 * @return 3734 * Only look for bean fields with this specified minimum visibility. 3735 */ 3736 protected final BeanFilter[] getBeanFilters() { 3737 return beanFilters; 3738 } 3739 3740 /** 3741 * BeanMap.put() returns old property value. 3742 * 3743 * @see #BEAN_beanMapPutReturnsOldValue 3744 * @return 3745 * <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values. 3746 * <br>Otherwise, it returns <jk>null</jk>. 3747 */ 3748 protected final boolean isBeanMapPutReturnsOldValue() { 3749 return beanMapPutReturnsOldValue; 3750 } 3751 3752 /** 3753 * Minimum bean method visibility. 3754 * 3755 * @see #BEAN_beanMethodVisibility 3756 * @return 3757 * Only look for bean methods with this specified minimum visibility. 3758 */ 3759 public final Visibility getBeanMethodVisibility() { 3760 return beanMethodVisibility; 3761 } 3762 3763 /** 3764 * Beans require no-arg constructors. 3765 * 3766 * @see #BEAN_beansRequireDefaultConstructor 3767 * @return 3768 * <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean. 3769 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 3770 */ 3771 protected final boolean isBeansRequireDefaultConstructor() { 3772 return beansRequireDefaultConstructor; 3773 } 3774 3775 /** 3776 * Beans require Serializable interface. 3777 * 3778 * @see #BEAN_beansRequireSerializable 3779 * @return 3780 * <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean. 3781 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 3782 */ 3783 protected final boolean isBeansRequireSerializable() { 3784 return beansRequireSerializable; 3785 } 3786 3787 /** 3788 * Beans require setters for getters. 3789 * 3790 * @see #BEAN_beansRequireSettersForGetters 3791 * @return 3792 * <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean. 3793 * <br>Otherwise, they are ignored. 3794 */ 3795 protected final boolean isBeansRequireSettersForGetters() { 3796 return beansRequireSettersForGetters; 3797 } 3798 3799 /** 3800 * Beans require at least one property. 3801 * 3802 * @see #BEAN_beansRequireSomeProperties 3803 * @return 3804 * <jk>true</jk> if a Java class must contain at least 1 property to be considered a bean. 3805 * <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method. 3806 */ 3807 protected final boolean isBeansRequireSomeProperties() { 3808 return beansRequireSomeProperties; 3809 } 3810 3811 /** 3812 * Bean type property name. 3813 * 3814 * @see #BEAN_typePropertyName 3815 * @return 3816 * The name of the bean property used to store the dictionary name of a bean type so that the parser knows the data type to reconstruct. 3817 */ 3818 protected final String getBeanTypePropertyName() { 3819 return typePropertyName; 3820 } 3821 3822 /** 3823 * Bean property includes. 3824 * 3825 * @see #BEAN_bpi 3826 * @return 3827 * Include properties keyed by class name. 3828 */ 3829 protected final Map<String,Set<String>> getBpi() { 3830 return bpi; 3831 } 3832 3833 /** 3834 * Returns the {@link #BEAN_bpi} setting for the specified class. 3835 * 3836 * @param c The class. 3837 * @return The properties to include for the specified class, or an empty set if it's not defined for the class. 3838 */ 3839 protected Set<String> getBpi(Class<?> c) { 3840 if (bpi.isEmpty()) 3841 return emptySet(); 3842 ClassInfo ci = ClassInfo.of(c); 3843 for (ClassInfo c2 : ci.getAllParentsChildFirst()) { 3844 for (String n : c2.getNames()) { 3845 Set<String> s = bpi.get(n); 3846 if (s != null) 3847 return s; 3848 } 3849 } 3850 if (bpi.containsKey("*")) 3851 return bpi.get("*"); 3852 return emptySet(); 3853 } 3854 3855 /** 3856 * Bean property excludes. 3857 * 3858 * @see #BEAN_bpx 3859 * @return 3860 * The list of property names to exclude keyed by class name. 3861 */ 3862 protected final Map<String,Set<String>> getBpx() { 3863 return bpx; 3864 } 3865 3866 /** 3867 * Returns the {@link #BEAN_bpx} setting for the specified class. 3868 * 3869 * @param c The class. 3870 * @return The properties to exclude for the specified class, or an empty set if it's not defined for the class. 3871 */ 3872 protected Set<String> getBpx(Class<?> c) { 3873 if (bpx.isEmpty()) 3874 return emptySet(); 3875 ClassInfo ci = ClassInfo.of(c); 3876 for (ClassInfo c2 : ci.getAllParentsChildFirst()) { 3877 for (String n : c2.getNames()) { 3878 Set<String> s = bpx.get(n); 3879 if (s != null) 3880 return s; 3881 } 3882 } 3883 if (bpx.containsKey("*")) 3884 return bpx.get("*"); 3885 return emptySet(); 3886 } 3887 3888 /** 3889 * Read-only bean properties. 3890 * 3891 * @see #BEAN_bpro 3892 * @return 3893 * The list of read-only property names keyed by class name. 3894 */ 3895 protected final Map<String,Set<String>> getBpro() { 3896 return bpro; 3897 } 3898 3899 /** 3900 * Returns the {@link #BEAN_bpro} setting for the specified class. 3901 * 3902 * @param c The class. 3903 * @return The read-only properties for the specified class, or an empty set if it's not defined for the class. 3904 */ 3905 protected Set<String> getBpro(Class<?> c) { 3906 if (bpro.isEmpty()) 3907 return emptySet(); 3908 ClassInfo ci = ClassInfo.of(c); 3909 for (ClassInfo c2 : ci.getAllParentsChildFirst()) { 3910 for (String n : c2.getNames()) { 3911 Set<String> s = bpro.get(n); 3912 if (s != null) 3913 return s; 3914 } 3915 } 3916 if (bpro.containsKey("*")) 3917 return bpro.get("*"); 3918 return emptySet(); 3919 } 3920 3921 /** 3922 * Write-only bean properties. 3923 * 3924 * @see #BEAN_bpwo 3925 * @return 3926 * The list of write-only property names keyed by class name. 3927 */ 3928 protected final Map<String,Set<String>> getBpwo() { 3929 return bpwo; 3930 } 3931 3932 /** 3933 * Returns the {@link #BEAN_bpwo} setting for the specified class. 3934 * 3935 * @param c The class. 3936 * @return The write-only properties for the specified class, or an empty set if it's not defined for the class. 3937 */ 3938 protected Set<String> getBpwo(Class<?> c) { 3939 if (bpwo.isEmpty()) 3940 return emptySet(); 3941 ClassInfo ci = ClassInfo.of(c); 3942 for (ClassInfo c2 : ci.getAllParentsChildFirst()) { 3943 for (String n : c2.getNames()) { 3944 Set<String> s = bpwo.get(n); 3945 if (s != null) 3946 return s; 3947 } 3948 } 3949 if (bpwo.containsKey("*")) 3950 return bpwo.get("*"); 3951 return emptySet(); 3952 } 3953 3954 3955 /** 3956 * POJO examples. 3957 * 3958 * @see #BEAN_examples 3959 * @return 3960 * A map of POJO examples keyed by class name. 3961 */ 3962 protected final Map<String,?> getExamples() { 3963 return examples; 3964 } 3965 3966 /** 3967 * Find fluent setters. 3968 * 3969 * <h5 class='section'>Description:</h5> 3970 * <p> 3971 * 3972 * @see #BEAN_fluentSetters 3973 * @return 3974 * <jk>true</jk> if fluent setters are detected on beans. 3975 */ 3976 protected final boolean isFluentSetters() { 3977 return fluentSetters; 3978 } 3979 3980 /** 3981 * Ignore invocation errors on getters. 3982 * 3983 * @see #BEAN_ignoreInvocationExceptionsOnGetters 3984 * @return 3985 * <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored. 3986 */ 3987 protected final boolean isIgnoreInvocationExceptionsOnGetters() { 3988 return ignoreInvocationExceptionsOnGetters; 3989 } 3990 3991 /** 3992 * Ignore invocation errors on setters. 3993 * 3994 * @see #BEAN_ignoreInvocationExceptionsOnSetters 3995 * @return 3996 * <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored. 3997 */ 3998 protected final boolean isIgnoreInvocationExceptionsOnSetters() { 3999 return ignoreInvocationExceptionsOnSetters; 4000 } 4001 4002 /** 4003 * Ignore properties without setters. 4004 * 4005 * @see #BEAN_ignorePropertiesWithoutSetters 4006 * @return 4007 * <jk>true</jk> if trying to set a value on a bean property without a setter is silently ignored. 4008 */ 4009 protected final boolean isIgnorePropertiesWithoutSetters() { 4010 return ignorePropertiesWithoutSetters; 4011 } 4012 4013 /** 4014 * Ignore transient fields. 4015 * 4016 * @see #BEAN_ignoreTransientFields 4017 * @return 4018 * <jk>true</jk> if fields and methods marked as transient should be ignored. 4019 */ 4020 protected final boolean isIgnoreTransientFields() { 4021 return ignoreTransientFields; 4022 } 4023 4024 /** 4025 * Ignore unknown properties. 4026 * 4027 * @see #BEAN_ignoreUnknownBeanProperties 4028 * @return 4029 * <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored. 4030 * <br>Otherwise, a {@code RuntimeException} is thrown. 4031 */ 4032 protected final boolean isIgnoreUnknownBeanProperties() { 4033 return ignoreUnknownBeanProperties; 4034 } 4035 4036 /** 4037 * Ignore unknown properties with null values. 4038 * 4039 * @see #BEAN_ignoreUnknownNullBeanProperties 4040 * @return 4041 * <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property is silently ignored. 4042 */ 4043 protected final boolean isIgnoreUnknownNullBeanProperties() { 4044 return ignoreUnknownNullBeanProperties; 4045 } 4046 4047 /** 4048 * Implementation classes. 4049 * 4050 * @see #BEAN_implClasses 4051 * @return 4052 * Implementation classes keyed by interface class names. 4053 */ 4054 protected final Map<String,ClassInfo> getImplClasses() { 4055 return implClasses; 4056 } 4057 4058 /** 4059 * Bean class exclusions. 4060 * 4061 * @see #BEAN_notBeanClasses 4062 * @return 4063 * The list of classes that are explicitly not beans. 4064 */ 4065 protected final Class<?>[] getNotBeanClasses() { 4066 return notBeanClasses; 4067 } 4068 4069 /** 4070 * Bean package exclusions. 4071 * 4072 * @see #BEAN_notBeanPackages 4073 * @return 4074 * The list of fully-qualified package names to exclude from being classified as beans. 4075 */ 4076 protected final String[] getNotBeanPackagesNames() { 4077 return notBeanPackageNames; 4078 } 4079 4080 /** 4081 * Bean package exclusions. 4082 * 4083 * @see #BEAN_notBeanPackages 4084 * @return 4085 * The list of package name prefixes to exclude from being classified as beans. 4086 */ 4087 protected final String[] getNotBeanPackagesPrefixes() { 4088 return notBeanPackagePrefixes; 4089 } 4090 4091 /** 4092 * Java object swaps. 4093 * 4094 * @see #BEAN_swaps 4095 * @return 4096 * The list POJO swaps defined. 4097 */ 4098 protected final PojoSwap<?,?>[] getSwaps() { 4099 return swaps; 4100 } 4101 4102 /** 4103 * Bean property namer. 4104 * 4105 * @see #BEAN_propertyNamer 4106 * @return 4107 * The interface used to calculate bean property names. 4108 */ 4109 protected final PropertyNamer getPropertyNamer() { 4110 return propertyNamer; 4111 } 4112 4113 /** 4114 * Sort bean properties. 4115 * 4116 * @see #BEAN_sortProperties 4117 * @return 4118 * <jk>true</jk> if all bean properties will be serialized and access in alphabetical order. 4119 */ 4120 protected final boolean isSortProperties() { 4121 return sortProperties; 4122 } 4123 4124 /** 4125 * Use enum names. 4126 * 4127 * @see #BEAN_useEnumNames 4128 * @return 4129 * <jk>true</jk> if enums are always serialized by name, not using {@link Object#toString()}. 4130 */ 4131 protected final boolean isUseEnumNames() { 4132 return useEnumNames; 4133 } 4134 4135 /** 4136 * Use interface proxies. 4137 * 4138 * @see #BEAN_useInterfaceProxies 4139 * @return 4140 * <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an 4141 * {@link InvocationHandler} if there is no other way of instantiating them. 4142 */ 4143 protected final boolean isUseInterfaceProxies() { 4144 return useInterfaceProxies; 4145 } 4146 4147 /** 4148 * Use Java Introspector. 4149 * 4150 * @see #BEAN_useJavaBeanIntrospector 4151 * @return 4152 * <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection. 4153 */ 4154 protected final boolean isUseJavaBeanIntrospector() { 4155 return useJavaBeanIntrospector; 4156 } 4157 4158 /** 4159 * Returns the serializer to use for serializing beans when using the {@link BeanSession#convertToType(Object, Class)} 4160 * and related methods. 4161 * 4162 * @return The serializer. May be <jk>null</jk> if all initialization has occurred. 4163 */ 4164 protected WriterSerializer getBeanToStringSerializer() { 4165 if (beanToStringSerializer == null) { 4166 if (JsonSerializer.DEFAULT == null) 4167 return null; 4168 this.beanToStringSerializer = JsonSerializer.create().apply(this.getPropertyStore()).sq().simple().build(); 4169 } 4170 return beanToStringSerializer; 4171 } 4172 4173 //----------------------------------------------------------------------------------------------------------------- 4174 // Other methods 4175 //----------------------------------------------------------------------------------------------------------------- 4176 4177 @Override /* Context */ 4178 public OMap toMap() { 4179 return super.toMap() 4180 .a("BeanContext", new DefaultFilteringOMap() 4181 .a("id", System.identityHashCode(this)) 4182 .a("beanClassVisibility", beanClassVisibility) 4183 .a("beanConstructorVisibility", beanConstructorVisibility) 4184 .a("beanDictionaryClasses", beanDictionaryClasses) 4185 .a("beanFieldVisibility", beanFieldVisibility) 4186 .a("beanFilters", beanFilters) 4187 .a("beanMapPutReturnsOldValue", beanMapPutReturnsOldValue) 4188 .a("beanMethodVisibility", beanMethodVisibility) 4189 .a("beansRequireDefaultConstructor", beansRequireDefaultConstructor) 4190 .a("beansRequireSerializable", beansRequireSerializable) 4191 .a("beansRequireSettersForGetters", beansRequireSettersForGetters) 4192 .a("beansRequireSomeProperties", beansRequireSomeProperties) 4193 .a("bpi", bpi) 4194 .a("bpx", bpx) 4195 .a("ignoreInvocationExceptionsOnGetters", ignoreInvocationExceptionsOnGetters) 4196 .a("ignoreInvocationExceptionsOnSetters", ignoreInvocationExceptionsOnSetters) 4197 .a("ignorePropertiesWithoutSetters", ignorePropertiesWithoutSetters) 4198 .a("ignoreTransientProperties", ignoreTransientFields) 4199 .a("ignoreUnknownBeanProperties", ignoreUnknownBeanProperties) 4200 .a("ignoreUnknownNullBeanProperties", ignoreUnknownNullBeanProperties) 4201 .a("implClasses", implClasses) 4202 .a("notBeanClasses", notBeanClasses) 4203 .a("notBeanPackageNames", notBeanPackageNames) 4204 .a("notBeanPackagePrefixes", notBeanPackagePrefixes) 4205 .a("pojoSwaps", swaps) 4206 .a("sortProperties", sortProperties) 4207 .a("useEnumNames", useEnumNames) 4208 .a("useInterfaceProxies", useInterfaceProxies) 4209 .a("useJavaBeanIntrospector", useJavaBeanIntrospector) 4210 ); 4211 } 4212}