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.commons.bean; 018 019import static java.util.Collections.*; 020import static org.apache.juneau.commons.utils.Shorts.*; 021 022import java.beans.*; 023import java.io.*; 024import java.util.*; 025import java.util.function.*; 026 027import org.apache.juneau.commons.inject.*; 028import org.apache.juneau.commons.reflect.*; 029import org.apache.juneau.commons.reflect.Visibility; 030 031/** 032 * Immutable runtime configuration for the bean-modeling layer. 033 * 034 * <p> 035 * {@code BeanConfigContext} is the runtime sibling of the {@link BeanConfig @BeanConfig} annotation: 036 * it carries the resolved values that drive how Java types are introspected as beans, independent 037 * of any marshalling concern. Settings include visibility thresholds, required-property toggles, 038 * fluent-setter detection, property naming, not-bean exclusions, the active {@link BeanStore} and 039 * {@link AnnotationProvider}, and a few related hooks. 040 * 041 * <p> 042 * This type is the bean-modeling counterpart of the marshalling-layer context that lives in 043 * {@code juneau-marshall}. It exists so the bean-modeling runtime (in {@code commons.bean}) can 044 * be used independently of the marshalling stack, and so the marshalling layer can compose a 045 * {@code BeanConfigContext} snapshot to feed bean-modeling code without exposing marshalling-only 046 * APIs. 047 * 048 * <h5 class='section'>Construction:</h5> 049 * <p class='bjava'> 050 * <jc>// All defaults.</jc> 051 * BeanConfigContext <jv>defaults</jv> = BeanConfigContext.<jsf>DEFAULT</jsf>; 052 * 053 * <jc>// Customized.</jc> 054 * BeanConfigContext <jv>ctx</jv> = BeanConfigContext.<jsm>create</jsm>() 055 * .beanClassVisibility(Visibility.<jsf>PROTECTED</jsf>) 056 * .findFluentSetters(<jk>true</jk>) 057 * .propertyNamer(<jk>new</jk> PropertyNamerDLC()) 058 * .build(); 059 * 060 * <jc>// Copy and tweak.</jc> 061 * BeanConfigContext <jv>ctx2</jv> = <jv>ctx</jv>.copy() 062 * .unsortedProperties(<jk>true</jk>) 063 * .build(); 064 * </p> 065 * 066 * <h5 class='topic'>Thread safety</h5> 067 * 068 * {@link BeanConfigContext} instances are immutable and thread-safe. 069 * {@link Builder} instances are mutable and not thread-safe. 070 * 071 * <h5 class='section'>See Also:</h5><ul> 072 * <li class='ja'>{@link BeanConfig @BeanConfig} — the annotation form. 073 * </ul> 074 */ 075@SuppressWarnings({ 076 "java:S107", // Builder.build() invokes a multi-arg constructor; high cardinality is inherent to a configuration POJO. 077 "java:S1192" // Duplicate string literals are annotation attribute values and protocol-wire keys; intentional 078}) 079public final class BeanConfigContext { 080 081 /** 082 * Default {@link BeanConfigContext} instance with all settings at their defaults. 083 * 084 * <p> 085 * Equivalent to {@code BeanConfigContext.create().build()}. 086 */ 087 public static final BeanConfigContext DEFAULT = create().build(); 088 089 /** 090 * Creates a new builder for {@link BeanConfigContext}. 091 * 092 * @return A new builder. 093 */ 094 public static Builder create() { 095 return new Builder(); 096 } 097 098 private final Visibility beanClassVisibility; 099 private final Visibility beanConstructorVisibility; 100 private final Visibility beanFieldVisibility; 101 private final Visibility beanMethodVisibility; 102 103 private final boolean beanMapPutReturnsOldValue; 104 private final boolean beansRequireDefaultConstructor; 105 private final boolean beansRequireSerializable; 106 private final boolean beansRequireSettersForGetters; 107 private final boolean beansRequireSomeProperties; 108 private final boolean findFluentSetters; 109 private final boolean ignoreInvocationExceptionsOnGetters; 110 private final boolean ignoreInvocationExceptionsOnSetters; 111 private final boolean ignoreMissingSetters; 112 private final boolean ignoreTransientFields; 113 private final boolean ignoreUnknownBeanProperties; 114 private final boolean ignoreUnknownNullBeanProperties; 115 private final boolean unsortedProperties; 116 private final boolean recordComponentOrder; 117 private final boolean useInterfaceProxies; 118 private final boolean useJavaBeanIntrospector; 119 120 private final PropertyNamer propertyNamer; 121 private final String beanTypePropertyName; 122 123 private final Set<String> notBeanPackageNames; 124 private final Set<String> notBeanPackagePrefixes; 125 private final Set<Class<?>> notBeanClasses; 126 127 private final BeanStore beanStore; 128 private final AnnotationProvider annotationProvider; 129 private final Predicate<ClassInfo> notABeanPredicate; 130 private final BeanMetaInitializer beanMetaInitializer; 131 private final BeanPropertyPostProcessor beanPropertyPostProcessor; 132 133 private BeanConfigContext(Builder b) { 134 beanClassVisibility = b.beanClassVisibility; 135 beanConstructorVisibility = b.beanConstructorVisibility; 136 beanFieldVisibility = b.beanFieldVisibility; 137 beanMethodVisibility = b.beanMethodVisibility; 138 beanMapPutReturnsOldValue = b.beanMapPutReturnsOldValue; 139 beansRequireDefaultConstructor = b.beansRequireDefaultConstructor; 140 beansRequireSerializable = b.beansRequireSerializable; 141 beansRequireSettersForGetters = b.beansRequireSettersForGetters; 142 beansRequireSomeProperties = b.beansRequireSomeProperties; 143 findFluentSetters = b.findFluentSetters; 144 ignoreInvocationExceptionsOnGetters = b.ignoreInvocationExceptionsOnGetters; 145 ignoreInvocationExceptionsOnSetters = b.ignoreInvocationExceptionsOnSetters; 146 ignoreMissingSetters = b.ignoreMissingSetters; 147 ignoreTransientFields = b.ignoreTransientFields; 148 ignoreUnknownBeanProperties = b.ignoreUnknownBeanProperties; 149 ignoreUnknownNullBeanProperties = b.ignoreUnknownNullBeanProperties; 150 unsortedProperties = b.unsortedProperties; 151 recordComponentOrder = b.recordComponentOrder; 152 useInterfaceProxies = b.useInterfaceProxies; 153 useJavaBeanIntrospector = b.useJavaBeanIntrospector; 154 propertyNamer = b.propertyNamer; 155 beanTypePropertyName = b.beanTypePropertyName; 156 notBeanPackageNames = u(b.notBeanPackageNames); 157 notBeanPackagePrefixes = u(b.notBeanPackagePrefixes); 158 notBeanClasses = u(b.notBeanClasses); 159 beanStore = b.beanStore; 160 annotationProvider = b.annotationProvider; 161 notABeanPredicate = b.notABeanPredicate; 162 beanMetaInitializer = b.beanMetaInitializer; 163 beanPropertyPostProcessor = b.beanPropertyPostProcessor; 164 } 165 166 /** 167 * Returns a builder pre-populated with the values from this context. 168 * 169 * @return A new builder. 170 */ 171 public Builder copy() { 172 return new Builder(this); 173 } 174 175 /** 176 * Minimum bean class visibility. 177 * 178 * <p> 179 * Classes are not considered beans unless they meet this minimum visibility requirement. 180 * 181 * @return The minimum bean class visibility. Never <jk>null</jk>. 182 */ 183 public Visibility getBeanClassVisibility() { return beanClassVisibility; } 184 185 /** 186 * Minimum bean constructor visibility. 187 * 188 * @return The minimum bean constructor visibility. Never <jk>null</jk>. 189 */ 190 public Visibility getBeanConstructorVisibility() { return beanConstructorVisibility; } 191 192 /** 193 * Minimum bean field visibility. 194 * 195 * @return The minimum bean field visibility. Never <jk>null</jk>. 196 */ 197 public Visibility getBeanFieldVisibility() { return beanFieldVisibility; } 198 199 /** 200 * Minimum bean method visibility. 201 * 202 * @return The minimum bean method visibility. Never <jk>null</jk>. 203 */ 204 public Visibility getBeanMethodVisibility() { return beanMethodVisibility; } 205 206 /** 207 * Returns whether {@code BeanMap.put(String,Object)} returns the previous property value. 208 * 209 * <p> 210 * When <jk>false</jk> (the default), {@code BeanMap.put(...)} always returns <jk>null</jk> for performance reasons — 211 * the underlying bean's getter is skipped before the setter is invoked. 212 * 213 * @return <jk>true</jk> if old values are returned. 214 */ 215 public boolean isBeanMapPutReturnsOldValue() { return beanMapPutReturnsOldValue; } 216 217 /** 218 * Returns whether classes must have a no-arg constructor to be considered beans. 219 * 220 * @return <jk>true</jk> if a no-arg constructor is required. 221 */ 222 public boolean isBeansRequireDefaultConstructor() { return beansRequireDefaultConstructor; } 223 224 /** 225 * Returns whether classes must implement {@link Serializable} to be considered beans. 226 * 227 * @return <jk>true</jk> if {@code Serializable} is required. 228 */ 229 public boolean isBeansRequireSerializable() { return beansRequireSerializable; } 230 231 /** 232 * Returns whether bean properties must have a setter to be considered writable from the getter. 233 * 234 * @return <jk>true</jk> if setters are required for getters. 235 */ 236 public boolean isBeansRequireSettersForGetters() { return beansRequireSettersForGetters; } 237 238 /** 239 * Returns whether classes must have at least one property to be considered beans. 240 * 241 * @return <jk>true</jk> if at least one property is required. 242 */ 243 public boolean isBeansRequireSomeProperties() { return beansRequireSomeProperties; } 244 245 /** 246 * Returns whether fluent-style setters (returning <c>this</c>) should be detected. 247 * 248 * @return <jk>true</jk> if fluent setters are detected. 249 */ 250 public boolean isFindFluentSetters() { return findFluentSetters; } 251 252 /** 253 * Returns whether exceptions thrown from bean property getters should be silently swallowed. 254 * 255 * <p> 256 * When <jk>true</jk>, an exception thrown by a getter is treated as a <jk>null</jk> property value rather than 257 * propagated to the caller. 258 * 259 * @return <jk>true</jk> if getter invocation exceptions are ignored. 260 */ 261 public boolean isIgnoreInvocationExceptionsOnGetters() { return ignoreInvocationExceptionsOnGetters; } 262 263 /** 264 * Returns whether exceptions thrown from bean property setters should be silently swallowed. 265 * 266 * <p> 267 * When <jk>true</jk>, an exception thrown by a setter is suppressed rather than propagated to the caller. 268 * 269 * @return <jk>true</jk> if setter invocation exceptions are ignored. 270 */ 271 public boolean isIgnoreInvocationExceptionsOnSetters() { return ignoreInvocationExceptionsOnSetters; } 272 273 /** 274 * Returns whether bean properties without setters should be silently ignored during deserialization. 275 * 276 * @return <jk>true</jk> if missing setters are ignored. 277 */ 278 public boolean isIgnoreMissingSetters() { return ignoreMissingSetters; } 279 280 /** 281 * Returns whether {@code transient} fields should be excluded from bean property detection. 282 * 283 * @return <jk>true</jk> if transient fields are ignored. 284 */ 285 public boolean isIgnoreTransientFields() { return ignoreTransientFields; } 286 287 /** 288 * Returns whether unknown properties on incoming bean payloads should be ignored. 289 * 290 * @return <jk>true</jk> if unknown properties are ignored. 291 */ 292 public boolean isIgnoreUnknownBeanProperties() { return ignoreUnknownBeanProperties; } 293 294 /** 295 * Returns whether attempts to set unknown bean properties to <jk>null</jk> should be silently ignored. 296 * 297 * <p> 298 * When <jk>true</jk> (the default), trying to set an unknown property to <jk>null</jk> is a no-op rather than an 299 * error. When <jk>false</jk>, the property setter still rejects unknown property names. 300 * 301 * @return <jk>true</jk> if unknown null properties are silently ignored. 302 */ 303 public boolean isIgnoreUnknownNullBeanProperties() { return ignoreUnknownNullBeanProperties; } 304 305 /** 306 * Returns whether properties use declaration order instead of alphabetical order. 307 * 308 * <p> 309 * Declaration order means record component order for records, field declaration order (superclass first) for 310 * other classes, followed by method-only properties in alphabetical order. 311 * 312 * @return <jk>true</jk> if properties remain unsorted. 313 */ 314 public boolean isUnsortedProperties() { return unsortedProperties; } 315 316 /** 317 * Returns whether record properties use record component (declaration) order. 318 * 319 * <p> 320 * When <jk>true</jk>, the properties of a {@link Record} are ordered by {@link Class#getRecordComponents()} even in 321 * the default sorted mode. Non-record beans are unaffected. 322 * 323 * @return <jk>true</jk> if records use component order. 324 */ 325 public boolean isRecordComponentOrder() { return recordComponentOrder; } 326 327 /** 328 * Returns whether interface proxies should be created for bean interfaces. 329 * 330 * @return <jk>true</jk> if interface proxies are enabled. 331 */ 332 public boolean isUseInterfaceProxies() { return useInterfaceProxies; } 333 334 /** 335 * Returns whether {@link Introspector} should be used to discover bean properties. 336 * 337 * @return <jk>true</jk> if the JavaBeans introspector is used. 338 */ 339 public boolean isUseJavaBeanIntrospector() { return useJavaBeanIntrospector; } 340 341 /** 342 * Returns the {@link PropertyNamer} used to derive property names from getter/setter/field names. 343 * 344 * @return The active property namer. Never <jk>null</jk>. 345 */ 346 public PropertyNamer getPropertyNamer() { return propertyNamer; } 347 348 /** 349 * Returns the property name used to embed the bean dictionary type name (default: <js>"_type"</js>). 350 * 351 * @return The bean type property name. Never <jk>null</jk>. 352 */ 353 public String getBeanTypePropertyName() { return beanTypePropertyName; } 354 355 /** 356 * Returns the set of fully qualified package names whose classes are excluded from bean detection. 357 * 358 * @return The not-a-bean package name set. Never <jk>null</jk>. Unmodifiable. 359 */ 360 public Set<String> getNotBeanPackageNames() { return notBeanPackageNames; } 361 362 /** 363 * Returns the set of fully qualified package prefixes whose classes are excluded from bean detection. 364 * 365 * @return The not-a-bean package prefix set. Never <jk>null</jk>. Unmodifiable. 366 */ 367 public Set<String> getNotBeanPackagePrefixes() { return notBeanPackagePrefixes; } 368 369 /** 370 * Returns the set of classes (and supertypes) that are explicitly excluded from bean detection. 371 * 372 * @return The not-a-bean class set. Never <jk>null</jk>. Unmodifiable. 373 */ 374 public Set<Class<?>> getNotBeanClasses() { return notBeanClasses; } 375 376 /** 377 * Returns the active {@link BeanStore} used for factory-based bean instantiation, or <jk>null</jk> if none configured. 378 * 379 * @return The bean store, or <jk>null</jk>. 380 */ 381 public BeanStore getBeanStore() { return beanStore; } 382 383 /** 384 * Returns the {@link AnnotationProvider} used to discover annotations on classes/methods/fields/parameters. 385 * 386 * @return The annotation provider. Never <jk>null</jk>. 387 */ 388 public AnnotationProvider getAnnotationProvider() { return annotationProvider; } 389 390 /** 391 * Returns the {@link BeanMetaInitializer} SPI hook used during {@link BeanMeta} construction. 392 * 393 * <p> 394 * On the commons-side path this is {@link BeanMetaInitializer#NOOP} (no marshalling-side help); on the 395 * marshalling-side path, {@code MarshallingContext} wires its own implementation that reads 396 * {@code @Marshalled} / {@code @BeanType} annotations and builds {@code BeanRegistry} instances. 397 * 398 * @return The bean-meta initializer. Never <jk>null</jk>. 399 */ 400 public BeanMetaInitializer getBeanMetaInitializer() { return beanMetaInitializer; } 401 402 /** 403 * Returns the {@link BeanPropertyPostProcessor} SPI hook used during {@link BeanPropertyMeta} construction. 404 * 405 * <p> 406 * On the commons-side path this is {@link BeanPropertyPostProcessor#NOOP} (no swap-aware transforms or 407 * {@code @MarshalledProp} / {@code @Swap} / {@code @Uri} reads); on the marshalling-side path, 408 * {@code MarshallingContext} wires its own implementation. 409 * 410 * @return The bean-property post-processor. Never <jk>null</jk>. 411 */ 412 public BeanPropertyPostProcessor getBeanPropertyPostProcessor() { return beanPropertyPostProcessor; } 413 414 /** 415 * Returns <jk>true</jk> if the specified class is excluded from bean detection. 416 * 417 * <p> 418 * The default implementation checks {@link #getNotBeanClasses()}, {@link #getNotBeanPackageNames()}, and 419 * {@link #getNotBeanPackagePrefixes()}, and rejects arrays/primitives/enums/annotations. A custom 420 * predicate (set via {@link Builder#notABeanPredicate(Predicate)}) overrides this behavior entirely. 421 * 422 * @param ci The class info being tested. Must not be <jk>null</jk>. 423 * @return <jk>true</jk> if the class is excluded from bean detection. 424 */ 425 @SuppressWarnings({ 426 "java:S3776" // Cognitive complexity acceptable for bean-exclusion predicate dispatch 427 }) 428 public boolean isNotABean(ClassInfo ci) { 429 reqnn("ci", ci); 430 if (notABeanPredicate != null) 431 return notABeanPredicate.test(ci); 432 if (ci.isArray() || ci.isPrimitive() || ci.isEnum() || ci.isAnnotation()) 433 return true; 434 var p = ci.getPackage(); 435 if (nn(p)) { 436 var pn = p.getName(); 437 for (var p2 : notBeanPackageNames) 438 if (pn.equals(p2)) 439 return true; 440 for (var p2 : notBeanPackagePrefixes) 441 if (pn.startsWith(p2)) 442 return true; 443 } 444 for (var exclude : notBeanClasses) 445 if (ci.isAssignableTo(exclude)) 446 return true; 447 return false; 448 } 449 450 /** 451 * Builder for {@link BeanConfigContext}. 452 */ 453 public static final class Builder { 454 455 private Visibility beanClassVisibility = Visibility.PUBLIC; 456 private Visibility beanConstructorVisibility = Visibility.PUBLIC; 457 private Visibility beanFieldVisibility = Visibility.PUBLIC; 458 private Visibility beanMethodVisibility = Visibility.PUBLIC; 459 460 private boolean beanMapPutReturnsOldValue; 461 private boolean beansRequireDefaultConstructor; 462 private boolean beansRequireSerializable; 463 private boolean beansRequireSettersForGetters; 464 private boolean beansRequireSomeProperties = true; 465 private boolean findFluentSetters; 466 private boolean ignoreInvocationExceptionsOnGetters; 467 private boolean ignoreInvocationExceptionsOnSetters; 468 private boolean ignoreMissingSetters = true; 469 private boolean ignoreTransientFields = true; 470 private boolean ignoreUnknownBeanProperties; 471 private boolean ignoreUnknownNullBeanProperties = true; 472 private boolean unsortedProperties; 473 private boolean recordComponentOrder; 474 private boolean useInterfaceProxies = true; 475 private boolean useJavaBeanIntrospector; 476 477 private PropertyNamer propertyNamer = new BasicPropertyNamer(); 478 private String beanTypePropertyName = "_type"; 479 480 private Set<String> notBeanPackageNames = st(); 481 private Set<String> notBeanPackagePrefixes = st(); 482 private Set<Class<?>> notBeanClasses = st(); 483 484 private BeanStore beanStore; 485 private AnnotationProvider annotationProvider = AnnotationProvider.INSTANCE; 486 private Predicate<ClassInfo> notABeanPredicate; 487 private BeanMetaInitializer beanMetaInitializer = BeanMetaInitializer.NOOP; 488 private BeanPropertyPostProcessor beanPropertyPostProcessor = BeanPropertyPostProcessor.NOOP; 489 490 private Builder() {} 491 492 private Builder(BeanConfigContext src) { 493 beanClassVisibility = src.beanClassVisibility; 494 beanConstructorVisibility = src.beanConstructorVisibility; 495 beanFieldVisibility = src.beanFieldVisibility; 496 beanMethodVisibility = src.beanMethodVisibility; 497 beanMapPutReturnsOldValue = src.beanMapPutReturnsOldValue; 498 beansRequireDefaultConstructor = src.beansRequireDefaultConstructor; 499 beansRequireSerializable = src.beansRequireSerializable; 500 beansRequireSettersForGetters = src.beansRequireSettersForGetters; 501 beansRequireSomeProperties = src.beansRequireSomeProperties; 502 findFluentSetters = src.findFluentSetters; 503 ignoreInvocationExceptionsOnGetters = src.ignoreInvocationExceptionsOnGetters; 504 ignoreInvocationExceptionsOnSetters = src.ignoreInvocationExceptionsOnSetters; 505 ignoreMissingSetters = src.ignoreMissingSetters; 506 ignoreTransientFields = src.ignoreTransientFields; 507 ignoreUnknownBeanProperties = src.ignoreUnknownBeanProperties; 508 ignoreUnknownNullBeanProperties = src.ignoreUnknownNullBeanProperties; 509 unsortedProperties = src.unsortedProperties; 510 recordComponentOrder = src.recordComponentOrder; 511 useInterfaceProxies = src.useInterfaceProxies; 512 useJavaBeanIntrospector = src.useJavaBeanIntrospector; 513 propertyNamer = src.propertyNamer; 514 beanTypePropertyName = src.beanTypePropertyName; 515 notBeanPackageNames = new LinkedHashSet<>(src.notBeanPackageNames); 516 notBeanPackagePrefixes = new LinkedHashSet<>(src.notBeanPackagePrefixes); 517 notBeanClasses = new LinkedHashSet<>(src.notBeanClasses); 518 beanStore = src.beanStore; 519 annotationProvider = src.annotationProvider; 520 notABeanPredicate = src.notABeanPredicate; 521 beanMetaInitializer = src.beanMetaInitializer; 522 beanPropertyPostProcessor = src.beanPropertyPostProcessor; 523 } 524 525 /** 526 * Builds a new {@link BeanConfigContext} from this builder's state. 527 * 528 * @return A new immutable {@link BeanConfigContext}. 529 */ 530 public BeanConfigContext build() { 531 return new BeanConfigContext(this); 532 } 533 534 /** 535 * Sets the minimum bean class visibility. 536 * 537 * @param value The visibility threshold. Must not be <jk>null</jk>. 538 * @return This object. 539 */ 540 public Builder beanClassVisibility(Visibility value) { beanClassVisibility = reqnn("value", value); return this; } 541 542 /** 543 * Sets the minimum bean constructor visibility. 544 * 545 * @param value The visibility threshold. Must not be <jk>null</jk>. 546 * @return This object. 547 */ 548 public Builder beanConstructorVisibility(Visibility value) { beanConstructorVisibility = reqnn("value", value); return this; } 549 550 /** 551 * Sets the minimum bean field visibility. 552 * 553 * @param value The visibility threshold. Must not be <jk>null</jk>. 554 * @return This object. 555 */ 556 public Builder beanFieldVisibility(Visibility value) { beanFieldVisibility = reqnn("value", value); return this; } 557 558 /** 559 * Sets the minimum bean method visibility. 560 * 561 * @param value The visibility threshold. Must not be <jk>null</jk>. 562 * @return This object. 563 */ 564 public Builder beanMethodVisibility(Visibility value) { beanMethodVisibility = reqnn("value", value); return this; } 565 566 /** 567 * Toggles whether {@code BeanMap.put(String,Object)} returns the previous value rather than <jk>null</jk>. 568 * 569 * @param value The new value. 570 * @return This object. 571 */ 572 public Builder beanMapPutReturnsOldValue(boolean value) { beanMapPutReturnsOldValue = value; return this; } 573 574 /** 575 * Toggles the requirement that beans have a no-arg default constructor. 576 * 577 * @param value The new value. 578 * @return This object. 579 */ 580 public Builder beansRequireDefaultConstructor(boolean value) { beansRequireDefaultConstructor = value; return this; } 581 582 /** 583 * Toggles the requirement that beans implement {@link Serializable}. 584 * 585 * @param value The new value. 586 * @return This object. 587 */ 588 public Builder beansRequireSerializable(boolean value) { beansRequireSerializable = value; return this; } 589 590 /** 591 * Toggles the requirement that bean getters have matching setters. 592 * 593 * @param value The new value. 594 * @return This object. 595 */ 596 public Builder beansRequireSettersForGetters(boolean value) { beansRequireSettersForGetters = value; return this; } 597 598 /** 599 * Toggles the requirement that beans expose at least one property. 600 * 601 * @param value The new value. 602 * @return This object. 603 */ 604 public Builder beansRequireSomeProperties(boolean value) { beansRequireSomeProperties = value; return this; } 605 606 /** 607 * Toggles fluent-setter detection (setters that return <c>this</c>). 608 * 609 * @param value The new value. 610 * @return This object. 611 */ 612 public Builder findFluentSetters(boolean value) { findFluentSetters = value; return this; } 613 614 /** 615 * Toggles silent suppression of exceptions thrown by bean property getters. 616 * 617 * @param value The new value. 618 * @return This object. 619 */ 620 public Builder ignoreInvocationExceptionsOnGetters(boolean value) { ignoreInvocationExceptionsOnGetters = value; return this; } 621 622 /** 623 * Toggles silent suppression of exceptions thrown by bean property setters. 624 * 625 * @param value The new value. 626 * @return This object. 627 */ 628 public Builder ignoreInvocationExceptionsOnSetters(boolean value) { ignoreInvocationExceptionsOnSetters = value; return this; } 629 630 /** 631 * Toggles silent ignoring of properties without setters during deserialization. 632 * 633 * @param value The new value. 634 * @return This object. 635 */ 636 public Builder ignoreMissingSetters(boolean value) { ignoreMissingSetters = value; return this; } 637 638 /** 639 * Toggles exclusion of {@code transient} fields from bean property detection. 640 * 641 * @param value The new value. 642 * @return This object. 643 */ 644 public Builder ignoreTransientFields(boolean value) { ignoreTransientFields = value; return this; } 645 646 /** 647 * Toggles silent ignoring of unknown properties on incoming bean payloads. 648 * 649 * @param value The new value. 650 * @return This object. 651 */ 652 public Builder ignoreUnknownBeanProperties(boolean value) { ignoreUnknownBeanProperties = value; return this; } 653 654 /** 655 * Toggles silent ignoring of attempts to set unknown bean properties to <jk>null</jk>. 656 * 657 * @param value The new value. 658 * @return This object. 659 */ 660 public Builder ignoreUnknownNullBeanProperties(boolean value) { ignoreUnknownNullBeanProperties = value; return this; } 661 662 /** 663 * Toggles declaration order (instead of alphabetical order) for bean properties. 664 * 665 * @param value The new value. 666 * @return This object. 667 */ 668 public Builder unsortedProperties(boolean value) { unsortedProperties = value; return this; } 669 670 /** 671 * Toggles record component (declaration) ordering for {@link Record} beans. 672 * 673 * @param value The new value. 674 * @return This object. 675 */ 676 public Builder recordComponentOrder(boolean value) { recordComponentOrder = value; return this; } 677 678 /** 679 * Toggles automatic creation of interface proxies for bean interfaces. 680 * 681 * @param value The new value. 682 * @return This object. 683 */ 684 public Builder useInterfaceProxies(boolean value) { useInterfaceProxies = value; return this; } 685 686 /** 687 * Toggles use of {@link Introspector} for property discovery. 688 * 689 * @param value The new value. 690 * @return This object. 691 */ 692 public Builder useJavaBeanIntrospector(boolean value) { useJavaBeanIntrospector = value; return this; } 693 694 /** 695 * Sets the {@link PropertyNamer} used to derive property names. 696 * 697 * @param value The property namer. Must not be <jk>null</jk>. 698 * @return This object. 699 */ 700 public Builder propertyNamer(PropertyNamer value) { propertyNamer = reqnn("value", value); return this; } 701 702 /** 703 * Sets the property name used to embed the bean dictionary type (default: <js>"_type"</js>). 704 * 705 * @param value The property name. Must not be <jk>null</jk>. 706 * @return This object. 707 */ 708 public Builder beanTypePropertyName(String value) { beanTypePropertyName = reqnn("value", value); return this; } 709 710 /** 711 * Adds package names whose classes should be excluded from bean detection. 712 * 713 * @param values The package names. Must not be <jk>null</jk>. 714 * @return This object. 715 */ 716 public Builder notBeanPackageNames(String...values) { 717 reqnn("values", values); 718 Collections.addAll(notBeanPackageNames, values); 719 return this; 720 } 721 722 /** 723 * Adds package prefixes whose classes should be excluded from bean detection. 724 * 725 * @param values The package prefixes. Must not be <jk>null</jk>. 726 * @return This object. 727 */ 728 public Builder notBeanPackagePrefixes(String...values) { 729 reqnn("values", values); 730 Collections.addAll(notBeanPackagePrefixes, values); 731 return this; 732 } 733 734 /** 735 * Adds classes (and supertypes) that should be excluded from bean detection. 736 * 737 * @param values The classes. Must not be <jk>null</jk>. 738 * @return This object. 739 */ 740 public Builder notBeanClasses(Class<?>...values) { 741 reqnn("values", values); 742 Collections.addAll(notBeanClasses, values); 743 return this; 744 } 745 746 /** 747 * Replaces the not-a-bean package name set. 748 * 749 * @param values The package names. May be <jk>null</jk> for an empty set. 750 * @return This object. 751 */ 752 public Builder notBeanPackageNames(Collection<String> values) { 753 notBeanPackageNames = new LinkedHashSet<>(values == null ? emptySet() : values); 754 return this; 755 } 756 757 /** 758 * Replaces the not-a-bean package prefix set. 759 * 760 * @param values The package prefixes. May be <jk>null</jk> for an empty set. 761 * @return This object. 762 */ 763 public Builder notBeanPackagePrefixes(Collection<String> values) { 764 notBeanPackagePrefixes = new LinkedHashSet<>(values == null ? emptySet() : values); 765 return this; 766 } 767 768 /** 769 * Replaces the not-a-bean class set. 770 * 771 * @param values The classes. May be <jk>null</jk> for an empty set. 772 * @return This object. 773 */ 774 @SuppressWarnings({ 775 "java:S4968" // '? extends Class<?>' is not redundant for the nested generic: it admits Collection<Class<X>> (e.g. List<Class<String>>); narrowing to Collection<Class<?>> would be a source-incompatible API reduction. 776 }) 777 public Builder notBeanClasses(Collection<? extends Class<?>> values) { 778 notBeanClasses = new LinkedHashSet<>(values == null ? emptySet() : values); 779 return this; 780 } 781 782 /** 783 * Sets the active {@link BeanStore} used for factory-based bean instantiation. 784 * 785 * @param value The bean store. May be <jk>null</jk>. 786 * @return This object. 787 */ 788 public Builder beanStore(BeanStore value) { beanStore = value; return this; } 789 790 /** 791 * Sets the active {@link AnnotationProvider}. 792 * 793 * @param value The annotation provider. Must not be <jk>null</jk>. 794 * @return This object. 795 */ 796 public Builder annotationProvider(AnnotationProvider value) { annotationProvider = reqnn("value", value); return this; } 797 798 /** 799 * Installs a custom predicate that fully overrides {@link BeanConfigContext#isNotABean(ClassInfo)}. 800 * 801 * <p> 802 * When set, the default not-bean computation (package/class exclusions, array/primitive/enum/annotation 803 * checks) is bypassed entirely. Pass <jk>null</jk> to revert to the built-in behavior. 804 * 805 * @param value The predicate. May be <jk>null</jk>. 806 * @return This object. 807 */ 808 public Builder notABeanPredicate(Predicate<ClassInfo> value) { notABeanPredicate = value; return this; } 809 810 /** 811 * Sets the {@link BeanMetaInitializer} SPI hook for marshalling-side {@link BeanMeta} construction. 812 * 813 * <p> 814 * Pass <jk>null</jk> to reset to {@link BeanMetaInitializer#NOOP} (commons-side default). 815 * 816 * @param value The initializer. May be <jk>null</jk>. 817 * @return This object. 818 */ 819 public Builder beanMetaInitializer(BeanMetaInitializer value) { beanMetaInitializer = value == null ? BeanMetaInitializer.NOOP : value; return this; } 820 821 /** 822 * Sets the {@link BeanPropertyPostProcessor} SPI hook for marshalling-side bean-property post-processing. 823 * 824 * <p> 825 * Pass <jk>null</jk> to reset to {@link BeanPropertyPostProcessor#NOOP} (commons-side default). 826 * 827 * @param value The post-processor. May be <jk>null</jk>. 828 * @return This object. 829 */ 830 public Builder beanPropertyPostProcessor(BeanPropertyPostProcessor value) { beanPropertyPostProcessor = value == null ? BeanPropertyPostProcessor.NOOP : value; return this; } 831 } 832}