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.reflect.*; 022import java.util.*; 023import java.util.concurrent.*; 024 025import org.apache.juneau.annotation.*; 026import org.apache.juneau.http.*; 027import org.apache.juneau.internal.*; 028import org.apache.juneau.json.*; 029import org.apache.juneau.reflect.*; 030import org.apache.juneau.serializer.*; 031import org.apache.juneau.transform.*; 032 033/** 034 * Core class of the Juneau architecture. 035 * 036 * <p> 037 * This class servers multiple purposes: 038 * <ul class='spaced-list'> 039 * <li> 040 * Provides the ability to wrap beans inside {@link Map} interfaces. 041 * <li> 042 * Serves as a repository for metadata on POJOs, such as associated {@link BeanFilter BeanFilters}, 043 * {@link PropertyNamer PropertyNamers}, etc... which are used to tailor how POJOs are serialized and parsed. 044 * </ul> 045 * 046 * <p> 047 * All serializers and parsers extend from this context so that they can handle POJOs using a common framework. 048 * 049 * <h5 class='topic'>Bean Contexts</h5> 050 * 051 * Bean contexts are created through the {@link BeanContext#create() BeanContext.create()} and {@link BeanContextBuilder#build()} methods. 052 * <br>These context objects are read-only, reusable, and thread-safe. 053 * 054 * <p> 055 * Each bean context maintains a cache of {@link ClassMeta} objects that describe information about classes encountered. 056 * These <c>ClassMeta</c> objects are time-consuming to construct. 057 * Therefore, instances of {@link BeanContext} that share the same <js>"BeanContext.*"</js> property values share 058 * the same cache. This allows for efficient reuse of <c>ClassMeta</c> objects so that the information about 059 * classes only needs to be calculated once. 060 * Because of this, many of the properties defined on the {@link BeanContext} class cannot be overridden on the session. 061 * 062 * <h5 class='topic'>Bean Sessions</h5> 063 * 064 * Whereas <c>BeanContext</c> objects are permanent, unchangeable, cached, and thread-safe, 065 * {@link BeanSession} objects are ephemeral and not thread-safe. 066 * They are meant to be used as quickly-constructed scratchpads for creating bean maps. 067 * {@link BeanMap} objects can only be created through the session. 068 * 069 * <h5 class='topic'>BeanContext configuration properties</h5> 070 * 071 * <c>BeanContexts</c> have several configuration properties that can be used to tweak behavior on how beans are 072 * handled. These are denoted as the static <jsf>BEAN_*</jsf> fields on this class. 073 * 074 * <p> 075 * Some settings (e.g. {@link #BEAN_beansRequireDefaultConstructor}) are used to differentiate between bean 076 * and non-bean classes. 077 * Attempting to create a bean map around one of these objects will throw a {@link BeanRuntimeException}. 078 * The purpose for this behavior is so that the serializers can identify these non-bean classes and convert them to 079 * plain strings using the {@link Object#toString()} method. 080 * 081 * <p> 082 * Some settings (e.g. {@link #BEAN_beanFieldVisibility}) are used to determine what kinds of properties are 083 * detected on beans. 084 * 085 * <p> 086 * Some settings (e.g. {@link #BEAN_beanMapPutReturnsOldValue}) change the runtime behavior of bean maps. 087 * 088 * <p> 089 * Settings are specified using the {@link BeanContextBuilder#set(String, Object)} method and related convenience 090 * methods. 091 * 092 * <h5 class='section'>Example:</h5> 093 * 094 * <p class='bcode w800'> 095 * <jc>// Construct a context from scratch.</jc> 096 * BeanContext beanContext = BeanContext 097 * .<jsm>create</jsm>() 098 * .set(BeanContext.<jsf>BEAN_beansRequireDefaultConstructor</jsf>, <jk>true</jk>) 099 * .notBeanClasses(Foo.<jk>class</jk>) 100 * .build(); 101 * </p> 102 * 103 * <h5 class='topic'>Bean Maps</h5> 104 * 105 * {@link BeanMap BeanMaps} are wrappers around Java beans that allow properties to be retrieved and 106 * set using the common {@link Map#put(Object,Object)} and {@link Map#get(Object)} methods. 107 * 108 * <p> 109 * Bean maps are created in two ways... 110 * <ol> 111 * <li>{@link BeanSession#toBeanMap(Object) BeanSession.toBeanMap()} - Wraps an existing bean inside a {@code Map} 112 * wrapper. 113 * <li>{@link BeanSession#newBeanMap(Class) BeanSession.newBeanMap()} - Create a new bean instance wrapped in a 114 * {@code Map} wrapper. 115 * </ol> 116 * 117 * <h5 class='section'>Example:</h5> 118 * 119 * <p class='bcode w800'> 120 * <jc>// A sample bean class</jc> 121 * <jk>public class</jk> Person { 122 * <jk>public</jk> String getName(); 123 * <jk>public void</jk> setName(String name); 124 * <jk>public int</jk> getAge(); 125 * <jk>public void</jk> setAge(<jk>int</jk> age); 126 * } 127 * 128 * <jc>// Create a new bean session</jc> 129 * BeanSession session = BeanContext.<jsf>DEFAULT</jsf>.createSession(); 130 * 131 * <jc>// Wrap an existing bean in a new bean map</jc> 132 * BeanMap<Person> m1 = session.toBeanMap(<jk>new</jk> Person()); 133 * m1.put(<js>"name"</js>, <js>"John Smith"</js>); 134 * m1.put(<js>"age"</js>, 45); 135 * 136 * <jc>// Create a new bean instance wrapped in a new bean map</jc> 137 * BeanMap<Person> m2 = session.newBeanMap(Person.<jk>class</jk>); 138 * m2.put(<js>"name"</js>, <js>"John Smith"</js>); 139 * m2.put(<js>"age"</js>, 45); 140 * Person p = m2.getBean(); <jc>// Get the bean instance that was created.</jc> 141 * </p> 142 * 143 * <ul class='seealso'> 144 * <li class='link'>{@doc juneau-marshall.ContextsBuildersSessionsPropertyStores} 145 * </ul> 146 */ 147@SuppressWarnings({"unchecked","rawtypes"}) 148@ConfigurableContext 149public class BeanContext extends Context { 150 151 static final String PREFIX = "BeanContext"; 152 153 /** 154 * Configuration property: Minimum bean class visibility. 155 * 156 * <h5 class='section'>Property:</h5> 157 * <ul> 158 * <li><b>Name:</b> <js>"BeanContext.beanClassVisibility.s"</js> 159 * <li><b>Data type:</b> <c>String</c> ({@link Visibility}) 160 * <li><b>Default:</b> <js>"PUBLIC"</js> 161 * <li><b>Session property:</b> <jk>false</jk> 162 * <li><b>Methods:</b> 163 * <ul> 164 * <li class='jm'>{@link BeanContextBuilder#beanClassVisibility(Visibility)} 165 * </ul> 166 * </ul> 167 * 168 * <h5 class='section'>Description:</h5> 169 * <p> 170 * Classes are not considered beans unless they meet the minimum visibility requirements. 171 * 172 * <p> 173 * For example, if the visibility is <c>PUBLIC</c> and the bean class is <jk>protected</jk>, then the class 174 * will not be interpreted as a bean class and be serialized as a string. 175 * <br>Use this setting to reduce the visibility requirement. 176 * 177 * <h5 class='section'>Example:</h5> 178 * <p class='bcode w800'> 179 * <jc>// Create a serializer that serializes protected classes.</jc> 180 * WriterSerializer s = JsonSerializer 181 * .<jsm>create</jsm>() 182 * .beanClassVisibility(<jsf>PROTECTED</jsf>) 183 * .build(); 184 * 185 * <jc>// Same, but use property.</jc> 186 * WriterSerializer s = JsonSerializer 187 * .<jsm>create</jsm>() 188 * .set(<jsf>BEAN_beanClassVisibility</jsf>, <js>"PROTECTED"</js>) 189 * .build(); 190 * </p> 191 */ 192 public static final String BEAN_beanClassVisibility = PREFIX + ".beanClassVisibility.s"; 193 194 /** 195 * Configuration property: Minimum bean constructor visibility. 196 * 197 * <h5 class='section'>Property:</h5> 198 * <ul> 199 * <li><b>Name:</b> <js>"BeanContext.beanConstructorVisibility.s"</js> 200 * <li><b>Data type:</b> <c>String</c> ({@link Visibility}) 201 * <li><b>Default:</b> <js>"PUBLIC"</js> 202 * <li><b>Session property:</b> <jk>false</jk> 203 * <li><b>Methods:</b> 204 * <ul> 205 * <li class='jm'>{@link BeanContextBuilder#beanConstructorVisibility(Visibility)} 206 * </ul> 207 * </ul> 208 * 209 * <h5 class='section'>Description:</h5> 210 * <p> 211 * Only look for constructors with the specified minimum visibility. 212 * 213 * <p> 214 * This setting affects the logic for finding no-arg constructors for bean. 215 * <br>Normally, only <jk>public</jk> no-arg constructors are used. 216 * <br>Use this setting if you want to reduce the visibility requirement. 217 * 218 * <h5 class='section'>Example:</h5> 219 * <p class='bcode w800'> 220 * <jc>// Create a serializer that looks for protected no-arg constructors.</jc> 221 * WriterSerializer s = JsonSerializer 222 * .<jsm>create</jsm>() 223 * .beanConstructorVisibility(<jsf>PROTECTED</jsf>) 224 * .build(); 225 * 226 * <jc>// Same, but use property.</jc> 227 * WriterSerializer s = JsonSerializer 228 * .<jsm>create</jsm>() 229 * .set(<jsf>BEAN_beanConstructorVisibility</jsf>, <js>"PROTECTED"</js>) 230 * .build(); 231 * </p> 232 */ 233 public static final String BEAN_beanConstructorVisibility = PREFIX + ".beanConstructorVisibility.s"; 234 235 /** 236 * Configuration property: Bean dictionary. 237 * 238 * <h5 class='section'>Property:</h5> 239 * <ul> 240 * <li><b>Name:</b> <js>"BeanContext.beanDictionary.lc"</js> 241 * <li><b>Data type:</b> <c>List<Class></c> 242 * <li><b>Default:</b> empty list 243 * <li><b>Session property:</b> <jk>false</jk> 244 * <li><b>Annotations:</b> 245 * <ul> 246 * <li class='ja'>{@link Bean#beanDictionary()} 247 * <li class='ja'>{@link BeanProperty#beanDictionary()} 248 * </ul> 249 * <li><b>Methods:</b> 250 * <ul> 251 * <li class='jm'>{@link BeanContextBuilder#beanDictionary(Object...)} 252 * <li class='jm'>{@link BeanContextBuilder#beanDictionary(Class...)} 253 * <li class='jm'>{@link BeanContextBuilder#beanDictionaryReplace(Object...)} 254 * <li class='jm'>{@link BeanContextBuilder#beanDictionaryReplace(Class...)} 255 * <li class='jm'>{@link BeanContextBuilder#beanDictionaryRemove(Object...)} 256 * <li class='jm'>{@link BeanContextBuilder#beanDictionaryRemove(Class...)} 257 * <li class='jm'>{@link BeanFilterBuilder#beanDictionary(Class...)} 258 * </ul> 259 * </ul> 260 * 261 * <h5 class='section'>Description:</h5> 262 * <p> 263 * The list of classes that make up the bean dictionary in this bean context. 264 * 265 * <p> 266 * A dictionary is a name/class mapping used to find class types during parsing when they cannot be inferred 267 * through reflection. 268 * <br>The names are defined through the {@link Bean#typeName() @Bean(typeName)} annotation defined on the bean class. 269 * <br>For example, if a class <c>Foo</c> has a type-name of <js>"myfoo"</js>, then it would end up serialized 270 * as <js>"{_type:'myfoo',...}"</js>. 271 * 272 * <p> 273 * This setting tells the parsers which classes to look for when resolving <js>"_type"</js> attributes. 274 * 275 * <p> 276 * Values can consist of any of the following types: 277 * <ul> 278 * <li>Any bean class that specifies a value for {@link Bean#typeName() @Bean(typeName)}. 279 * <li>Any subclass of {@link BeanDictionaryList} containing a collection of bean classes with type name annotations. 280 * <li>Any subclass of {@link BeanDictionaryMap} containing a mapping of type names to classes without type name annotations. 281 * <li>Any array or collection of the objects above. 282 * </ul> 283 * 284 * <h5 class='section'>Example:</h5> 285 * <p class='bcode w800'> 286 * <jc>// Create a parser and tell it which classes to try to resolve.</jc> 287 * ReaderParser p = JsonParser 288 * .<jsm>create</jsm>() 289 * .beanDictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>) 290 * .build(); 291 * 292 * <jc>// Same, but use property.</jc> 293 * ReaderParser p = JsonParser 294 * .<jsm>create</jsm>() 295 * .addTo(<jsf>BEAN_beanDictionary</jsf>, Foo.<jk>class</jk>) 296 * .addTo(<jsf>BEAN_beanDictionary</jsf>, Bar.<jk>class</jk>) 297 * .build(); 298 * 299 * <jc>// Instead of by parser, define a bean dictionary on a class through an annotation.</jc> 300 * <jc>// This applies to all properties on this class and all subclasses.</jc> 301 * <ja>@Bean</ja>(beanDictionary={Foo.<jk>class</jk>,Bar.<jk>class</jk>}) 302 * <jk>public class</jk> MyBean {...} 303 * 304 * <jc>// Use the predefined HTML5 bean dictionary which is a BeanDictionaryList.</jc> 305 * ReaderParser p = HtmlParser 306 * .<jsm>create</jsm>() 307 * .beanDictionary(HtmlBeanDictionary.<jk>class</jk>) 308 * .build(); 309 * </p> 310 * 311 * <ul class='seealso'> 312 * <li class='link'>{@doc juneau-marshall.BeanDictionaries} 313 * </ul> 314 */ 315 public static final String BEAN_beanDictionary = PREFIX + ".beanDictionary.lc"; 316 317 /** 318 * Configuration property: Add to bean dictionary. 319 */ 320 public static final String BEAN_beanDictionary_add = PREFIX + ".beanDictionary.lc/add"; 321 322 /** 323 * Configuration property: Remove from bean dictionary. 324 */ 325 public static final String BEAN_beanDictionary_remove = PREFIX + ".beanDictionary.lc/remove"; 326 327 /** 328 * Configuration property: Minimum bean field visibility. 329 * 330 * <h5 class='section'>Property:</h5> 331 * <ul> 332 * <li><b>Name:</b> <js>"BeanContext.beanFieldVisibility.s"</js> 333 * <li><b>Data type:</b> <c>String</c> ({@link Visibility}) 334 * <li><b>Default:</b> <js>"PUBLIC"</js> 335 * <li><b>Session property:</b> <jk>false</jk> 336 * <li><b>Methods:</b> 337 * <ul> 338 * <li class='jm'>{@link BeanContextBuilder#beanFieldVisibility(Visibility)} 339 * </ul> 340 * </ul> 341 * 342 * <h5 class='section'>Description:</h5> 343 * <p> 344 * Only look for bean fields with the specified minimum visibility. 345 * 346 * <p> 347 * This affects which fields on a bean class are considered bean properties. 348 * <br>Normally only <jk>public</jk> fields are considered. 349 * <br>Use this setting if you want to reduce the visibility requirement. 350 * 351 * <h5 class='section'>Example:</h5> 352 * <p class='bcode w800'> 353 * <jc>// Create a serializer that looks for protected fields.</jc> 354 * WriterSerializer s = JsonSerializer 355 * .<jsm>create</jsm>() 356 * .beanFieldVisibility(<jsf>PROTECTED</jsf>) 357 * .build(); 358 * 359 * <jc>// Same, but use property.</jc> 360 * WriterSerializer s = JsonSerializer 361 * .<jsm>create</jsm>() 362 * .set(<jsf>BEAN_beanFieldVisibility</jsf>, <js>"PROTECTED"</js>) 363 * .build(); 364 * 365 * <jc>// Disable using fields as properties entirely.</jc> 366 * WriterSerializer s = JsonSerializer 367 * .<jsm>create</jsm>() 368 * .beanFieldVisibility(<jsf>NONE</jsf>) 369 * .build(); 370 * </p> 371 */ 372 public static final String BEAN_beanFieldVisibility = PREFIX + ".beanFieldVisibility.s"; 373 374 /** 375 * Configuration property: Bean filters. 376 * 377 * <h5 class='section'>Property:</h5> 378 * <ul> 379 * <li><b>Name:</b> <js>"BeanContext.beanFilters.lc"</js> 380 * <li><b>Data type:</b> <c>List<Class></c> 381 * <li><b>Default:</b> empty list 382 * <li><b>Session property:</b> <jk>false</jk> 383 * <li><b>Methods:</b> 384 * <ul> 385 * <li class='jm'>{@link BeanContextBuilder#beanFilters(Object...)} 386 * <li class='jm'>{@link BeanContextBuilder#beanFilters(Class...)} 387 * <li class='jm'>{@link BeanContextBuilder#beanFiltersReplace(Object...)} 388 * <li class='jm'>{@link BeanContextBuilder#beanFiltersReplace(Class...)} 389 * <li class='jm'>{@link BeanContextBuilder#beanFiltersRemove(Object...)} 390 * <li class='jm'>{@link BeanContextBuilder#beanFiltersRemove(Class...)} 391 * </ul> 392 * </ul> 393 * 394 * <h5 class='section'>Description:</h5> 395 * <p> 396 * This is a programmatic equivalent to the {@link Bean @Bean} annotation. 397 * <br>It's useful when you want to use the <c>@Bean</c> annotation functionality, but you don't have the ability to alter 398 * the bean classes. 399 * 400 * <p> 401 * Values can consist of any of the following types: 402 * <ul class='spaced-list'> 403 * <li>Any subclass of {@link BeanFilterBuilder}. 404 * <br>These must have a public no-arg constructor. 405 * <li>Any bean interfaces. 406 * <br>A shortcut for defining a {@link InterfaceBeanFilterBuilder}. 407 * <br>Any subclasses of an interface class will only have properties defined on the interface. 408 * All other bean properties will be ignored. 409 * <li>Any array or collection of the objects above. 410 * </ul> 411 * 412 * <h5 class='section'>Example:</h5> 413 * <p class='bcode w800'> 414 * <jc>// Create a bean filter for the MyBean class.</jc> 415 * <jk>public class</jk> MyBeanFilter <jk>extends</jk> BeanFilterBuilder<MyBean> { 416 * 417 * <jc>// Must provide a no-arg constructor!</jc> 418 * <jk>public</jk> MyBeanFilter() { 419 * includeProperties(<js>"foo,bar,baz"</js>); <jc>// The properties we want exposed.</jc> 420 * } 421 * } 422 * 423 * <jc>// Associate our bean filter with a serializer.</jc> 424 * WriterSerializer s = JsonSerializer 425 * .<jsm>create</jsm>() 426 * .beanFilters(MyBeanFilter.<jk>class</jk>) 427 * .build(); 428 * 429 * <jc>// Same, but use property.</jc> 430 * WriterSerializer s = JsonSerializer 431 * .<jsm>create</jsm>() 432 * .addTo(<jsf>BEAN_beanFilters</jsf>, MyBeanFilter.<jk>class</jk>) 433 * .build(); 434 * </p> 435 * 436 * <ul class='seealso'> 437 * <li class='link'>{@doc juneau-marshall.Transforms.BeanFilters} 438 * <li class='link'>{@doc juneau-marshall.Transforms.InterfaceFilters} 439 * </ul> 440 */ 441 public static final String BEAN_beanFilters = PREFIX + ".beanFilters.lc"; 442 443 /** 444 * Configuration property: Add to bean filters. 445 */ 446 public static final String BEAN_beanFilters_add = PREFIX + ".beanFilters.lc/add"; 447 448 /** 449 * Configuration property: Remove from bean filters. 450 */ 451 public static final String BEAN_beanFilters_remove = PREFIX + ".beanFilters.lc/remove"; 452 453 /** 454 * Configuration property: BeanMap.put() returns old property value. 455 * 456 * <h5 class='section'>Property:</h5> 457 * <ul> 458 * <li><b>Name:</b> <js>"BeanContext.beanMapPutReturnsOldValue.b"</js> 459 * <li><b>Data type:</b> <c>Boolean</c> 460 * <li><b>Default:</b> <jk>false</jk> 461 * <li><b>Session property:</b> <jk>false</jk> 462 * <li><b>Methods:</b> 463 * <ul> 464 * <li class='jm'>{@link BeanContextBuilder#beanMapPutReturnsOldValue(boolean)} 465 * <li class='jm'>{@link BeanContextBuilder#beanMapPutReturnsOldValue()} 466 * </ul> 467 * </ul> 468 * 469 * <h5 class='section'>Description:</h5> 470 * <p> 471 * If <jk>true</jk>, then the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property 472 * values. 473 * <br>Otherwise, it returns <jk>null</jk>. 474 * 475 * <p> 476 * Disabled by default because it introduces a slight performance penalty during serialization. 477 * 478 * <h5 class='section'>Example:</h5> 479 * <p class='bcode w800'> 480 * <jc>// Create a serializer that creates BeanMaps with normal put() behavior.</jc> 481 * WriterSerializer s = JsonSerializer 482 * .<jsm>create</jsm>() 483 * .beanMapPutReturnsOldValue() 484 * .build(); 485 * 486 * <jc>// Same, but use property.</jc> 487 * WriterSerializer s = JsonSerializer 488 * .<jsm>create</jsm>() 489 * .set(<jsf>BEAN_beanMapPutReturnsOldValue</jsf>, <jk>true</jk>) 490 * .build(); 491 * 492 * BeanMap<MyBean> bm = s.createSession().toBeanMap(<jk>new</jk> MyBean()); 493 * bm.put(<js>"foo"</js>, <js>"bar"</js>); 494 * Object oldValue = bm.put(<js>"foo"</js>, <js>"baz"</js>); <jc>// oldValue == "bar"</jc> 495 * </p> 496 */ 497 public static final String BEAN_beanMapPutReturnsOldValue = PREFIX + ".beanMapPutReturnsOldValue.b"; 498 499 /** 500 * Configuration property: Minimum bean method visibility. 501 * 502 * <h5 class='section'>Property:</h5> 503 * <ul> 504 * <li><b>Name:</b> <js>"BeanContext.beanMethodVisibility.s"</js> 505 * <li><b>Data type:</b> <c>String</c> ({@link Visibility}) 506 * <li><b>Default:</b> <js>"PUBLIC"</js> 507 * <li><b>Session property:</b> <jk>false</jk> 508 * <li><b>Methods:</b> 509 * <ul> 510 * <li class='jm'>{@link BeanContextBuilder#beanMethodVisibility(Visibility)} 511 * </ul> 512 * </ul> 513 * 514 * <h5 class='section'>Description:</h5> 515 * <p> 516 * Only look for bean methods with the specified minimum visibility. 517 * 518 * <p> 519 * This affects which methods are detected as getters and setters on a bean class. 520 * <br>Normally only <jk>public</jk> getters and setters are considered. 521 * <br>Use this setting if you want to reduce the visibility requirement. 522 * 523 * <h5 class='section'>Example:</h5> 524 * <p class='bcode w800'> 525 * <jc>// Create a serializer that looks for protected getters and setters.</jc> 526 * WriterSerializer s = JsonSerializer 527 * .<jsm>create</jsm>() 528 * .beanMethodVisibility(<jsf>PROTECTED</jsf>) 529 * .build(); 530 * 531 * <jc>// Same, but use property.</jc> 532 * WriterSerializer s = JsonSerializer 533 * .<jsm>create</jsm>() 534 * .set(<jsf>BEAN_beanMethodVisibility</jsf>, <js>"PROTECTED"</js>) 535 * .build(); 536 * </p> 537 */ 538 public static final String BEAN_beanMethodVisibility = PREFIX + ".beanMethodVisibility.s"; 539 540 /** 541 * Configuration property: Beans require no-arg constructors. 542 * 543 * <h5 class='section'>Property:</h5> 544 * <ul> 545 * <li><b>Name:</b> <js>"BeanContext.beansRequireDefaultConstructor.b"</js> 546 * <li><b>Data type:</b> <c>Boolean</c> 547 * <li><b>Default:</b> <jk>false</jk> 548 * <li><b>Session property:</b> <jk>false</jk> 549 * <li><b>Methods:</b> 550 * <ul> 551 * <li class='jm'>{@link BeanContextBuilder#beansRequireDefaultConstructor(boolean)} 552 * <li class='jm'>{@link BeanContextBuilder#beansRequireDefaultConstructor()} 553 * </ul> 554 * </ul> 555 * 556 * <h5 class='section'>Description:</h5> 557 * <p> 558 * If <jk>true</jk>, a Java class must implement a default no-arg constructor to be considered a bean. 559 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 560 * 561 * <p> 562 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>. 563 * 564 * <h5 class='section'>Example:</h5> 565 * <p class='bcode w800'> 566 * <jc>// Create a serializer that ignores beans without default constructors.</jc> 567 * WriterSerializer s = JsonSerializer 568 * .<jsm>create</jsm>() 569 * .beansRequireDefaultConstructor() 570 * .build(); 571 * 572 * <jc>// Same, but use property.</jc> 573 * WriterSerializer s = JsonSerializer 574 * .<jsm>create</jsm>() 575 * .set(<jsf>BEAN_beansRequireDefaultConstructor</jsf>, <jk>true</jk>) 576 * .build(); 577 * </p> 578 */ 579 public static final String BEAN_beansRequireDefaultConstructor = PREFIX + ".beansRequireDefaultConstructor.b"; 580 581 /** 582 * Configuration property: Beans require Serializable interface. 583 * 584 * <h5 class='section'>Property:</h5> 585 * <ul> 586 * <li><b>Name:</b> <js>"BeanContext.beansRequireSerializable.b"</js> 587 * <li><b>Data type:</b> <c>Boolean</c> 588 * <li><b>Default:</b> <jk>false</jk> 589 * <li><b>Session property:</b> <jk>false</jk> 590 * <li><b>Methods:</b> 591 * <ul> 592 * <li class='jm'>{@link BeanContextBuilder#beansRequireSerializable(boolean)} 593 * <li class='jm'>{@link BeanContextBuilder#beansRequireSerializable()} 594 * </ul> 595 * </ul> 596 * 597 * <h5 class='section'>Description:</h5> 598 * <p> 599 * If <jk>true</jk>, a Java class must implement the {@link Serializable} interface to be considered a bean. 600 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 601 * 602 * <p> 603 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>. 604 * 605 * <h5 class='section'>Example:</h5> 606 * <p class='bcode w800'> 607 * <jc>// Create a serializer that ignores beans not implementing Serializable.</jc> 608 * WriterSerializer s = JsonSerializer 609 * .<jsm>create</jsm>() 610 * .beansRequireSerializable() 611 * .build(); 612 * 613 * <jc>// Same, but use property.</jc> 614 * WriterSerializer s = JsonSerializer 615 * .<jsm>create</jsm>() 616 * .set(<jsf>BEAN_beansRequireSerializable</jsf>, <jk>true</jk>) 617 * .build(); 618 * </p> 619 */ 620 public static final String BEAN_beansRequireSerializable = PREFIX + ".beansRequireSerializable.b"; 621 622 /** 623 * Configuration property: Beans require setters for getters. 624 * 625 * <h5 class='section'>Property:</h5> 626 * <ul> 627 * <li><b>Name:</b> <js>"BeanContext.beansRequireSettersForGetters.b"</js> 628 * <li><b>Data type:</b> <c>Boolean</c> 629 * <li><b>Default:</b> <jk>false</jk> 630 * <li><b>Session property:</b> <jk>false</jk> 631 * <li><b>Methods:</b> 632 * <ul> 633 * <li class='jm'>{@link BeanContextBuilder#beansRequireSettersForGetters(boolean)} 634 * <li class='jm'>{@link BeanContextBuilder#beansRequireSettersForGetters()} 635 * </ul> 636 * </ul> 637 * 638 * <h5 class='section'>Description:</h5> 639 * <p> 640 * If <jk>true</jk>, only getters that have equivalent setters will be considered as properties on a bean. 641 * <br>Otherwise, they will be ignored. 642 * 643 * <h5 class='section'>Example:</h5> 644 * <p class='bcode w800'> 645 * <jc>// Create a serializer that ignores bean properties without setters.</jc> 646 * WriterSerializer s = JsonSerializer 647 * .<jsm>create</jsm>() 648 * .beansRequireSettersForGetter() 649 * .build(); 650 * 651 * <jc>// Same, but use property.</jc> 652 * WriterSerializer s = JsonSerializer 653 * .<jsm>create</jsm>() 654 * .set(<jsf>BEAN_beansRequireSettersForGetters</jsf>, <jk>true</jk>) 655 * .build(); 656 * </p> 657 */ 658 public static final String BEAN_beansRequireSettersForGetters = PREFIX + ".beansRequireSettersForGetters.b"; 659 660 /** 661 * Configuration property: Beans require at least one property. 662 * 663 * <h5 class='section'>Property:</h5> 664 * <ul> 665 * <li><b>Name:</b> <js>"BeanContext.beansRequireSomeProperties.b"</js> 666 * <li><b>Data type:</b> <c>Boolean</c> 667 * <li><b>Default:</b> <jk>true</jk> 668 * <li><b>Session property:</b> <jk>false</jk> 669 * <li><b>Methods:</b> 670 * <ul> 671 * <li class='jm'>{@link BeanContextBuilder#beansRequireSomeProperties(boolean)} 672 * </ul> 673 * </ul> 674 * 675 * <h5 class='section'>Description:</h5> 676 * <p> 677 * If <jk>true</jk>, then a Java class must contain at least 1 property to be considered a bean. 678 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 679 * 680 * <p> 681 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>. 682 * 683 * <h5 class='section'>Example:</h5> 684 * <p class='bcode w800'> 685 * <jc>// Create a serializer that serializes beans even if they have zero properties.</jc> 686 * WriterSerializer s = JsonSerializer 687 * .<jsm>create</jsm>() 688 * .beansRequireSomeProperties(<jk>false</jk>) 689 * .build(); 690 * 691 * <jc>// Same, but use property.</jc> 692 * WriterSerializer s = JsonSerializer 693 * .<jsm>create</jsm>() 694 * .set(<jsf>BEAN_beansRequireSomeProperties</jsf>, <jk>false</jk>) 695 * .build(); 696 * </p> 697 */ 698 public static final String BEAN_beansRequireSomeProperties = PREFIX + ".beansRequireSomeProperties.b"; 699 700 /** 701 * Configuration property: Bean type property name. 702 * 703 * <h5 class='section'>Property:</h5> 704 * <ul> 705 * <li><b>Name:</b> <js>"BeanContext.beanTypePropertyName.s"</js> 706 * <li><b>Data type:</b> <c>String</c> 707 * <li><b>Default:</b> <js>"_type"</js> 708 * <li><b>Session property:</b> <jk>false</jk> 709 * <li><b>Annotations:</b> 710 * <ul> 711 * <li class='ja'>{@link Bean#typePropertyName()} 712 * </ul> 713 * <li><b>Methods:</b> 714 * <ul> 715 * <li class='jm'>{@link BeanContextBuilder#beanTypePropertyName(String)} 716 * </ul> 717 * </ul> 718 * 719 * <p> 720 * This specifies the name of the bean property used to store the dictionary name of a bean type so that the 721 * parser knows the data type to reconstruct. 722 * 723 * <h5 class='section'>Example:</h5> 724 * <p class='bcode w800'> 725 * <jc>// Create a serializer that uses 'type' instead of '_type' for dictionary names.</jc> 726 * WriterSerializer s = JsonSerializer 727 * .<jsm>create</jsm>() 728 * .beanTypePropertyName(<js>"type"</js>) 729 * .build(); 730 * 731 * <jc>// Same, but use property.</jc> 732 * WriterSerializer s = JsonSerializer 733 * .<jsm>create</jsm>() 734 * .set(<jsf>BEAN_beanTypePropertyName</jsf>, <js>"type"</js>) 735 * .build(); 736 * </p> 737 * 738 * <ul class='seealso'> 739 * <li class='link'>{@doc juneau-marshall.BeanDictionaries} 740 * </ul> 741 */ 742 public static final String BEAN_beanTypePropertyName = PREFIX + ".beanTypePropertyName.s"; 743 744 /** 745 * Configuration property: Debug mode. 746 * 747 * <h5 class='section'>Property:</h5> 748 * <ul> 749 * <li><b>Name:</b> <js>"BeanContext.debug.b"</js> 750 * <li><b>Data type:</b> <c>Boolean</c> 751 * <li><b>Default:</b> <jk>false</jk> 752 * <li><b>Session property:</b> <jk>true</jk> 753 * <li><b>Methods:</b> 754 * <ul> 755 * <li class='jm'>{@link BeanContextBuilder#debug(boolean)} 756 * <li class='jm'>{@link BeanContextBuilder#debug()} 757 * <li class='jm'>{@link BeanSessionArgs#debug(Boolean)} 758 * </ul> 759 * </ul> 760 * 761 * <h5 class='section'>Description:</h5> 762 * <p> 763 * Enables the following additional information during serialization: 764 * <ul class='spaced-list'> 765 * <li> 766 * When bean getters throws exceptions, the exception includes the object stack information 767 * in order to determine how that method was invoked. 768 * <li> 769 * Enables {@link Serializer#BEANTRAVERSE_detectRecursions}. 770 * </ul> 771 * 772 * <p> 773 * Enables the following additional information during parsing: 774 * <ul class='spaced-list'> 775 * <li> 776 * When bean setters throws exceptions, the exception includes the object stack information 777 * in order to determine how that method was invoked. 778 * </ul> 779 * 780 * <h5 class='section'>Example:</h5> 781 * <p class='bcode w800'> 782 * <jc>// Create a serializer with debug enabled.</jc> 783 * WriterSerializer s = JsonSerializer 784 * .<jsm>create</jsm>() 785 * .debug() 786 * .build(); 787 * 788 * <jc>// Same, but use property.</jc> 789 * WriterSerializer s = JsonSerializer 790 * .<jsm>create</jsm>() 791 * .set(<jsf>BEAN_debug</jsf>, <jk>true</jk>) 792 * .build(); 793 * </p> 794 */ 795 public static final String BEAN_debug = PREFIX + ".debug.b"; 796 797 /** 798 * Configuration property: POJO examples. 799 * 800 * <h5 class='section'>Property:</h5> 801 * <ul> 802 * <li><b>Name:</b> <js>"BeanContext.examples.smo"</js> 803 * <li><b>Data type:</b> <c>Map<String,Object></c> 804 * <li><b>Default:</b> <c>{}</c> 805 * <li><b>Session property:</b> <jk>false</jk> 806 * <li><b>Annotations:</b> 807 * <ul> 808 * <li class='ja'>{@link Example} 809 * </ul> 810 * <li><b>Methods:</b> 811 * <ul> 812 * <li class='jm'>{@link BeanContextBuilder#example(Class,Object)} 813 * </ul> 814 * </ul> 815 * 816 * <h5 class='section'>Description:</h5> 817 * <p> 818 * Specifies an example of the specified class. 819 * 820 * <p> 821 * Examples are used in cases such as POJO examples in Swagger documents. 822 * 823 * <p> 824 * Setting applies to specified class and all subclasses. 825 * 826 * <h5 class='section'>Example:</h5> 827 * <p class='bcode w800'> 828 * <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc> 829 * WriterSerializer s = JsonSerializer 830 * .<jsm>create</jsm>() 831 * .example(MyBean.<jk>class</jk>, <jk>new</jk> MyBean().foo(<js>"foo"</js>).bar(123)) 832 * .build(); 833 * 834 * <jc>// Same, but use property.</jc> 835 * WriterSerializer s = JsonSerializer 836 * .<jsm>create</jsm>() 837 * .addTo(<jsf>BEAN_examples</jsf>, MyBean.<jk>class</jk>.getName(), <jk>new</jk> MyBean().foo(<js>"foo"</js>).bar(123)) 838 * .build(); 839 * </p> 840 * 841 * <p> 842 * POJO examples can also be defined on classes via the following: 843 * <ul class='spaced-list'> 844 * <li>A static field annotated with {@link Example @Example}. 845 * <li>A static method annotated with {@link Example @Example} with zero arguments or one {@link BeanSession} argument. 846 * <li>A static method with name <c>example</c> with no arguments or one {@link BeanSession} argument. 847 * </ul> 848 */ 849 public static final String BEAN_examples = PREFIX + ".examples.smo"; 850 851 /** 852 * Configuration property: Bean property excludes. 853 * 854 * <h5 class='section'>Property:</h5> 855 * <ul> 856 * <li><b>Name:</b> <js>"BeanContext.excludeProperties.sms"</js> 857 * <li><b>Data type:</b> <c>Map<String,String></c> 858 * <li><b>Default:</b> <c>{}</c> 859 * <li><b>Session property:</b> <jk>false</jk> 860 * <li><b>Annotations:</b> 861 * <ul> 862 * <li class='ja'>{@link Bean#excludeProperties()} 863 * </ul> 864 * <li><b>Methods:</b> 865 * <ul> 866 * <li class='jm'>{@link BeanContextBuilder#excludeProperties(Class, String)} 867 * <li class='jm'>{@link BeanContextBuilder#excludeProperties(String, String)} 868 * <li class='jm'>{@link BeanContextBuilder#excludeProperties(Map)} 869 * <li class='jm'>{@link BeanFilterBuilder#excludeProperties(String...)} 870 * </ul> 871 * </ul> 872 * 873 * <h5 class='section'>Description:</h5> 874 * <p> 875 * Specifies to exclude the specified list of properties for the specified bean class. 876 * 877 * <p> 878 * The keys are either fully-qualified or simple class names, and the values are comma-delimited lists of property 879 * names. 880 * The key <js>"*"</js> means all bean classes. 881 * 882 * <p> 883 * For example, <code>{Bean1:<js>'foo,bar'</js>}</code> means don't serialize the <c>foo</c> and 884 * <c>bar</c> properties on any beans whose simple class name is <c>Bean1</c>. 885 * 886 * <p> 887 * Setting applies to specified class and all subclasses. 888 * 889 * <h5 class='section'>Example:</h5> 890 * <p class='bcode w800'> 891 * <jc>// Create a serializer that excludes the 'foo' and 'bar' properties on the MyBean class.</jc> 892 * WriterSerializer s = JsonSerializer 893 * .<jsm>create</jsm>() 894 * .excludeProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>) 895 * .build(); 896 * 897 * <jc>// Same, but use property.</jc> 898 * WriterSerializer s = JsonSerializer 899 * .<jsm>create</jsm>() 900 * .addTo(<jsf>BEAN_excludeProperties</jsf>, MyBean.<jk>class</jk>.getName(), <js>"foo,bar"</js>) 901 * .build(); 902 * 903 * <jc>// Alternate using JSON object.</jc> 904 * WriterSerializer s = JsonSerializer 905 * .<jsm>create</jsm>() 906 * .addTo(<jsf>BEAN_excludeProperties</jsf>, <js>"{'org.apache.MyBean':'foo,bar'}"</js>) 907 * .build(); 908 * </p> 909 */ 910 public static final String BEAN_excludeProperties = PREFIX + ".excludeProperties.sms"; 911 912 /** 913 * Configuration property: Find fluent setters. 914 * 915 * <h5 class='section'>Property:</h5> 916 * <ul> 917 * <li><b>Name:</b> <js>"BeanContext.fluentSetters.b"</js> 918 * <li><b>Data type:</b> <c>Boolean</c> 919 * <li><b>Default:</b> <jk>false</jk> 920 * <li><b>Session property:</b> <jk>false</jk> 921 * <li><b>Annotations:</b> 922 * <ul> 923 * <li class='ja'>{@link Bean#fluentSetters()} 924 * </ul> 925 * <li><b>Methods:</b> 926 * <ul> 927 * <li class='jm'>{@link BeanContextBuilder#fluentSetters(boolean)} 928 * <li class='jm'>{@link BeanContextBuilder#fluentSetters()} 929 * <li class='jm'>{@link BeanFilterBuilder#fluentSetters(boolean)} 930 * <li class='jm'>{@link BeanFilterBuilder#fluentSetters()} 931 * </ul> 932 * </ul> 933 * 934 * <h5 class='section'>Description:</h5> 935 * <p> 936 * When enabled, fluent setters are detected on beans. 937 * 938 * <p> 939 * Fluent setters must have the following attributes: 940 * <ul> 941 * <li>Public. 942 * <li>Not static. 943 * <li>Take in one parameter. 944 * <li>Return the bean itself. 945 * </ul> 946 * 947 * <h5 class='section'>Example:</h5> 948 * <p class='bcode w800'> 949 * <jc>// Create a serializer that finds fluent setters.</jc> 950 * WriterSerializer s = JsonSerializer 951 * .<jsm>create</jsm>() 952 * .fluentSetters() 953 * .build(); 954 * 955 * <jc>// Same, but use property.</jc> 956 * WriterSerializer s = JsonSerializer 957 * .<jsm>create</jsm>() 958 * .set(<jsf>BEAN_fluentSetters</jsf>, <jk>true</jk>) 959 * .build(); 960 * </p> 961 */ 962 public static final String BEAN_fluentSetters = PREFIX + ".fluentSetters.b"; 963 964 /** 965 * Configuration property: Ignore invocation errors on getters. 966 * 967 * <h5 class='section'>Property:</h5> 968 * <ul> 969 * <li><b>Name:</b> <js>"BeanContext.ignoreInvocationExceptionsOnGetters.b"</js> 970 * <li><b>Data type:</b> <c>Boolean</c> 971 * <li><b>Default:</b> <jk>false</jk> 972 * <li><b>Session property:</b> <jk>false</jk> 973 * <li><b>Methods:</b> 974 * <ul> 975 * <li class='jm'>{@link BeanContextBuilder#ignoreInvocationExceptionsOnGetters(boolean)} 976 * <li class='jm'>{@link BeanContextBuilder#ignoreInvocationExceptionsOnGetters()} 977 * </ul> 978 * </ul> 979 * 980 * <h5 class='section'>Description:</h5> 981 * <p> 982 * If <jk>true</jk>, errors thrown when calling bean getter methods will silently be ignored. 983 * <br>Otherwise, a {@code BeanRuntimeException} is thrown. 984 * 985 * <h5 class='section'>Example:</h5> 986 * <p class='bcode w800'> 987 * <jc>// Create a serializer that ignores bean getter exceptions.</jc> 988 * WriterSerializer s = JsonSerializer 989 * .<jsm>create</jsm>() 990 * .ingoreInvocationExceptionsOnGetters() 991 * .build(); 992 * 993 * <jc>// Same, but use property.</jc> 994 * WriterSerializer s = JsonSerializer 995 * .<jsm>create</jsm>() 996 * .set(<jsf>BEAN_ignoreInvocationExceptionsOnGetters</jsf>, <jk>true</jk>) 997 * .build(); 998 * </p> 999 */ 1000 public static final String BEAN_ignoreInvocationExceptionsOnGetters = PREFIX + ".ignoreInvocationExceptionsOnGetters.b"; 1001 1002 /** 1003 * Configuration property: Ignore invocation errors on setters. 1004 * 1005 * <h5 class='section'>Property:</h5> 1006 * <ul> 1007 * <li><b>Name:</b> <js>"BeanContext.ignoreInvocationExceptionsOnSetters.b"</js> 1008 * <li><b>Data type:</b> <c>Boolean</c> 1009 * <li><b>Default:</b> <jk>false</jk> 1010 * <li><b>Session property:</b> <jk>false</jk> 1011 * <li><b>Methods:</b> 1012 * <ul> 1013 * <li class='jm'>{@link BeanContextBuilder#ignoreInvocationExceptionsOnSetters(boolean)} 1014 * <li class='jm'>{@link BeanContextBuilder#ignoreInvocationExceptionsOnSetters()} 1015 * </ul> 1016 * </ul> 1017 * 1018 * <h5 class='section'>Description:</h5> 1019 * <p> 1020 * If <jk>true</jk>, errors thrown when calling bean setter methods will silently be ignored. 1021 * <br>Otherwise, a {@code BeanRuntimeException} is thrown. 1022 * 1023 * <h5 class='section'>Example:</h5> 1024 * <p class='bcode w800'> 1025 * <jc>// Create a parser that ignores bean setter exceptions.</jc> 1026 * ReaderParser p = JsonParser 1027 * .<jsm>create</jsm>() 1028 * .ignoreInvocationExceptionsOnSetters() 1029 * .build(); 1030 * 1031 * <jc>// Same, but use property.</jc> 1032 * ReaderParser p = JsonParser 1033 * .<jsm>create</jsm>() 1034 * .set(<jsf>BEAN_ignoreInvocationExceptionsOnSetters</jsf>, <jk>true</jk>) 1035 * .build(); 1036 * </p> 1037 */ 1038 public static final String BEAN_ignoreInvocationExceptionsOnSetters = PREFIX + ".ignoreInvocationExceptionsOnSetters.b"; 1039 1040 /** 1041 * Configuration property: Ignore properties without setters. 1042 * 1043 * <h5 class='section'>Property:</h5> 1044 * <ul> 1045 * <li><b>Name:</b> <js>"BeanContext.ignorePropertiesWithoutSetters.b"</js> 1046 * <li><b>Data type:</b> <c>Boolean</c> 1047 * <li><b>Default:</b> <jk>true</jk> 1048 * <li><b>Session property:</b> <jk>false</jk> 1049 * <li><b>Methods:</b> 1050 * <ul> 1051 * <li class='jm'>{@link BeanContextBuilder#ignorePropertiesWithoutSetters(boolean)} 1052 * </ul> 1053 * </ul> 1054 * 1055 * <h5 class='section'>Description:</h5> 1056 * <p> 1057 * If <jk>true</jk>, trying to set a value on a bean property without a setter will silently be ignored. 1058 * <br>Otherwise, a {@code RuntimeException} is thrown. 1059 * 1060 * <h5 class='section'>Example:</h5> 1061 * <p class='bcode w800'> 1062 * <jc>// Create a parser that throws an exception if a setter is not found but a getter is.</jc> 1063 * ReaderParser p = JsonParser 1064 * .<jsm>create</jsm>() 1065 * .ignorePropertiesWithoutSetters(<jk>false</jk>) 1066 * .build(); 1067 * 1068 * <jc>// Same, but use property.</jc> 1069 * ReaderParser p = JsonParser 1070 * .<jsm>create</jsm>() 1071 * .set(<jsf>BEAN_ignorePropertiesWithoutSetters</jsf>, <jk>false</jk>) 1072 * .build(); 1073 * </p> 1074 */ 1075 public static final String BEAN_ignorePropertiesWithoutSetters = PREFIX + ".ignorePropertiesWithoutSetters.b"; 1076 1077 /** 1078 * Configuration property: Ignore unknown properties. 1079 * 1080 * <h5 class='section'>Property:</h5> 1081 * <ul> 1082 * <li><b>Name:</b> <js>"BeanContext.ignoreUnknownBeanProperties.b"</js> 1083 * <li><b>Data type:</b> <c>Boolean</c> 1084 * <li><b>Default:</b> <jk>false</jk> 1085 * <li><b>Session property:</b> <jk>false</jk> 1086 * <li><b>Methods:</b> 1087 * <ul> 1088 * <li class='jm'>{@link BeanContextBuilder#ignoreUnknownBeanProperties(boolean)} 1089 * <li class='jm'>{@link BeanContextBuilder#ignoreUnknownBeanProperties()} 1090 * </ul> 1091 * </ul> 1092 * 1093 * <h5 class='section'>Description:</h5> 1094 * <p> 1095 * If <jk>true</jk>, trying to set a value on a non-existent bean property will silently be ignored. 1096 * <br>Otherwise, a {@code RuntimeException} is thrown. 1097 * 1098 * <h5 class='section'>Example:</h5> 1099 * <p class='bcode w800'> 1100 * <jc>// Create a parser that ignores missing bean properties.</jc> 1101 * ReaderParser p = JsonParser 1102 * .<jsm>create</jsm>() 1103 * .ignoreUnknownBeanProperties() 1104 * .build(); 1105 * 1106 * <jc>// Same, but use property.</jc> 1107 * ReaderParser p = JsonParser 1108 * .<jsm>create</jsm>() 1109 * .set(<jsf>BEAN_ignoreUnknownBeanProperties</jsf>, <jk>true</jk>) 1110 * .build(); 1111 * </p> 1112 */ 1113 public static final String BEAN_ignoreUnknownBeanProperties = PREFIX + ".ignoreUnknownBeanProperties.b"; 1114 1115 /** 1116 * Configuration property: Ignore unknown properties with null values. 1117 * 1118 * <h5 class='section'>Property:</h5> 1119 * <ul> 1120 * <li><b>Name:</b> <js>"BeanContext.ignoreUnknownNullBeanProperties.b"</js> 1121 * <li><b>Data type:</b> <c>Boolean</c> 1122 * <li><b>Default:</b> <jk>true</jk> 1123 * <li><b>Session property:</b> <jk>false</jk> 1124 * <li><b>Methods:</b> 1125 * <ul> 1126 * <li class='jm'>{@link BeanContextBuilder#ignoreUnknownNullBeanProperties(boolean)} 1127 * </ul> 1128 * </ul> 1129 * 1130 * <h5 class='section'>Description:</h5> 1131 * <p> 1132 * If <jk>true</jk>, trying to set a <jk>null</jk> value on a non-existent bean property will silently be ignored. 1133 * <br>Otherwise, a {@code RuntimeException} is thrown. 1134 * 1135 * <h5 class='section'>Example:</h5> 1136 * <p class='bcode w800'> 1137 * <jc>// Create a parser that throws an exception on an unknown property even if the value being set is null.</jc> 1138 * ReaderParser p = JsonParser 1139 * .<jsm>create</jsm>() 1140 * .ignoreUnknownNullBeanProperties(<jk>false</jk>) 1141 * .build(); 1142 * 1143 * <jc>// Same, but use property.</jc> 1144 * ReaderParser p = JsonParser 1145 * .<jsm>create</jsm>() 1146 * .set(<jsf>BEAN_ignoreUnknownNullBeanProperties</jsf>, <jk>false</jk>) 1147 * .build(); 1148 * </p> 1149 */ 1150 public static final String BEAN_ignoreUnknownNullBeanProperties = PREFIX + ".ignoreUnknownNullBeanProperties.b"; 1151 1152 /** 1153 * Configuration property: Implementation classes. 1154 * 1155 * <h5 class='section'>Property:</h5> 1156 * <ul> 1157 * <li><b>Name:</b> <js>"BeanContext.implClasses.smc"</js> 1158 * <li><b>Data type:</b> <c>Map<String,Class></c> 1159 * <li><b>Default:</b> empty map 1160 * <li><b>Session property:</b> <jk>false</jk> 1161 * <li><b>Methods:</b> 1162 * <ul> 1163 * <li class='jm'>{@link BeanContextBuilder#implClasses(Map)} 1164 * <li class='jm'>{@link BeanContextBuilder#implClass(Class, Class)} 1165 * </ul> 1166 * </ul> 1167 * 1168 * <h5 class='section'>Description:</h5> 1169 * <p> 1170 * For interfaces and abstract classes this method can be used to specify an implementation class for the 1171 * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a 1172 * parse). 1173 * 1174 * <h5 class='section'>Example:</h5> 1175 * <p class='bcode w800'> 1176 * <jc>// Create a parser that instantiates MyBeanImpls when parsing MyBeanInterfaces.</jc> 1177 * ReaderParser p = JsonParser 1178 * .<jsm>create</jsm>() 1179 * .implClass(MyBeanInterface.<jk>class</jk>, MyBeanImpl.<jk>class</jk>) 1180 * .build(); 1181 * 1182 * <jc>// Same, but use property.</jc> 1183 * ReaderParser p = JsonParser 1184 * .<jsm>create</jsm>() 1185 * .addTo(<jsf>BEAN_implClasses</jsf>, MyBeanInterface.<jk>class</jk>.getName(), MyBeanImpl.<jk>class</jk>) 1186 * .build(); 1187 * </p> 1188 */ 1189 public static final String BEAN_implClasses = PREFIX + ".implClasses.smc"; 1190 1191 /** 1192 * Configuration property: Bean property includes. 1193 * 1194 * <h5 class='section'>Property:</h5> 1195 * <ul> 1196 * <li><b>Name:</b> <js>"BeanContext.properties.sms"</js> 1197 * <li><b>Data type:</b> <c>Map<String,String></c> 1198 * <li><b>Default:</b> <c>{}</c> 1199 * <li><b>Session property:</b> <jk>false</jk> 1200 * <li><b>Annotations:</b> 1201 * <ul> 1202 * <li class='ja'>{@link Bean#properties()} 1203 * <li class='ja'>{@link BeanProperty#properties()} 1204 * </ul> 1205 * <li><b>Methods:</b> 1206 * <ul> 1207 * <li class='jm'>{@link BeanContextBuilder#includeProperties(Class, String)} 1208 * <li class='jm'>{@link BeanContextBuilder#includeProperties(String, String)} 1209 * <li class='jm'>{@link BeanContextBuilder#includeProperties(Map)} 1210 * <li class='jm'>{@link BeanFilterBuilder#properties(String...)} 1211 * </ul> 1212 * </ul> 1213 * 1214 * <h5 class='section'>Description:</h5> 1215 * <p> 1216 * Specifies the set and order of names of properties associated with the bean class. 1217 * 1218 * <p> 1219 * The keys are either fully-qualified or simple class names, and the values are comma-delimited lists of property 1220 * names. 1221 * The key <js>"*"</js> means all bean classes. 1222 * 1223 * <p> 1224 * For example, <code>{Bean1:<js>'foo,bar'</js>}</code> means only serialize the <c>foo</c> and 1225 * <c>bar</c> properties on the specified bean. 1226 * 1227 * <p> 1228 * Setting applies to specified class and all subclasses. 1229 * 1230 * <h5 class='section'>Example:</h5> 1231 * <p class='bcode w800'> 1232 * <jc>// Create a serializer that includes only the 'foo' and 'bar' properties on the MyBean class.</jc> 1233 * WriterSerializer s = JsonSerializer 1234 * .<jsm>create</jsm>() 1235 * .includeProperties(MyBean.<jk>class</jk>, <js>"foo,bar"</js>) 1236 * .build(); 1237 * 1238 * <jc>// Same, but use property.</jc> 1239 * WriterSerializer s = JsonSerializer 1240 * .<jsm>create</jsm>() 1241 * .addTo(<jsf>BEAN_includeProperties</jsf>, MyBean.<jk>class</jk>.getName(), <js>"foo,bar"</js>) 1242 * .build(); 1243 * 1244 * <jc>// Alternate using JSON object.</jc> 1245 * WriterSerializer s = JsonSerializer 1246 * .<jsm>create</jsm>() 1247 * .addTo(<jsf>BEAN_includeProperties</jsf>, <js>"{'org.apache.MyBean':'foo,bar'}"</js>) 1248 * .build(); 1249 * </p> 1250 */ 1251 public static final String BEAN_includeProperties = PREFIX + ".includeProperties.sms"; 1252 1253 /** 1254 * Configuration property: Locale. 1255 * 1256 * <h5 class='section'>Property:</h5> 1257 * <ul> 1258 * <li><b>Name:</b> <js>"BeanContext.locale.s"</js> 1259 * <li><b>Data type:</b> <c>String</c> ({@link Locale}) 1260 * <li><b>Default:</b> <jk>null</jk> (defaults to {@link Locale#getDefault()}) 1261 * <li><b>Session property:</b> <jk>true</jk> 1262 * <li><b>Methods:</b> 1263 * <ul> 1264 * <li class='jm'>{@link BeanContextBuilder#locale(Locale)} 1265 * <li class='jm'>{@link BeanSessionArgs#locale(Locale)} 1266 * </ul> 1267 * </ul> 1268 * 1269 * <h5 class='section'>Description:</h5> 1270 * <p> 1271 * Specifies the default locale for serializer and parser sessions. 1272 * 1273 * <h5 class='section'>Example:</h5> 1274 * <p class='bcode w800'> 1275 * <jc>// Create a serializer that uses the specified locale if it's not passed in through session args.</jc> 1276 * WriterSerializer s = JsonSerializer 1277 * .<jsm>create</jsm>() 1278 * .locale(Locale.<jsf>UK</jsf>) 1279 * .build(); 1280 * 1281 * <jc>// Same, but use property.</jc> 1282 * WriterSerializer s = JsonSerializer 1283 * .<jsm>create</jsm>() 1284 * .set(<jsf>BEAN_locale</jsf>, Locale.<jsf>UK</jsf>) 1285 * .build(); 1286 * 1287 * <jc>// Define on session-args instead.</jc> 1288 * SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().locale(Locale.<jsf>UK</jsf>); 1289 * <jk>try</jk> (WriterSerializerSession session = s.createSession(sessionArgs)) { 1290 * ... 1291 * } 1292 * </p> 1293 */ 1294 public static final String BEAN_locale = PREFIX + ".locale.s"; 1295 1296 /** 1297 * Configuration property: Media type. 1298 * 1299 * <h5 class='section'>Property:</h5> 1300 * <ul> 1301 * <li><b>Name:</b> <js>"BeanContext.mediaType.s"</js> 1302 * <li><b>Data type:</b> <c>String</c> ({@link MediaType}) 1303 * <li><b>Default:</b> <jk>null</jk> 1304 * <li><b>Session property:</b> <jk>true</jk> 1305 * <li><b>Methods:</b> 1306 * <ul> 1307 * <li class='jm'>{@link BeanContextBuilder#mediaType(MediaType)} 1308 * <li class='jm'>{@link BeanSessionArgs#mediaType(MediaType)} 1309 * </ul> 1310 * </ul> 1311 * 1312 * <h5 class='section'>Description:</h5> 1313 * <p> 1314 * Specifies the default media type value for serializer and parser sessions. 1315 * 1316 * <h5 class='section'>Example:</h5> 1317 * <p class='bcode w800'> 1318 * <jc>// Create a serializer that uses the specified media type if it's not passed in through session args.</jc> 1319 * WriterSerializer s = JsonSerializer 1320 * .<jsm>create</jsm>() 1321 * .mediaType(MediaType.<jsf>JSON</jsf>) 1322 * .build(); 1323 * 1324 * <jc>// Same, but use property.</jc> 1325 * WriterSerializer s = JsonSerializer 1326 * .<jsm>create</jsm>() 1327 * .set(<jsf>BEAN_mediaType</jsf>, MediaType.<jsf>JSON</jsf>) 1328 * .build(); 1329 * 1330 * <jc>// Define on session-args instead.</jc> 1331 * SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().mediaType(MediaType.<jsf>JSON</jsf>); 1332 * <jk>try</jk> (WriterSerializerSession session = s.createSession(sessionArgs)) { 1333 * ... 1334 * } 1335 * </p> 1336 */ 1337 public static final String BEAN_mediaType = PREFIX + ".mediaType.s"; 1338 1339 /** 1340 * Configuration property: Bean class exclusions. 1341 * 1342 * <h5 class='section'>Property:</h5> 1343 * <ul> 1344 * <li><b>Name:</b> <js>"BeanContext.notBeanClasses.sc"</js> 1345 * <li><b>Data type:</b> <c>Set<Class></c> 1346 * <li><b>Default:</b> empty set 1347 * <li><b>Session property:</b> <jk>false</jk> 1348 * <li><b>Annotations:</b> 1349 * <ul> 1350 * <li class='ja'>{@link BeanIgnore} 1351 * </ul> 1352 * <li><b>Methods:</b> 1353 * <ul> 1354 * <li class='jm'>{@link BeanContextBuilder#notBeanClasses(Class...)} 1355 * <li class='jm'>{@link BeanContextBuilder#notBeanClasses(Object...)} 1356 * <li class='jm'>{@link BeanContextBuilder#notBeanClassesReplace(Class...)} 1357 * <li class='jm'>{@link BeanContextBuilder#notBeanClassesReplace(Object...)} 1358 * <li class='jm'>{@link BeanContextBuilder#notBeanClassesRemove(Class...)} 1359 * <li class='jm'>{@link BeanContextBuilder#notBeanClassesRemove(Object...)} 1360 * </ul> 1361 * </ul> 1362 * 1363 * <h5 class='section'>Description:</h5> 1364 * <p> 1365 * List of classes that should not be treated as beans even if they appear to be bean-like. 1366 * <br>Not-bean classes are converted to <c>Strings</c> during serialization. 1367 * 1368 * <p> 1369 * Values can consist of any of the following types: 1370 * <ul> 1371 * <li>Classes. 1372 * <li>Arrays and collections of classes. 1373 * </ul> 1374 * 1375 * <h5 class='section'>Example:</h5> 1376 * <p class='bcode w800'> 1377 * <jc>// Create a serializer that doesn't treat MyBean as a bean class.</jc> 1378 * WriterSerializer s = JsonSerializer 1379 * .<jsm>create</jsm>() 1380 * .notBeanClasses(MyBean.<jk>class</jk>) 1381 * .build(); 1382 * 1383 * <jc>// Same, but use property.</jc> 1384 * WriterSerializer s = JsonSerializer 1385 * .<jsm>create</jsm>() 1386 * .addTo(<jsf>BEAN_notBeanClasses</jsf>, MyBean.<jk>class</jk>) 1387 * .build(); 1388 * </p> 1389 */ 1390 public static final String BEAN_notBeanClasses = PREFIX + ".notBeanClasses.sc"; 1391 1392 /** 1393 * Configuration property: Add to classes that should not be considered beans. 1394 */ 1395 public static final String BEAN_notBeanClasses_add = PREFIX + ".notBeanClasses.sc/add"; 1396 1397 /** 1398 * Configuration property: Remove from classes that should not be considered beans. 1399 */ 1400 public static final String BEAN_notBeanClasses_remove = PREFIX + ".notBeanClasses.sc/remove"; 1401 1402 /** 1403 * Configuration property: Bean package exclusions. 1404 * 1405 * <h5 class='section'>Property:</h5> 1406 * <ul> 1407 * <li><b>Name:</b> <js>"BeanContext.notBeanPackages.ss"</js> 1408 * <li><b>Data type:</b> <c>Set<String></c> 1409 * <li><b>Default:</b> 1410 * <ul> 1411 * <li><c>java.lang</c> 1412 * <li><c>java.lang.annotation</c> 1413 * <li><c>java.lang.ref</c> 1414 * <li><c>java.lang.reflect</c> 1415 * <li><c>java.io</c> 1416 * <li><c>java.net</c> 1417 * <li><c>java.nio.*</c> 1418 * <li><c>java.util.*</c> 1419 * </ul> 1420 * <li><b>Session property:</b> <jk>false</jk> 1421 * <li><b>Methods:</b> 1422 * <ul> 1423 * <li class='jm'>{@link BeanContextBuilder#notBeanPackages(Object...)} 1424 * <li class='jm'>{@link BeanContextBuilder#notBeanPackages(String...)} 1425 * <li class='jm'>{@link BeanContextBuilder#notBeanPackagesReplace(Object...)} 1426 * <li class='jm'>{@link BeanContextBuilder#notBeanPackagesReplace(String...)} 1427 * <li class='jm'>{@link BeanContextBuilder#notBeanPackagesRemove(Object...)} 1428 * <li class='jm'>{@link BeanContextBuilder#notBeanPackagesRemove(String...)} 1429 * </ul> 1430 * </ul> 1431 * 1432 * <h5 class='section'>Description:</h5> 1433 * <p> 1434 * When specified, the current list of ignore packages are appended to. 1435 * 1436 * <p> 1437 * Any classes within these packages will be serialized to strings using {@link Object#toString()}. 1438 * 1439 * <p> 1440 * Note that you can specify suffix patterns to include all subpackages. 1441 * 1442 * <p> 1443 * Values can consist of any of the following types: 1444 * <ul> 1445 * <li>Strings. 1446 * <li>Arrays and collections of strings. 1447 * </ul> 1448 * 1449 * <h5 class='section'>Example:</h5> 1450 * <p class='bcode w800'> 1451 * <jc>// Create a serializer that ignores beans in the specified packages.</jc> 1452 * WriterSerializer s = JsonSerializer 1453 * .<jsm>create</jsm>() 1454 * .notBeanPackages(<js>"org.apache.foo"</js>, <js>"org.apache.bar.*"</js>) 1455 * .build(); 1456 * 1457 * <jc>// Same, but use property.</jc> 1458 * WriterSerializer s = JsonSerializer 1459 * .<jsm>create</jsm>() 1460 * .addTo(<jsf>BEAN_notBeanPackages</jsf>, <js>"org.apache.foo"</js>) 1461 * .addTo(<jsf>BEAN_notBeanPackages</jsf>, <js>"org.apache.bar.*"</js>) 1462 * .build(); 1463 * </p> 1464 */ 1465 public static final String BEAN_notBeanPackages = PREFIX + ".notBeanPackages.ss"; 1466 1467 /** 1468 * Configuration property: Add to packages whose classes should not be considered beans. 1469 */ 1470 public static final String BEAN_notBeanPackages_add = PREFIX + ".notBeanPackages.ss/add"; 1471 1472 /** 1473 * Configuration property: Remove from packages whose classes should not be considered beans. 1474 */ 1475 public static final String BEAN_notBeanPackages_remove = PREFIX + ".notBeanPackages.ss/remove"; 1476 1477 /** 1478 * Configuration property: POJO swaps. 1479 * 1480 * <h5 class='section'>Property:</h5> 1481 * <ul> 1482 * <li><b>Name:</b> <js>"BeanContext.pojoSwaps.lo"</js> 1483 * <li><b>Data type:</b> <c>List<Object></c> 1484 * <li><b>Default:</b> empty list 1485 * <li><b>Session property:</b> <jk>false</jk> 1486 * <li><b>Annotations:</b> 1487 * <ul> 1488 * <li class='ja'>{@link Swap} 1489 * <li class='ja'>{@link Swaps} 1490 * </ul> 1491 * <li><b>Methods:</b> 1492 * <ul> 1493 * <li class='jm'>{@link BeanContextBuilder#pojoSwaps(Object...)} 1494 * <li class='jm'>{@link BeanContextBuilder#pojoSwaps(Class...)} 1495 * <li class='jm'>{@link BeanContextBuilder#pojoSwapsReplace(Object...)} 1496 * <li class='jm'>{@link BeanContextBuilder#pojoSwapsReplace(Class...)} 1497 * <li class='jm'>{@link BeanContextBuilder#pojoSwapsRemove(Object...)} 1498 * <li class='jm'>{@link BeanContextBuilder#pojoSwapsRemove(Class...)} 1499 * </ul> 1500 * </ul> 1501 * 1502 * <h5 class='section'>Description:</h5> 1503 * <p> 1504 * POJO swaps are used to "swap out" non-serializable classes with serializable equivalents during serialization, 1505 * and "swap in" the non-serializable class during parsing. 1506 * 1507 * <p> 1508 * An example of a POJO swap would be a <c>Calendar</c> object that gets swapped out for an ISO8601 string. 1509 * 1510 * <p> 1511 * Multiple POJO swaps can be associated with a single class. 1512 * <br>When multiple swaps are applicable to the same class, the media type pattern defined by 1513 * {@link PojoSwap#forMediaTypes()} or {@link Swap#mediaTypes() @Swap(mediaTypes)} are used to come up with the best match. 1514 * 1515 * <p> 1516 * Values can consist of any of the following types: 1517 * <ul> 1518 * <li>Any subclass of {@link PojoSwap}. 1519 * <li>Any instance of {@link PojoSwap}. 1520 * <li>Any surrogate class. A shortcut for defining a {@link SurrogateSwap}. 1521 * <li>Any array or collection of the objects above. 1522 * </ul> 1523 * 1524 * <h5 class='section'>Example:</h5> 1525 * <p class='bcode w800'> 1526 * <jc>// Sample swap for converting Dates to ISO8601 strings.</jc> 1527 * <jk>public class</jk> MyDateSwap <jk>extends</jk> StringSwap<Date> { 1528 * <jc>// ISO8601 formatter.</jc> 1529 * <jk>private</jk> DateFormat <jf>format</jf> = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>); 1530 * 1531 * <ja>@Override</ja> 1532 * <jk>public</jk> String swap(BeanSession session, Date o) { 1533 * <jk>return</jk> <jf>format</jf>.format(o); 1534 * } 1535 * 1536 * <ja>@Override</ja> 1537 * <jk>public</jk> Date unswap(BeanSession session, String o, ClassMeta hint) <jk>throws</jk> Exception { 1538 * <jk>return</jk> <jf>format</jf>.parse(o); 1539 * } 1540 * } 1541 * 1542 * <jc>// Sample bean with a Date field.</jc> 1543 * <jk>public class</jk> MyBean { 1544 * <jk>public</jk> Date <jf>date</jf> = <jk>new</jk> Date(112, 2, 3, 4, 5, 6); 1545 * } 1546 * 1547 * <jc>// Create a serializer that uses our date swap.</jc> 1548 * WriterSerializer s = JsonSerializer 1549 * .<jsm>create</jsm>() 1550 * .pojoSwaps(MyDateSwap.<jk>class</jk>) 1551 * .build(); 1552 * 1553 * <jc>// Same, but use property.</jc> 1554 * WriterSerializer s = JsonSerializer 1555 * .<jsm>create</jsm>() 1556 * .addTo(<jsf>BEAN_pojoSwaps</jsf>, MyDateSwap.<jk>class</jk>) 1557 * .build(); 1558 * 1559 * <jc>// Produces "{date:'2012-03-03T04:05:06-0500'}"</jc> 1560 * String json = s.serialize(<jk>new</jk> MyBean()); 1561 * 1562 * <jc>// Create a serializer that uses our date swap.</jc> 1563 * ReaderParser p = JsonParser 1564 * .<jsm>create</jsm>() 1565 * .pojoSwaps(MyDateSwap.<jk>class</jk>) 1566 * .build(); 1567 * 1568 * <jc>// Use our parser to parse a bean.</jc> 1569 * MyBean bean = p.parse(json, MyBean.<jk>class</jk>); 1570 * </p> 1571 * 1572 * <ul class='seealso'> 1573 * <li class='link'>{@doc juneau-marshall.Transforms.PojoSwaps} 1574 * <li class='link'>{@doc juneau-marshall.Transforms.PerMediaTypePojoSwaps} 1575 * <li class='link'>{@doc juneau-marshall.Transforms.OneWayPojoSwaps} 1576 * <li class='link'>{@doc juneau-marshall.Transforms.SwapAnnotation} 1577 * <li class='link'>{@doc juneau-marshall.Transforms.AutoPojoSwaps} 1578 * <li class='link'>{@doc juneau-marshall.Transforms.SurrogateClasses} 1579 * </ul> 1580 */ 1581 public static final String BEAN_pojoSwaps = PREFIX + ".pojoSwaps.lo"; 1582 1583 /** 1584 * Configuration property: Add to POJO swap classes. 1585 */ 1586 public static final String BEAN_pojoSwaps_add = PREFIX + ".pojoSwaps.lo/add"; 1587 1588 /** 1589 * Configuration property: Remove from POJO swap classes. 1590 */ 1591 public static final String BEAN_pojoSwaps_remove = PREFIX + ".pojoSwaps.lo/remove"; 1592 1593 /** 1594 * Configuration property: Bean property namer. 1595 * 1596 * <h5 class='section'>Property:</h5> 1597 * <ul> 1598 * <li><b>Name:</b> <js>"BeanContext.propertyNamer.c"</js> 1599 * <li><b>Data type:</b> <code>Class<? <jk>implements</jk> {@link PropertyNamer}></code> 1600 * <li><b>Default:</b> {@link PropertyNamerDefault} 1601 * <li><b>Session property:</b> <jk>false</jk> 1602 * <li><b>Annotations:</b> 1603 * <ul> 1604 * <li class='ja'>{@link Bean#propertyNamer()} 1605 * </ul> 1606 * <li><b>Methods:</b> 1607 * <ul> 1608 * <li class='jm'>{@link BeanContextBuilder#propertyNamer(Class)} 1609 * <li class='jm'>{@link BeanFilterBuilder#propertyNamer(Class)} 1610 * </ul> 1611 * </ul> 1612 * 1613 * <h5 class='section'>Description:</h5> 1614 * <p> 1615 * The class to use for calculating bean property names. 1616 * 1617 * <p> 1618 * Predefined classes: 1619 * <ul> 1620 * <li>{@link PropertyNamerDefault} - Default. 1621 * <li>{@link PropertyNamerDLC} - Dashed-lower-case names. 1622 * <li>{@link PropertyNamerULC} - Dashed-upper-case names. 1623 * </ul> 1624 * 1625 * <h5 class='section'>Example:</h5> 1626 * <p class='bcode w800'> 1627 * <jc>// Create a serializer that uses Dashed-Lower-Case property names.</jc> 1628 * <jc>// (e.g. "foo-bar-url" instead of "fooBarURL")</jc> 1629 * WriterSerializer s = JsonSerializer 1630 * .<jsm>create</jsm>() 1631 * .propertyNamer(PropertyNamerDLC.<jk>class</jk>) 1632 * .build(); 1633 * 1634 * <jc>// Same, but use property.</jc> 1635 * WriterSerializer s = JsonSerializer 1636 * .<jsm>create</jsm>() 1637 * .set(<jsf>BEAN_propertyNamer</jsf>, PropertyNamerDLC.<jk>class</jk>) 1638 * .build(); 1639 * </p> 1640 */ 1641 public static final String BEAN_propertyNamer = PREFIX + ".propertyNamer.c"; 1642 1643 /** 1644 * Configuration property: Sort bean properties. 1645 * 1646 * <h5 class='section'>Property:</h5> 1647 * <ul> 1648 * <li><b>Name:</b> <js>"BeanContext.sortProperties.b"</js> 1649 * <li><b>Data type:</b> <c>Boolean</c> 1650 * <li><b>Default:</b> <jk>false</jk> 1651 * <li><b>Session property:</b> <jk>false</jk> 1652 * <li><b>Annotations:</b> 1653 * <ul> 1654 * <li class='ja'>{@link Bean#sort()} 1655 * </ul> 1656 * <li><b>Methods:</b> 1657 * <ul> 1658 * <li class='jm'>{@link BeanContextBuilder#sortProperties(boolean)} 1659 * <li class='jm'>{@link BeanContextBuilder#sortProperties()} 1660 * <li class='jm'>{@link BeanFilterBuilder#sortProperties(boolean)} 1661 * <li class='jm'>{@link BeanFilterBuilder#sortProperties()} 1662 * </ul> 1663 * </ul> 1664 * 1665 * <h5 class='section'>Description:</h5> 1666 * <p> 1667 * When <jk>true</jk>, all bean properties will be serialized and access in alphabetical order. 1668 * <br>Otherwise, the natural order of the bean properties is used which is dependent on the JVM vendor. 1669 * <br>On IBM JVMs, the bean properties are ordered based on their ordering in the Java file. 1670 * <br>On Oracle JVMs, the bean properties are not ordered (which follows the official JVM specs). 1671 * 1672 * <p> 1673 * This property is disabled by default so that IBM JVM users don't have to use {@link Bean @Bean} annotations 1674 * to force bean properties to be in a particular order and can just alter the order of the fields/methods 1675 * in the Java file. 1676 * 1677 * <h5 class='section'>Example:</h5> 1678 * <p class='bcode w800'> 1679 * <jc>// Create a serializer that sorts bean properties.</jc> 1680 * WriterSerializer s = JsonSerializer 1681 * .<jsm>create</jsm>() 1682 * .sortProperties() 1683 * .build(); 1684 * 1685 * <jc>// Same, but use property.</jc> 1686 * WriterSerializer s = JsonSerializer 1687 * .<jsm>create</jsm>() 1688 * .set(<jsf>BEAN_sortProperties</jsf>, <jk>true</jk>) 1689 * .build(); 1690 * </p> 1691 */ 1692 public static final String BEAN_sortProperties = PREFIX + ".sortProperties.b"; 1693 1694 /** 1695 * Configuration property: Time zone. 1696 * 1697 * <h5 class='section'>Property:</h5> 1698 * <ul> 1699 * <li><b>Name:</b> <js>"BeanContext.timeZone.s"</js> 1700 * <li><b>Data type:</b> <c>String</c> ({@link TimeZone}) 1701 * <li><b>Default:</b> <jk>null</jk> 1702 * <li><b>Session property:</b> <jk>true</jk> 1703 * <li><b>Methods:</b> 1704 * <ul> 1705 * <li class='jm'>{@link BeanContextBuilder#timeZone(TimeZone)} 1706 * <li class='jm'>{@link BeanSessionArgs#timeZone(TimeZone)} 1707 * </ul> 1708 * </ul> 1709 * 1710 * <h5 class='section'>Description:</h5> 1711 * <p> 1712 * Specifies the default timezone for serializer and parser sessions. 1713 * 1714 * <h5 class='section'>Example:</h5> 1715 * <p class='bcode w800'> 1716 * <jc>// Create a serializer that uses GMT if the timezone is not specified in the session args.</jc> 1717 * WriterSerializer s = JsonSerializer 1718 * .<jsm>create</jsm>() 1719 * .timeZone(TimeZone.<jsf>GMT</jsf>) 1720 * .build(); 1721 * 1722 * <jc>// Same, but use property.</jc> 1723 * WriterSerializer s = JsonSerializer 1724 * .<jsm>create</jsm>() 1725 * .set(<jsf>BEAN_timeZone</jsf>, TimeZone.<jsf>GMT</jsf>) 1726 * .build(); 1727 * 1728 * <jc>// Define on session-args instead.</jc> 1729 * SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().timeZone(TimeZone.<jsf>GMT</jsf>); 1730 * <jk>try</jk> (WriterSerializerSession ss = JsonSerializer.<jsf>DEFAULT</jsf>.createSession(sessionArgs)) { 1731 * String json = s.serialize(<jk>new</jk> MyBean()); 1732 * } 1733 * </p> 1734 */ 1735 public static final String BEAN_timeZone = PREFIX + ".timeZone.s"; 1736 1737 /** 1738 * Configuration property: Use enum names. 1739 * 1740 * <h5 class='section'>Property:</h5> 1741 * <ul> 1742 * <li><b>Name:</b> <js>"BeanContext.useEnumNames.b"</js> 1743 * <li><b>Data type:</b> <c>Boolean</c> 1744 * <li><b>Default:</b> <jk>false</jk> 1745 * <li><b>Session property:</b> <jk>false</jk> 1746 * <li><b>Methods:</b> 1747 * <ul> 1748 * <li class='jm'>{@link BeanContextBuilder#useEnumNames()} 1749 * </ul> 1750 * </ul> 1751 * 1752 * <h5 class='section'>Description:</h5> 1753 * <p> 1754 * When enabled, enums are always serialized by name, not using {@link Object#toString()}. 1755 * 1756 * <h5 class='section'>Example:</h5> 1757 * <p class='bcode w800'> 1758 * <jc>// Create a serializer with debug enabled.</jc> 1759 * WriterSerializer s = JsonSerializer 1760 * .<jsm>create</jsm>() 1761 * .useEnumNames() 1762 * .build(); 1763 * 1764 * <jc>// Same, but use property.</jc> 1765 * WriterSerializer s = JsonSerializer 1766 * .<jsm>create</jsm>() 1767 * .set(<jsf>BEAN_useEnumNames</jsf>, <jk>true</jk>) 1768 * .build(); 1769 * 1770 * <jc>// Enum with overridden toString().</jc> 1771 * <jc>// Will be serialized as ONE/TWO/THREE even though there's a toString() method.. 1772 * <jk>public enum</jk> Option { 1773 * <jsf>ONE</jsf>(1), 1774 * <jsf>TWO</jsf>(2), 1775 * <jsf>THREE</jsf>(3); 1776 * 1777 * <jk>private int</jk> <jf>i</jf>; 1778 * 1779 * Option(<jk>int</jk> i) { 1780 * <jk>this</jk>.<jf>i</jf> = i; 1781 * } 1782 * 1783 * <ja>@Override</ja> 1784 * <jk>public</jk> String toString() { 1785 * <jk>return</jk> String.<jsm>valueOf</jsm>(<jf>i</jf>); 1786 * } 1787 * </p> 1788 */ 1789 public static final String BEAN_useEnumNames = PREFIX + ".useEnumNames.b"; 1790 1791 /** 1792 * Configuration property: Use interface proxies. 1793 * 1794 * <h5 class='section'>Property:</h5> 1795 * <ul> 1796 * <li><b>Name:</b> <js>"BeanContext.useInterfaceProxies.b"</js> 1797 * <li><b>Data type:</b> <c>Boolean</c> 1798 * <li><b>Default:</b> <jk>true</jk> 1799 * <li><b>Session property:</b> <jk>false</jk> 1800 * <li><b>Methods:</b> 1801 * <ul> 1802 * <li class='jm'>{@link BeanContextBuilder#useInterfaceProxies(boolean)} 1803 * </ul> 1804 * </ul> 1805 * 1806 * <h5 class='section'>Description:</h5> 1807 * <p> 1808 * If <jk>true</jk>, then interfaces will be instantiated as proxy classes through the use of an 1809 * {@link InvocationHandler} if there is no other way of instantiating them. 1810 * <br>Otherwise, throws a {@link BeanRuntimeException}. 1811 * 1812 * <h5 class='section'>Example:</h5> 1813 * <p class='bcode w800'> 1814 * <jc>// Create a parser that doesn't try to make interface proxies.</jc> 1815 * ReaderParser p = JsonParser 1816 * .<jsm>create</jsm>() 1817 * .useInterfaceProxies(<jk>false</jk>) 1818 * .build(); 1819 * 1820 * <jc>// Same, but use property.</jc> 1821 * ReaderParser p = JsonParser 1822 * .<jsm>create</jsm>() 1823 * .set(<jsf>BEAN_useInterfaceProxies</jsf>, <jk>false</jk>) 1824 * .build(); 1825 * </p> 1826 */ 1827 public static final String BEAN_useInterfaceProxies = PREFIX + ".useInterfaceProxies.b"; 1828 1829 /** 1830 * Configuration property: Use Java Introspector. 1831 * 1832 * <h5 class='section'>Property:</h5> 1833 * <ul> 1834 * <li><b>Name:</b> <js>"BeanContext.useJavaBeanIntrospector.b"</js> 1835 * <li><b>Data type:</b> <c>Boolean</c> 1836 * <li><b>Default:</b> <jk>false</jk> 1837 * <li><b>Session property:</b> <jk>false</jk> 1838 * <li><b>Methods:</b> 1839 * <ul> 1840 * <li class='jm'>{@link BeanContextBuilder#useJavaBeanIntrospector(boolean)} 1841 * <li class='jm'>{@link BeanContextBuilder#useJavaBeanIntrospector()} 1842 * </ul> 1843 * </ul> 1844 * 1845 * <h5 class='section'>Description:</h5> 1846 * <p> 1847 * Using the built-in Java bean introspector will not pick up fields or non-standard getters/setters. 1848 * <br>Most {@link Bean @Bean} annotations will be ignored. 1849 * 1850 * <h5 class='section'>Example:</h5> 1851 * <p class='bcode w800'> 1852 * <jc>// Create a serializer that only uses the built-in java bean introspector for finding properties.</jc> 1853 * WriterSerializer s = JsonSerializer 1854 * .<jsm>create</jsm>() 1855 * .useJavaBeanIntrospector(<jk>false</jk>) 1856 * .build(); 1857 * 1858 * <jc>// Same, but use property.</jc> 1859 * WriterSerializer s = JsonSerializer 1860 * .<jsm>create</jsm>() 1861 * .set(<jsf>BEAN_useJavaBeanIntrospector</jsf>, <jk>false</jk>) 1862 * .build(); 1863 * </p> 1864 */ 1865 public static final String BEAN_useJavaBeanIntrospector = PREFIX + ".useJavaBeanIntrospector.b"; 1866 1867 /* 1868 * The default package pattern exclusion list. 1869 * Any beans in packages in this list will not be considered beans. 1870 */ 1871 private static final String[] DEFAULT_NOTBEAN_PACKAGES = { 1872 "java.lang", 1873 "java.lang.annotation", 1874 "java.lang.ref", 1875 "java.lang.reflect", 1876 "java.io", 1877 "java.net", 1878 "java.nio.*", 1879 "java.util.*" 1880 }; 1881 1882 /* 1883 * The default bean class exclusion list. 1884 * Anything in this list will not be considered beans. 1885 */ 1886 private static final Class<?>[] DEFAULT_NOTBEAN_CLASSES = { 1887 Map.class, 1888 Collection.class, 1889 Reader.class, 1890 Writer.class, 1891 InputStream.class, 1892 OutputStream.class, 1893 Throwable.class 1894 }; 1895 1896 1897 // This map is important! 1898 // We may have many Context objects that have identical BeanContext properties. 1899 // This map ensures that if the BeanContext properties in the Context are the same, 1900 // then we reuse the same Class->ClassMeta cache map. 1901 // This significantly reduces the number of times we need to construct ClassMeta objects which can be expensive. 1902 private static final ConcurrentHashMap<Integer,Map<Class,ClassMeta>> cmCacheCache 1903 = new ConcurrentHashMap<>(); 1904 1905 /** Default config. All default settings. */ 1906 public static final BeanContext DEFAULT = BeanContext.create().build(); 1907 1908 /** Default config. All default settings except sort bean properties. */ 1909 public static final BeanContext DEFAULT_SORTED = BeanContext.create().sortProperties().build(); 1910 1911 private final boolean 1912 beansRequireDefaultConstructor, 1913 beansRequireSerializable, 1914 beansRequireSettersForGetters, 1915 beansRequireSomeProperties, 1916 beanMapPutReturnsOldValue, 1917 useInterfaceProxies, 1918 ignoreUnknownBeanProperties, 1919 ignoreUnknownNullBeanProperties, 1920 ignorePropertiesWithoutSetters, 1921 ignoreInvocationExceptionsOnGetters, 1922 ignoreInvocationExceptionsOnSetters, 1923 useJavaBeanIntrospector, 1924 useEnumNames, 1925 sortProperties, 1926 fluentSetters, 1927 debug; 1928 1929 private final Visibility 1930 beanConstructorVisibility, 1931 beanClassVisibility, 1932 beanMethodVisibility, 1933 beanFieldVisibility; 1934 1935 private final Class<?>[] notBeanClasses; 1936 private final List<Class<?>> beanDictionaryClasses; 1937 private final String[] notBeanPackageNames, notBeanPackagePrefixes; 1938 private final BeanFilter[] beanFilters; 1939 private final PojoSwap<?,?>[] pojoSwaps; 1940 private final Map<String,?> examples; 1941 private final BeanRegistry beanRegistry; 1942 private final Map<String,ClassInfo> implClasses; 1943 private final Locale locale; 1944 private final TimeZone timeZone; 1945 private final MediaType mediaType; 1946 private final Map<String,String[]> includeProperties, excludeProperties; 1947 private final PropertyNamer propertyNamer; 1948 private final String beanTypePropertyName; 1949 private final int beanHashCode; 1950 1951 final Map<Class,ClassMeta> cmCache; 1952 private final ClassMeta<Object> cmObject; // Reusable ClassMeta that represents general Objects. 1953 private final ClassMeta<String> cmString; // Reusable ClassMeta that represents general Strings. 1954 private final ClassMeta<Class> cmClass; // Reusable ClassMeta that represents general Classes. 1955 1956 1957 /** 1958 * Constructor. 1959 * 1960 * <p> 1961 * Typically only called from {@link ContextBuilder#build(Class)} method. 1962 * 1963 * @param ps The property store containing the unmodifiable configuration for this bean context. 1964 */ 1965 public BeanContext(PropertyStore ps) { 1966 super(ps, true); 1967 1968 if (ps == null) 1969 ps = PropertyStore.DEFAULT; 1970 1971 beanHashCode = ps.hashCode("BeanContext"); 1972 1973 beansRequireDefaultConstructor = getBooleanProperty(BEAN_beansRequireDefaultConstructor, false); 1974 beansRequireSerializable = getBooleanProperty(BEAN_beansRequireSerializable, false); 1975 beansRequireSettersForGetters = getBooleanProperty(BEAN_beansRequireSettersForGetters, false); 1976 beansRequireSomeProperties = getBooleanProperty(BEAN_beansRequireSomeProperties, true); 1977 beanMapPutReturnsOldValue = getBooleanProperty(BEAN_beanMapPutReturnsOldValue, false); 1978 useEnumNames = getBooleanProperty(BEAN_useEnumNames, false); 1979 useInterfaceProxies = getBooleanProperty(BEAN_useInterfaceProxies, true); 1980 ignoreUnknownBeanProperties = getBooleanProperty(BEAN_ignoreUnknownBeanProperties, false); 1981 ignoreUnknownNullBeanProperties = getBooleanProperty(BEAN_ignoreUnknownNullBeanProperties, true); 1982 ignorePropertiesWithoutSetters = getBooleanProperty(BEAN_ignorePropertiesWithoutSetters, true); 1983 ignoreInvocationExceptionsOnGetters = getBooleanProperty(BEAN_ignoreInvocationExceptionsOnGetters, false); 1984 ignoreInvocationExceptionsOnSetters = getBooleanProperty(BEAN_ignoreInvocationExceptionsOnSetters, false); 1985 useJavaBeanIntrospector = getBooleanProperty(BEAN_useJavaBeanIntrospector, false); 1986 sortProperties = getBooleanProperty(BEAN_sortProperties, false); 1987 fluentSetters = getBooleanProperty(BEAN_fluentSetters, false); 1988 beanTypePropertyName = getStringProperty(BEAN_beanTypePropertyName, "_type"); 1989 debug = getBooleanProperty(BEAN_debug, false); 1990 1991 beanConstructorVisibility = getProperty(BEAN_beanConstructorVisibility, Visibility.class, PUBLIC); 1992 beanClassVisibility = getProperty(BEAN_beanClassVisibility, Visibility.class, PUBLIC); 1993 beanMethodVisibility = getProperty(BEAN_beanMethodVisibility, Visibility.class, PUBLIC); 1994 beanFieldVisibility = getProperty(BEAN_beanFieldVisibility, Visibility.class, PUBLIC); 1995 1996 notBeanClasses = getClassArrayProperty(BEAN_notBeanClasses, DEFAULT_NOTBEAN_CLASSES); 1997 1998 propertyNamer = getInstanceProperty(BEAN_propertyNamer, PropertyNamer.class, PropertyNamerDefault.class); 1999 2000 List<String> l1 = new LinkedList<>(); 2001 List<String> l2 = new LinkedList<>(); 2002 for (String s : getArrayProperty(BEAN_notBeanPackages, String.class, DEFAULT_NOTBEAN_PACKAGES)) { 2003 if (s.endsWith(".*")) 2004 l2.add(s.substring(0, s.length()-2)); 2005 else 2006 l1.add(s); 2007 } 2008 notBeanPackageNames = l1.toArray(new String[l1.size()]); 2009 notBeanPackagePrefixes = l2.toArray(new String[l2.size()]); 2010 2011 LinkedList<BeanFilter> lbf = new LinkedList<>(); 2012 for (Class<?> c : getClassListProperty(BEAN_beanFilters)) { 2013 ClassInfo ci = ClassInfo.of(c); 2014 if (ci.isChildOf(BeanFilter.class)) 2015 lbf.add(castOrCreate(BeanFilter.class, c)); 2016 else if (ci.isChildOf(BeanFilterBuilder.class)) 2017 lbf.add(castOrCreate(BeanFilterBuilder.class, c).build()); 2018 else 2019 lbf.add(new InterfaceBeanFilterBuilder(c).build()); 2020 } 2021 beanFilters = lbf.toArray(new BeanFilter[0]); 2022 2023 LinkedList<PojoSwap<?,?>> lpf = new LinkedList<>(); 2024 for (Object o : getListProperty(BEAN_pojoSwaps, Object.class)) { 2025 if (o instanceof Class) { 2026 ClassInfo ci = ClassInfo.of((Class<?>)o); 2027 if (ci.isChildOf(PojoSwap.class)) 2028 lpf.add(castOrCreate(PojoSwap.class, ci.inner())); 2029 else if (ci.isChildOf(Surrogate.class)) 2030 lpf.addAll(SurrogateSwap.findPojoSwaps(ci.inner())); 2031 else 2032 throw new FormattedRuntimeException("Invalid class {0} specified in BeanContext.pojoSwaps property. Must be a subclass of PojoSwap or Surrogate.", ci.inner()); 2033 } else if (o instanceof PojoSwap) { 2034 lpf.add((PojoSwap)o); 2035 } 2036 } 2037 pojoSwaps = lpf.toArray(new PojoSwap[lpf.size()]); 2038 2039 examples = getMapProperty(BEAN_examples, Object.class); 2040 2041 Map<String,ClassInfo> icm = new LinkedHashMap<>(); 2042 for (Map.Entry<String,Class<?>> e : getClassMapProperty(BEAN_implClasses).entrySet()) 2043 icm.put(e.getKey(), ClassInfo.of(e.getValue())); 2044 implClasses = unmodifiableMap(icm); 2045 2046 Map<String,String[]> m2 = new HashMap<>(); 2047 for (Map.Entry<String,String> e : getMapProperty(BEAN_includeProperties, String.class).entrySet()) 2048 m2.put(e.getKey(), StringUtils.split(e.getValue())); 2049 includeProperties = unmodifiableMap(m2); 2050 2051 m2 = new HashMap<>(); 2052 for (Map.Entry<String,String> e : getMapProperty(BEAN_excludeProperties, String.class).entrySet()) 2053 m2.put(e.getKey(), StringUtils.split(e.getValue())); 2054 excludeProperties = unmodifiableMap(m2); 2055 2056 locale = getInstanceProperty(BEAN_locale, Locale.class, Locale.getDefault()); 2057 timeZone = getInstanceProperty(BEAN_timeZone, TimeZone.class, null); 2058 mediaType = getInstanceProperty(BEAN_mediaType, MediaType.class, null); 2059 2060 if (! cmCacheCache.containsKey(beanHashCode)) { 2061 ConcurrentHashMap<Class,ClassMeta> cm = new ConcurrentHashMap<>(); 2062 cm.putIfAbsent(String.class, new ClassMeta(String.class, this, null, null, findPojoSwaps(String.class), findChildPojoSwaps(String.class), findExample(String.class))); 2063 cm.putIfAbsent(Object.class, new ClassMeta(Object.class, this, null, null, findPojoSwaps(Object.class), findChildPojoSwaps(Object.class), findExample(Object.class))); 2064 cmCacheCache.putIfAbsent(beanHashCode, cm); 2065 } 2066 cmCache = cmCacheCache.get(beanHashCode); 2067 cmString = cmCache.get(String.class); 2068 cmObject = cmCache.get(Object.class); 2069 cmClass = cmCache.get(Class.class); 2070 2071 beanDictionaryClasses = unmodifiableList(Arrays.asList(getClassArrayProperty(BEAN_beanDictionary))); 2072 beanRegistry = new BeanRegistry(this, null); 2073 } 2074 2075 @Override /* Context */ 2076 public BeanContextBuilder builder() { 2077 return new BeanContextBuilder(getPropertyStore()); 2078 } 2079 2080 /** 2081 * Instantiates a new clean-slate {@link BeanContextBuilder} object. 2082 * 2083 * <p> 2084 * This is equivalent to simply calling <code><jk>new</jk> BeanContextBuilder()</code>. 2085 * 2086 * @return A new {@link JsonSerializerBuilder} object. 2087 */ 2088 public static BeanContextBuilder create() { 2089 return new BeanContextBuilder(); 2090 } 2091 2092 /** 2093 * Create a new bean session based on the properties defined on this context. 2094 * 2095 * <p> 2096 * Use this method for creating sessions if you don't need to override any 2097 * properties or locale/timezone currently set on this context. 2098 * 2099 * @return A new session object. 2100 */ 2101 @Override /* Context */ 2102 public BeanSession createSession() { 2103 return createBeanSession(createDefaultSessionArgs()); 2104 } 2105 2106 /** 2107 * Create a new bean session based on the properties defined on this context combined with the specified 2108 * runtime args. 2109 * 2110 * <p> 2111 * Use this method for creating sessions if you don't need to override any 2112 * properties or locale/timezone currently set on this context. 2113 * 2114 * @param args 2115 * The session arguments. 2116 * @return A new session object. 2117 */ 2118 public BeanSession createSession(BeanSessionArgs args) { 2119 return createBeanSession(args); 2120 } 2121 2122 @Override /* Context */ 2123 public final Session createSession(SessionArgs args) { 2124 throw new NoSuchMethodError(); 2125 } 2126 2127 /** 2128 * Same as {@link #createSession(BeanSessionArgs)} except always returns a {@link BeanSession} object unlike {@link #createSession(BeanSessionArgs)} 2129 * which is meant to be overridden by subclasses. 2130 * 2131 * @param args The session arguments. 2132 * @return A new session object. 2133 */ 2134 public final BeanSession createBeanSession(BeanSessionArgs args) { 2135 return new BeanSession(this, args); 2136 } 2137 2138 /** 2139 * Same as {@link #createSession()} except always returns a {@link BeanSession} object unlike {@link #createSession()} 2140 * which is meant to be overridden by subclasses. 2141 * 2142 * @return A new session object. 2143 */ 2144 public final BeanSession createBeanSession() { 2145 return new BeanSession(this, createDefaultBeanSessionArgs()); 2146 } 2147 2148 @Override /* Context */ 2149 public BeanSessionArgs createDefaultSessionArgs() { 2150 return createDefaultBeanSessionArgs(); 2151 } 2152 2153 /** 2154 * Same as {@link #createDefaultSessionArgs()} except always returns a {@link BeanSessionArgs} unlike 2155 * {@link #createDefaultBeanSessionArgs()} which is meant to be overridden by subclasses. 2156 * 2157 * @return A new session arguments object. 2158 */ 2159 public final BeanSessionArgs createDefaultBeanSessionArgs() { 2160 return new BeanSessionArgs(); 2161 } 2162 2163 /** 2164 * Returns <jk>true</jk> if the specified bean context shares the same cache as this bean context. 2165 * 2166 * <p> 2167 * Useful for testing purposes. 2168 * 2169 * @param bc The bean context to compare to. 2170 * @return <jk>true</jk> if the bean contexts have equivalent settings and thus share caches. 2171 */ 2172 public final boolean hasSameCache(BeanContext bc) { 2173 return bc.cmCache == this.cmCache; 2174 } 2175 2176 /** 2177 * Determines whether the specified class is ignored as a bean class based on the various exclusion parameters 2178 * specified on this context class. 2179 * 2180 * @param c The class type being tested. 2181 * @return <jk>true</jk> if the specified class matches any of the exclusion parameters. 2182 */ 2183 protected final boolean isNotABean(Class<?> c) { 2184 if (c.isArray() || c.isPrimitive() || c.isEnum() || c.isAnnotation()) 2185 return true; 2186 Package p = c.getPackage(); 2187 if (p != null) { 2188 for (String p2 : notBeanPackageNames) 2189 if (p.getName().equals(p2)) 2190 return true; 2191 for (String p2 : notBeanPackagePrefixes) 2192 if (p.getName().startsWith(p2)) 2193 return true; 2194 } 2195 ClassInfo ci = ClassInfo.of(c); 2196 for (Class exclude : notBeanClasses) 2197 if (ci.isChildOf(exclude)) 2198 return true; 2199 return false; 2200 } 2201 2202 /** 2203 * Returns <jk>true</jk> if the specified object is a bean. 2204 * 2205 * @param o The object to test. 2206 * @return <jk>true</jk> if the specified object is a bean. <jk>false</jk> if the bean is <jk>null</jk>. 2207 */ 2208 public boolean isBean(Object o) { 2209 if (o == null) 2210 return false; 2211 return getClassMetaForObject(o).isBean(); 2212 } 2213 2214 /** 2215 * Prints meta cache statistics to <c>System.out</c>. 2216 */ 2217 protected static void dumpCacheStats() { 2218 try { 2219 int ctCount = 0; 2220 for (Map<Class,ClassMeta> cm : cmCacheCache.values()) 2221 ctCount += cm.size(); 2222 System.out.println(format("ClassMeta cache: {0} instances in {1} caches", ctCount, cmCacheCache.size())); // NOT DEBUG 2223 } catch (Exception e) { 2224 e.printStackTrace(); 2225 } 2226 } 2227 2228 /** 2229 * Returns the {@link BeanMeta} class for the specified class. 2230 * 2231 * @param <T> The class type to get the meta-data on. 2232 * @param c The class to get the meta-data on. 2233 * @return 2234 * The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class is not a bean per the settings on 2235 * this context. 2236 */ 2237 public final <T> BeanMeta<T> getBeanMeta(Class<T> c) { 2238 if (c == null) 2239 return null; 2240 return getClassMeta(c).getBeanMeta(); 2241 } 2242 2243 /** 2244 * Construct a {@code ClassMeta} wrapper around a {@link Class} object. 2245 * 2246 * @param <T> The class type being wrapped. 2247 * @param type The class to resolve. 2248 * @return 2249 * If the class is not an array, returns a cached {@link ClassMeta} object. 2250 * Otherwise, returns a new {@link ClassMeta} object every time. 2251 */ 2252 public final <T> ClassMeta<T> getClassMeta(Class<T> type) { 2253 return getClassMeta(type, true); 2254 } 2255 2256 /** 2257 * Construct a {@code ClassMeta} wrapper around a {@link Class} object. 2258 * 2259 * @param <T> The class type being wrapped. 2260 * @param type The class to resolve. 2261 * @param waitForInit 2262 * If <jk>true</jk>, wait for the ClassMeta constructor to finish before returning. 2263 * @return 2264 * If the class is not an array, returns a cached {@link ClassMeta} object. 2265 * Otherwise, returns a new {@link ClassMeta} object every time. 2266 */ 2267 final <T> ClassMeta<T> getClassMeta(Class<T> type, boolean waitForInit) { 2268 2269 // If this is an array, then we want it wrapped in an uncached ClassMeta object. 2270 // Note that if it has a pojo swap, we still want to cache it so that 2271 // we can cache something like byte[] with ByteArraySwap.Base64. 2272 if (type.isArray() && findPojoSwaps(type) == null) 2273 return new ClassMeta(type, this, findImplClass(type), findBeanFilter(type), findPojoSwaps(type), findChildPojoSwaps(type), findExample(type)); 2274 2275 // This can happen if we have transforms defined against String or Object. 2276 if (cmCache == null) 2277 return null; 2278 2279 ClassMeta<T> cm = cmCache.get(type); 2280 if (cm == null) { 2281 2282 synchronized (this) { 2283 // Make sure someone didn't already set it while this thread was blocked. 2284 cm = cmCache.get(type); 2285 if (cm == null) 2286 cm = new ClassMeta<>(type, this, findImplClass(type), findBeanFilter(type), findPojoSwaps(type), findChildPojoSwaps(type), findExample(type)); 2287 } 2288 } 2289 if (waitForInit) 2290 cm.waitForInit(); 2291 return cm; 2292 } 2293 2294 /** 2295 * Used to resolve <c>ClassMetas</c> of type <c>Collection</c> and <c>Map</c> that have 2296 * <c>ClassMeta</c> values that themselves could be collections or maps. 2297 * 2298 * <p> 2299 * <c>Collection</c> meta objects are assumed to be followed by zero or one meta objects indicating the element type. 2300 * 2301 * <p> 2302 * <c>Map</c> meta objects are assumed to be followed by zero or two meta objects indicating the key and value types. 2303 * 2304 * <p> 2305 * The array can be arbitrarily long to indicate arbitrarily complex data structures. 2306 * 2307 * <h5 class='section'>Examples:</h5> 2308 * <ul> 2309 * <li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type. 2310 * <li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects. 2311 * <li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings. 2312 * <li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing 2313 * strings. 2314 * <li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - 2315 * A linked-list containing linked-lists of strings. 2316 * <li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values. 2317 * <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map 2318 * containing string keys/values. 2319 * <li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> - 2320 * A map containing string keys and values of lists containing beans. 2321 * </ul> 2322 * 2323 * @param type 2324 * The class to resolve. 2325 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 2326 * @param args 2327 * The type arguments of the class if it's a collection or map. 2328 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 2329 * <br>Ignored if the main type is not a map or collection. 2330 * @return The resolved class meta. 2331 */ 2332 public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) { 2333 if (type == null) 2334 return null; 2335 ClassMeta<T> cm = type instanceof Class ? getClassMeta((Class)type) : resolveClassMeta(type, null); 2336 if (args.length == 0) 2337 return cm; 2338 ClassMeta<?>[] cma = new ClassMeta[args.length+1]; 2339 cma[0] = cm; 2340 for (int i = 0; i < Array.getLength(args); i++) { 2341 Type arg = (Type)Array.get(args, i); 2342 cma[i+1] = arg instanceof Class ? getClassMeta((Class)arg) : resolveClassMeta(arg, null); 2343 } 2344 return (ClassMeta<T>) getTypedClassMeta(cma, 0); 2345 } 2346 2347 /* 2348 * Resolves the 'genericized' class meta at the specified position in the ClassMeta array. 2349 */ 2350 private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) { 2351 ClassMeta<?> cm = c[pos++]; 2352 if (cm.isCollection() || cm.isOptional()) { 2353 ClassMeta<?> ce = c.length == pos ? object() : getTypedClassMeta(c, pos); 2354 return (ce.isObject() ? cm : new ClassMeta(cm, null, null, ce)); 2355 } else if (cm.isMap()) { 2356 ClassMeta<?> ck = c.length == pos ? object() : c[pos++]; 2357 ClassMeta<?> cv = c.length == pos ? object() : getTypedClassMeta(c, pos); 2358 return (ck.isObject() && cv.isObject() ? cm : new ClassMeta(cm, ck, cv, null)); 2359 } 2360 return cm; 2361 } 2362 2363 final ClassMeta resolveClassMeta(Type o, Map<Class<?>,Class<?>[]> typeVarImpls) { 2364 if (o == null) 2365 return null; 2366 2367 if (o instanceof ClassMeta) { 2368 ClassMeta<?> cm = (ClassMeta)o; 2369 2370 // This classmeta could have been created by a different context. 2371 // Need to re-resolve it to pick up PojoSwaps and stuff on this context. 2372 if (cm.getBeanContext() == this) 2373 return cm; 2374 if (cm.isMap()) 2375 return getClassMeta(cm.innerClass, cm.getKeyType(), cm.getValueType()); 2376 if (cm.isCollection() || cm.isOptional()) 2377 return getClassMeta(cm.innerClass, cm.getElementType()); 2378 return getClassMeta(cm.innerClass); 2379 } 2380 2381 Class c = resolve(o, typeVarImpls); 2382 2383 // This can happen when trying to resolve the "E getFirst()" method on LinkedList, whose type is a TypeVariable 2384 // These should just resolve to Object. 2385 if (c == null) 2386 return object(); 2387 2388 ClassMeta rawType = getClassMeta(c); 2389 2390 // If this is a Map or Collection, and the parameter types aren't part 2391 // of the class definition itself (e.g. class AddressBook extends List<Person>), 2392 // then we need to figure out the parameters. 2393 if (rawType.isMap() || rawType.isCollection() || rawType.isOptional()) { 2394 ClassMeta[] params = findParameters(o, c); 2395 if (params == null) 2396 return rawType; 2397 if (rawType.isMap()) { 2398 if (params.length != 2) 2399 return rawType; 2400 if (params[0].isObject() && params[1].isObject()) 2401 return rawType; 2402 return new ClassMeta(rawType, params[0], params[1], null); 2403 } 2404 if (rawType.isCollection() || rawType.isOptional()) { 2405 if (params.length != 1) 2406 return rawType; 2407 if (params[0].isObject()) 2408 return rawType; 2409 return new ClassMeta(rawType, null, null, params[0]); 2410 } 2411 } 2412 2413 if (rawType.isArray()) { 2414 if (o instanceof GenericArrayType) { 2415 GenericArrayType gat = (GenericArrayType)o; 2416 ClassMeta elementType = resolveClassMeta(gat.getGenericComponentType(), typeVarImpls); 2417 return new ClassMeta(rawType, null, null, elementType); 2418 } 2419 } 2420 2421 return rawType; 2422 } 2423 2424 /** 2425 * Convert a Type to a Class if possible. 2426 * Return null if not possible. 2427 */ 2428 final Class resolve(Type t, Map<Class<?>,Class<?>[]> typeVarImpls) { 2429 2430 if (t instanceof Class) 2431 return (Class)t; 2432 2433 if (t instanceof ParameterizedType) 2434 // A parameter (e.g. <String>. 2435 return (Class)((ParameterizedType)t).getRawType(); 2436 2437 if (t instanceof GenericArrayType) { 2438 // An array parameter (e.g. <byte[]>). 2439 Type gatct = ((GenericArrayType)t).getGenericComponentType(); 2440 2441 if (gatct instanceof Class) 2442 return Array.newInstance((Class)gatct, 0).getClass(); 2443 2444 if (gatct instanceof ParameterizedType) 2445 return Array.newInstance((Class)((ParameterizedType)gatct).getRawType(), 0).getClass(); 2446 2447 if (gatct instanceof GenericArrayType) 2448 return Array.newInstance(resolve(gatct, typeVarImpls), 0).getClass(); 2449 2450 return null; 2451 2452 } else if (t instanceof TypeVariable) { 2453 if (typeVarImpls != null) { 2454 TypeVariable tv = (TypeVariable)t; 2455 String varName = tv.getName(); 2456 int varIndex = -1; 2457 Class gc = (Class)tv.getGenericDeclaration(); 2458 TypeVariable[] tvv = gc.getTypeParameters(); 2459 for (int i = 0; i < tvv.length; i++) { 2460 if (tvv[i].getName().equals(varName)) { 2461 varIndex = i; 2462 } 2463 } 2464 if (varIndex != -1) { 2465 2466 // If we couldn't find a type variable implementation, that means 2467 // the type was defined at runtime (e.g. Bean b = new Bean<Foo>();) 2468 // in which case the type is lost through erasure. 2469 // Assume java.lang.Object as the type. 2470 if (! typeVarImpls.containsKey(gc)) 2471 return null; 2472 2473 return typeVarImpls.get(gc)[varIndex]; 2474 } 2475 } 2476 } 2477 return null; 2478 } 2479 2480 final ClassMeta[] findParameters(Type o, Class c) { 2481 if (o == null) 2482 o = c; 2483 2484 // Loop until we find a ParameterizedType 2485 if (! (o instanceof ParameterizedType)) { 2486 loop: do { 2487 o = c.getGenericSuperclass(); 2488 if (o instanceof ParameterizedType) 2489 break loop; 2490 for (Type t : c.getGenericInterfaces()) { 2491 o = t; 2492 if (o instanceof ParameterizedType) 2493 break loop; 2494 } 2495 c = c.getSuperclass(); 2496 } while (c != null); 2497 } 2498 2499 if (o instanceof ParameterizedType) { 2500 ParameterizedType pt = (ParameterizedType)o; 2501 if (! pt.getRawType().equals(Enum.class)) { 2502 List<ClassMeta<?>> l = new LinkedList<>(); 2503 for (Type pt2 : pt.getActualTypeArguments()) { 2504 if (pt2 instanceof WildcardType || pt2 instanceof TypeVariable) 2505 return null; 2506 l.add(resolveClassMeta(pt2, null)); 2507 } 2508 if (l.isEmpty()) 2509 return null; 2510 return l.toArray(new ClassMeta[l.size()]); 2511 } 2512 } 2513 2514 return null; 2515 } 2516 2517 /** 2518 * Shortcut for calling {@code getClassMeta(o.getClass())}. 2519 * 2520 * @param <T> The class of the object being passed in. 2521 * @param o The class to find the class type for. 2522 * @return The ClassMeta object, or <jk>null</jk> if {@code o} is <jk>null</jk>. 2523 */ 2524 public final <T> ClassMeta<T> getClassMetaForObject(T o) { 2525 if (o == null) 2526 return null; 2527 return (ClassMeta<T>)getClassMeta(o.getClass()); 2528 } 2529 2530 2531 /** 2532 * Used for determining the class type on a method or field where a {@code @BeanProperty} annotation may be present. 2533 * 2534 * @param <T> The class type we're wrapping. 2535 * @param p The property annotation on the type if there is one. 2536 * @param t The type. 2537 * @param typeVarImpls 2538 * Contains known resolved type parameters on the specified class so that we can result 2539 * {@code ParameterizedTypes} and {@code TypeVariables}. 2540 * Can be <jk>null</jk> if the information is not known. 2541 * @return The new {@code ClassMeta} object wrapped around the {@code Type} object. 2542 */ 2543 protected final <T> ClassMeta<T> resolveClassMeta(BeanProperty p, Type t, Map<Class<?>,Class<?>[]> typeVarImpls) { 2544 ClassMeta<T> cm = resolveClassMeta(t, typeVarImpls); 2545 ClassMeta<T> cm2 = cm; 2546 if (p != null) { 2547 2548 if (p.type() != Object.class) 2549 cm2 = resolveClassMeta(p.type(), typeVarImpls); 2550 2551 if (cm2.isMap()) { 2552 Class<?>[] pParams = (p.params().length == 0 ? new Class[]{Object.class, Object.class} : p.params()); 2553 if (pParams.length != 2) 2554 throw new FormattedRuntimeException("Invalid number of parameters specified for Map (must be 2): {0}", pParams.length); 2555 ClassMeta<?> keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType()); 2556 ClassMeta<?> valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType()); 2557 if (keyType.isObject() && valueType.isObject()) 2558 return cm2; 2559 return new ClassMeta<>(cm2, keyType, valueType, null); 2560 } 2561 2562 if (cm2.isCollection() || cm2.isOptional()) { 2563 Class<?>[] pParams = (p.params().length == 0 ? new Class[]{Object.class} : p.params()); 2564 if (pParams.length != 1) 2565 throw new FormattedRuntimeException("Invalid number of parameters specified for "+(cm2.isCollection() ? "Collection" : cm2.isOptional() ? "Optional" : "Array")+" (must be 1): {0}", pParams.length); 2566 ClassMeta<?> elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType()); 2567 if (elementType.isObject()) 2568 return cm2; 2569 return new ClassMeta<>(cm2, null, null, elementType); 2570 } 2571 2572 return cm2; 2573 } 2574 2575 return cm; 2576 } 2577 2578 private ClassMeta<?> resolveType(Type...t) { 2579 for (Type tt : t) { 2580 if (tt != null) { 2581 ClassMeta<?> cm = getClassMeta(tt); 2582 if (tt != cmObject) 2583 return cm; 2584 } 2585 } 2586 return cmObject; 2587 } 2588 2589 /** 2590 * Returns the {@link PojoSwap} associated with the specified class, or <jk>null</jk> if there is no POJO swap 2591 * associated with the class. 2592 * 2593 * @param <T> The class associated with the swap. 2594 * @param c The class associated with the swap. 2595 * @return The swap associated with the class, or null if there is no association. 2596 */ 2597 private final <T> PojoSwap[] findPojoSwaps(Class<T> c) { 2598 // Note: On first 2599 if (c != null) { 2600 List<PojoSwap> l = new ArrayList<>(); 2601 for (PojoSwap f : pojoSwaps) 2602 if (f.getNormalClass().isParentOf(c)) 2603 l.add(f); 2604 return l.size() == 0 ? null : l.toArray(new PojoSwap[l.size()]); 2605 } 2606 return null; 2607 } 2608 2609 private final Object findExample(Class<?> c) { 2610 if (c != null) { 2611 Object o = examples.get(c.getName()); 2612 if (o != null) 2613 return o; 2614 o = examples.get(c.getSimpleName()); 2615 if (o != null) 2616 return o; 2617 Class<?> c2 = findImplClass(c); 2618 if (c2 == null) 2619 return null; 2620 o = examples.get(c2.getName()); 2621 if (o != null) 2622 return o; 2623 o = examples.get(c2.getSimpleName()); 2624 return o; 2625 } 2626 return null; 2627 } 2628 2629 /** 2630 * Checks whether a class has a {@link PojoSwap} associated with it in this bean context. 2631 * 2632 * @param c The class to check. 2633 * @return <jk>true</jk> if the specified class or one of its subclasses has a {@link PojoSwap} associated with it. 2634 */ 2635 private final PojoSwap[] findChildPojoSwaps(Class<?> c) { 2636 if (c == null || pojoSwaps.length == 0) 2637 return null; 2638 List<PojoSwap> l = null; 2639 for (PojoSwap f : pojoSwaps) { 2640 if (f.getNormalClass().isChildOf(c)) { 2641 if (l == null) 2642 l = new ArrayList<>(); 2643 l.add(f); 2644 } 2645 } 2646 return l == null ? null : l.toArray(new PojoSwap[l.size()]); 2647 } 2648 2649 /** 2650 * Returns the {@link BeanFilter} associated with the specified class, or <jk>null</jk> if there is no bean filter 2651 * associated with the class. 2652 * 2653 * @param <T> The class associated with the bean filter. 2654 * @param c The class associated with the bean filter. 2655 * @return The bean filter associated with the class, or null if there is no association. 2656 */ 2657 private final <T> BeanFilter findBeanFilter(Class<T> c) { 2658 if (c != null) 2659 for (BeanFilter f : beanFilters) 2660 if (ClassInfo.of(f.getBeanClass()).isParentOf(c)) 2661 return f; 2662 return null; 2663 } 2664 2665 /** 2666 * Gets the no-arg constructor for the specified class. 2667 * 2668 * @param <T> The class to check. 2669 * @param c The class to check. 2670 * @param v The minimum visibility for the constructor. 2671 * @return The no arg constructor, or <jk>null</jk> if the class has no no-arg constructor. 2672 */ 2673 protected final <T> ConstructorInfo getImplClassConstructor(Class<T> c, Visibility v) { 2674 if (implClasses.isEmpty()) 2675 return null; 2676 Class cc = c; 2677 while (cc != null) { 2678 ClassInfo implClass = implClasses.get(cc.getName()); 2679 if (implClass != null) 2680 return implClass.getNoArgConstructor(v); 2681 for (Class ic : cc.getInterfaces()) { 2682 implClass = implClasses.get(ic.getName()); 2683 if (implClass != null) 2684 return implClass.getNoArgConstructor(v); 2685 } 2686 cc = cc.getSuperclass(); 2687 } 2688 return null; 2689 } 2690 2691 private final <T> Class<T> findImplClass(Class<T> c) { 2692 if (implClasses.isEmpty()) 2693 return null; 2694 Class cc = c; 2695 while (cc != null) { 2696 ClassInfo implClass = implClasses.get(cc.getName()); 2697 if (implClass != null) 2698 return implClass.<T>inner(); 2699 for (Class ic : cc.getInterfaces()) { 2700 implClass = implClasses.get(ic.getName()); 2701 if (implClass != null) 2702 return implClass.<T>inner(); 2703 } 2704 cc = cc.getSuperclass(); 2705 } 2706 return null; 2707 } 2708 2709 /** 2710 * Returns the {@link #BEAN_includeProperties} setting for the specified class. 2711 * 2712 * @param c The class. 2713 * @return The properties to include for the specified class, or <jk>null</jk> if it's not defined for the class. 2714 */ 2715 protected String[] getIncludeProperties(Class<?> c) { 2716 if (includeProperties.isEmpty()) 2717 return null; 2718 String[] s = null; 2719 ClassInfo ci = ClassInfo.of(c); 2720 for (ClassInfo c2 : ci.getAllParents()) { 2721 s = includeProperties.get(c2.getFullName()); 2722 if (s != null) 2723 return s; 2724 s = includeProperties.get(c2.getSimpleName()); 2725 if (s != null) 2726 return s; 2727 } 2728 return includeProperties.get("*"); 2729 } 2730 2731 /** 2732 * Returns the {@link #BEAN_excludeProperties} setting for the specified class. 2733 * 2734 * @param c The class. 2735 * @return The properties to exclude for the specified class, or <jk>null</jk> if it's not defined for the class. 2736 */ 2737 protected String[] getExcludeProperties(Class<?> c) { 2738 if (excludeProperties.isEmpty()) 2739 return null; 2740 String[] s = null; 2741 ClassInfo ci = ClassInfo.of(c); 2742 for (ClassInfo c2 : ci.getAllParents()) { 2743 s = excludeProperties.get(c2.getFullName()); 2744 if (s != null) 2745 return s; 2746 s = excludeProperties.get(c2.getSimpleName()); 2747 if (s != null) 2748 return s; 2749 } 2750 return excludeProperties.get("*"); 2751 } 2752 2753 /** 2754 * Returns a reusable {@link ClassMeta} representation for the class <c>Object</c>. 2755 * 2756 * <p> 2757 * This <c>ClassMeta</c> is often used to represent "any object type" when an object type is not known. 2758 * 2759 * <p> 2760 * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to 2761 * avoid a hashmap lookup. 2762 * 2763 * @return The {@link ClassMeta} object associated with the <c>Object</c> class. 2764 */ 2765 protected final ClassMeta<Object> object() { 2766 return cmObject; 2767 } 2768 2769 /** 2770 * Returns a reusable {@link ClassMeta} representation for the class <c>String</c>. 2771 * 2772 * <p> 2773 * This <c>ClassMeta</c> is often used to represent key types in maps. 2774 * 2775 * <p> 2776 * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to 2777 * avoid a hashmap lookup. 2778 * 2779 * @return The {@link ClassMeta} object associated with the <c>String</c> class. 2780 */ 2781 protected final ClassMeta<String> string() { 2782 return cmString; 2783 } 2784 2785 /** 2786 * Returns a reusable {@link ClassMeta} representation for the class <c>Class</c>. 2787 * 2788 * <p> 2789 * This <c>ClassMeta</c> is often used to represent key types in maps. 2790 * 2791 * <p> 2792 * This method is identical to calling <code>getClassMeta(Class.<jk>class</jk>)</code> but uses a cached copy to 2793 * avoid a hashmap lookup. 2794 * 2795 * @return The {@link ClassMeta} object associated with the <c>String</c> class. 2796 */ 2797 protected final ClassMeta<Class> _class() { 2798 return cmClass; 2799 } 2800 2801 /** 2802 * Returns the lookup table for resolving bean types by name. 2803 * 2804 * @return The lookup table for resolving bean types by name. 2805 */ 2806 protected final BeanRegistry getBeanRegistry() { 2807 return beanRegistry; 2808 } 2809 2810 //----------------------------------------------------------------------------------------------------------------- 2811 // Properties 2812 //----------------------------------------------------------------------------------------------------------------- 2813 2814 /** 2815 * Configuration property: Minimum bean class visibility. 2816 * 2817 * @see #BEAN_beanClassVisibility 2818 * @return 2819 * Classes are not considered beans unless they meet the minimum visibility requirements. 2820 */ 2821 protected final Visibility getBeanClassVisibility() { 2822 return beanClassVisibility; 2823 } 2824 2825 /** 2826 * Configuration property: Minimum bean constructor visibility. 2827 * 2828 * @see #BEAN_beanConstructorVisibility 2829 * @return 2830 * Only look for constructors with this specified minimum visibility. 2831 */ 2832 protected final Visibility getBeanConstructorVisibility() { 2833 return beanConstructorVisibility; 2834 } 2835 2836 /** 2837 * Configuration property: Bean dictionary. 2838 * 2839 * @see #BEAN_beanDictionary 2840 * @return 2841 * The list of classes that make up the bean dictionary in this bean context. 2842 */ 2843 protected final List<Class<?>> getBeanDictionaryClasses() { 2844 return beanDictionaryClasses; 2845 } 2846 2847 /** 2848 * Configuration property: Minimum bean field visibility. 2849 * 2850 * 2851 * @see #BEAN_beanFieldVisibility 2852 * @return 2853 * Only look for bean fields with this specified minimum visibility. 2854 */ 2855 protected final Visibility getBeanFieldVisibility() { 2856 return beanFieldVisibility; 2857 } 2858 2859 /** 2860 * Configuration property: Bean filters. 2861 * 2862 * 2863 * @see BeanContext#BEAN_beanFilters 2864 * @return 2865 * Only look for bean fields with this specified minimum visibility. 2866 */ 2867 protected final BeanFilter[] getBeanFilters() { 2868 return beanFilters; 2869 } 2870 2871 /** 2872 * Configuration property: BeanMap.put() returns old property value. 2873 * 2874 * @see #BEAN_beanMapPutReturnsOldValue 2875 * @return 2876 * <jk>true</jk> if the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property values. 2877 * <br>Otherwise, it returns <jk>null</jk>. 2878 */ 2879 protected final boolean isBeanMapPutReturnsOldValue() { 2880 return beanMapPutReturnsOldValue; 2881 } 2882 2883 /** 2884 * Configuration property: Minimum bean method visibility. 2885 * 2886 * @see #BEAN_beanMethodVisibility 2887 * @return 2888 * Only look for bean methods with this specified minimum visibility. 2889 */ 2890 protected final Visibility getBeanMethodVisibility() { 2891 return beanMethodVisibility; 2892 } 2893 2894 /** 2895 * Configuration property: Beans require no-arg constructors. 2896 * 2897 * @see #BEAN_beansRequireDefaultConstructor 2898 * @return 2899 * <jk>true</jk> if a Java class must implement a default no-arg constructor to be considered a bean. 2900 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 2901 */ 2902 protected final boolean isBeansRequireDefaultConstructor() { 2903 return beansRequireDefaultConstructor; 2904 } 2905 2906 /** 2907 * Configuration property: Beans require Serializable interface. 2908 * 2909 * @see #BEAN_beansRequireSerializable 2910 * @return 2911 * <jk>true</jk> if a Java class must implement the {@link Serializable} interface to be considered a bean. 2912 * <br>Otherwise, the bean will be serialized as a string using the {@link Object#toString()} method. 2913 */ 2914 protected final boolean isBeansRequireSerializable() { 2915 return beansRequireSerializable; 2916 } 2917 2918 /** 2919 * Configuration property: Beans require setters for getters. 2920 * 2921 * @see #BEAN_beansRequireSettersForGetters 2922 * @return 2923 * <jk>true</jk> if only getters that have equivalent setters will be considered as properties on a bean. 2924 * <br>Otherwise, they are ignored. 2925 */ 2926 protected final boolean isBeansRequireSettersForGetters() { 2927 return beansRequireSettersForGetters; 2928 } 2929 2930 /** 2931 * Configuration property: Beans require at least one property. 2932 * 2933 * @see #BEAN_beansRequireSomeProperties 2934 * @return 2935 * <jk>true</jk> if a Java class must contain at least 1 property to be considered a bean. 2936 * <br>Otherwise, the bean is serialized as a string using the {@link Object#toString()} method. 2937 */ 2938 protected final boolean isBeansRequireSomeProperties() { 2939 return beansRequireSomeProperties; 2940 } 2941 2942 /** 2943 * Configuration property: Bean type property name. 2944 * 2945 * @see #BEAN_beanTypePropertyName 2946 * @return 2947 * 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. 2948 */ 2949 protected final String getBeanTypePropertyName() { 2950 return beanTypePropertyName; 2951 } 2952 2953 /** 2954 * Configuration property: Debug mode. 2955 * 2956 * @see #BEAN_debug 2957 * @return 2958 * <jk>true</jk> if debug mode is enabled. 2959 */ 2960 protected boolean isDebug() { 2961 return debug; 2962 } 2963 2964 /** 2965 * Configuration property: POJO examples. 2966 * 2967 * @see #BEAN_examples 2968 * @return 2969 * A map of POJO examples keyed by class name. 2970 */ 2971 protected final Map<String,?> getExamples() { 2972 return examples; 2973 } 2974 2975 /** 2976 * Configuration property: Bean property excludes. 2977 * 2978 * @see #BEAN_excludeProperties 2979 * @return 2980 * The list of property names to exclude keyed by class name. 2981 */ 2982 protected final Map<String,String[]> getExcludeProperties() { 2983 return excludeProperties; 2984 } 2985 2986 /** 2987 * Configuration property: Find fluent setters. 2988 * 2989 * <h5 class='section'>Description:</h5> 2990 * <p> 2991 * 2992 * @see #BEAN_fluentSetters 2993 * @return 2994 * <jk>true</jk> if fluent setters are detected on beans. 2995 */ 2996 protected final boolean isFluentSetters() { 2997 return fluentSetters; 2998 } 2999 3000 /** 3001 * Configuration property: Ignore invocation errors on getters. 3002 * 3003 * @see #BEAN_ignoreInvocationExceptionsOnGetters 3004 * @return 3005 * <jk>true</jk> if errors thrown when calling bean getter methods are silently ignored. 3006 */ 3007 protected final boolean isIgnoreInvocationExceptionsOnGetters() { 3008 return ignoreInvocationExceptionsOnGetters; 3009 } 3010 3011 /** 3012 * Configuration property: Ignore invocation errors on setters. 3013 * 3014 * @see #BEAN_ignoreInvocationExceptionsOnSetters 3015 * @return 3016 * <jk>true</jk> if errors thrown when calling bean setter methods are silently ignored. 3017 */ 3018 protected final boolean isIgnoreInvocationExceptionsOnSetters() { 3019 return ignoreInvocationExceptionsOnSetters; 3020 } 3021 3022 /** 3023 * Configuration property: Ignore properties without setters. 3024 * 3025 * <br>Otherwise, a {@code RuntimeException} is thrown. 3026 * 3027 * @see #BEAN_ignorePropertiesWithoutSetters 3028 * @return 3029 * <jk>true</jk> if trying to set a value on a bean property without a setter is silently ignored. 3030 */ 3031 protected final boolean isIgnorePropertiesWithoutSetters() { 3032 return ignorePropertiesWithoutSetters; 3033 } 3034 3035 /** 3036 * Configuration property: Ignore unknown properties. 3037 * 3038 * @see #BEAN_ignoreUnknownBeanProperties 3039 * @return 3040 * <jk>true</jk> if trying to set a value on a non-existent bean property is silently ignored. 3041 * <br>Otherwise, a {@code RuntimeException} is thrown. 3042 */ 3043 protected final boolean isIgnoreUnknownBeanProperties() { 3044 return ignoreUnknownBeanProperties; 3045 } 3046 3047 /** 3048 * Configuration property: Ignore unknown properties with null values. 3049 * 3050 * @see #BEAN_ignoreUnknownNullBeanProperties 3051 * @return 3052 * <jk>true</jk> if trying to set a <jk>null</jk> value on a non-existent bean property is silently ignored. 3053 */ 3054 protected final boolean isIgnoreUnknownNullBeanProperties() { 3055 return ignoreUnknownNullBeanProperties; 3056 } 3057 3058 /** 3059 * Configuration property: Implementation classes. 3060 * 3061 * @see #BEAN_implClasses 3062 * @return 3063 * Implementation classes keyed by interface class names. 3064 */ 3065 protected final Map<String,ClassInfo> getImplClasses() { 3066 return implClasses; 3067 } 3068 3069 /** 3070 * Configuration property: Bean property includes. 3071 * 3072 * @see #BEAN_includeProperties 3073 * @return 3074 * Include properties keyed by class name. 3075 */ 3076 protected final Map<String,String[]> getIncludeProperties() { 3077 return includeProperties; 3078 } 3079 3080 /** 3081 * Configuration property: Locale. 3082 * 3083 * @see #BEAN_locale 3084 * @return 3085 * The default locale for serializer and parser sessions. 3086 */ 3087 protected final Locale getLocale() { 3088 return locale; 3089 } 3090 3091 /** 3092 * Configuration property: Media type. 3093 * 3094 * @see #BEAN_mediaType 3095 * @return 3096 * The default media type value for serializer and parser sessions. 3097 */ 3098 protected final MediaType getMediaType() { 3099 return mediaType; 3100 } 3101 3102 /** 3103 * Configuration property: Bean class exclusions. 3104 * 3105 * @see #BEAN_notBeanClasses 3106 * @return 3107 * The list of classes that are explicitly not beans. 3108 */ 3109 protected final Class<?>[] getNotBeanClasses() { 3110 return notBeanClasses; 3111 } 3112 3113 /** 3114 * Configuration property: Bean package exclusions. 3115 * 3116 * @see #BEAN_notBeanPackages 3117 * @return 3118 * The list of fully-qualified package names to exclude from being classified as beans. 3119 */ 3120 protected final String[] getNotBeanPackagesNames() { 3121 return notBeanPackageNames; 3122 } 3123 3124 /** 3125 * Configuration property: Bean package exclusions. 3126 * 3127 * @see #BEAN_notBeanPackages 3128 * @return 3129 * The list of package name prefixes to exclude from being classified as beans. 3130 */ 3131 protected final String[] getNotBeanPackagesPrefixes() { 3132 return notBeanPackagePrefixes; 3133 } 3134 3135 /** 3136 * Configuration property: POJO swaps. 3137 * 3138 * @see #BEAN_pojoSwaps 3139 * @return 3140 * The list POJO swaps defined. 3141 */ 3142 protected final PojoSwap<?,?>[] getPojoSwaps() { 3143 return pojoSwaps; 3144 } 3145 3146 /** 3147 * Configuration property: Bean property namer. 3148 * 3149 * @see #BEAN_propertyNamer 3150 * @return 3151 * The interface used to calculate bean property names. 3152 */ 3153 protected final PropertyNamer getPropertyNamer() { 3154 return propertyNamer; 3155 } 3156 3157 /** 3158 * Configuration property: Sort bean properties. 3159 * 3160 * @see #BEAN_sortProperties 3161 * @return 3162 * <jk>true</jk> if all bean properties will be serialized and access in alphabetical order. 3163 */ 3164 protected final boolean isSortProperties() { 3165 return sortProperties; 3166 } 3167 3168 /** 3169 * Configuration property: Time zone. 3170 * 3171 * @see #BEAN_timeZone 3172 * @return 3173 * The default timezone for serializer and parser sessions. 3174 */ 3175 protected final TimeZone getTimeZone() { 3176 return timeZone; 3177 } 3178 3179 /** 3180 * Configuration property: Use enum names. 3181 * 3182 * @see #BEAN_useEnumNames 3183 * @return 3184 * <jk>true</jk> if enums are always serialized by name, not using {@link Object#toString()}. 3185 */ 3186 protected final boolean isUseEnumNames() { 3187 return useEnumNames; 3188 } 3189 3190 /** 3191 * Configuration property: Use interface proxies. 3192 * 3193 * @see #BEAN_useInterfaceProxies 3194 * @return 3195 * <jk>true</jk> if interfaces will be instantiated as proxy classes through the use of an 3196 * {@link InvocationHandler} if there is no other way of instantiating them. 3197 */ 3198 protected final boolean isUseInterfaceProxies() { 3199 return useInterfaceProxies; 3200 } 3201 3202 /** 3203 * Configuration property: Use Java Introspector. 3204 * 3205 * @see #BEAN_useJavaBeanIntrospector 3206 * @return 3207 * <jk>true</jk> if the built-in Java bean introspector should be used for bean introspection. 3208 */ 3209 protected final boolean isUseJavaBeanIntrospector() { 3210 return useJavaBeanIntrospector; 3211 } 3212 3213 //----------------------------------------------------------------------------------------------------------------- 3214 // Other methods 3215 //----------------------------------------------------------------------------------------------------------------- 3216 3217 @Override /* Context */ 3218 public ObjectMap toMap() { 3219 return super.toMap() 3220 .append("BeanContext", new DefaultFilteringObjectMap() 3221 .append("id", System.identityHashCode(this)) 3222 .append("beanClassVisibility", beanClassVisibility) 3223 .append("beanConstructorVisibility", beanConstructorVisibility) 3224 .append("beanDictionaryClasses", beanDictionaryClasses) 3225 .append("beanFieldVisibility", beanFieldVisibility) 3226 .append("beanFilters", beanFilters) 3227 .append("beanMapPutReturnsOldValue", beanMapPutReturnsOldValue) 3228 .append("beanMethodVisibility", beanMethodVisibility) 3229 .append("beansRequireDefaultConstructor", beansRequireDefaultConstructor) 3230 .append("beansRequireSerializable", beansRequireSerializable) 3231 .append("beansRequireSettersForGetters", beansRequireSettersForGetters) 3232 .append("beansRequireSomeProperties", beansRequireSomeProperties) 3233 .append("excludeProperties", excludeProperties) 3234 .append("ignoreInvocationExceptionsOnGetters", ignoreInvocationExceptionsOnGetters) 3235 .append("ignoreInvocationExceptionsOnSetters", ignoreInvocationExceptionsOnSetters) 3236 .append("ignorePropertiesWithoutSetters", ignorePropertiesWithoutSetters) 3237 .append("ignoreUnknownBeanProperties", ignoreUnknownBeanProperties) 3238 .append("ignoreUnknownNullBeanProperties", ignoreUnknownNullBeanProperties) 3239 .append("implClasses", implClasses) 3240 .append("includeProperties", includeProperties) 3241 .append("locale", locale) 3242 .append("mediaType", mediaType) 3243 .append("notBeanClasses", notBeanClasses) 3244 .append("notBeanPackageNames", notBeanPackageNames) 3245 .append("notBeanPackagePrefixes", notBeanPackagePrefixes) 3246 .append("pojoSwaps", pojoSwaps) 3247 .append("sortProperties", sortProperties) 3248 .append("timeZone", timeZone) 3249 .append("useEnumNames", useEnumNames) 3250 .append("useInterfaceProxies", useInterfaceProxies) 3251 .append("useJavaBeanIntrospector", useJavaBeanIntrospector) 3252 ); 3253 } 3254}