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