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}