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