001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015import static org.apache.juneau.Context.*;
016
017import java.lang.reflect.*;
018import java.util.*;
019
020import org.apache.juneau.annotation.*;
021import org.apache.juneau.csv.annotation.*;
022import org.apache.juneau.html.annotation.*;
023import org.apache.juneau.http.*;
024import org.apache.juneau.internal.*;
025import org.apache.juneau.jso.annotation.*;
026import org.apache.juneau.json.annotation.*;
027import org.apache.juneau.jsonschema.annotation.*;
028import org.apache.juneau.msgpack.annotation.*;
029import org.apache.juneau.oapi.annotation.*;
030import org.apache.juneau.parser.annotation.*;
031import org.apache.juneau.plaintext.annotation.*;
032import org.apache.juneau.reflect.*;
033import org.apache.juneau.serializer.*;
034import org.apache.juneau.serializer.annotation.*;
035import org.apache.juneau.soap.annotation.*;
036import org.apache.juneau.svl.*;
037import org.apache.juneau.transform.*;
038import org.apache.juneau.uon.annotation.*;
039import org.apache.juneau.urlencoding.annotation.*;
040import org.apache.juneau.xml.annotation.*;
041
042/**
043 * Base builder class for building instances of any context objects configured through property stores.
044 */
045public abstract class ContextBuilder {
046
047   /** Contains all the modifiable settings for the implementation class. */
048   private final PropertyStoreBuilder psb;
049
050   /**
051    * Constructor.
052    * Default settings.
053    */
054   public ContextBuilder() {
055      this.psb = PropertyStore.create();
056   }
057
058   /**
059    * Constructor that takes in an initial set of configuration properties.
060    *
061    * @param ps The initial configuration settings for this builder.
062    */
063   public ContextBuilder(PropertyStore ps) {
064      if (ps == null)
065         ps = PropertyStore.DEFAULT;
066      this.psb = ps.builder();
067   }
068
069   /**
070    * Constructor.
071    *
072    * <p>
073    * Used in cases where multiple context builder are sharing the same property store builder.
074    * <br>(e.g. <c>HtmlDocBuilder</c>)
075    *
076    * @param psb The property store builder to use.
077    */
078   protected ContextBuilder(PropertyStoreBuilder psb) {
079      this.psb = psb;
080   }
081
082   /**
083    * Returns access to the inner property store builder.
084    *
085    * <p>
086    * Used in conjunction with {@link #ContextBuilder(PropertyStoreBuilder)} when builders share property store builders.
087    *
088    * @return The inner property store builder.
089    */
090   protected PropertyStoreBuilder getPropertyStoreBuilder() {
091      return psb;
092   }
093
094   /**
095    * Build the object.
096    *
097    * @return
098    *    The built object.
099    *    <br>Subsequent calls to this method will create new instances (unless context object is cacheable).
100    */
101   public abstract Context build();
102
103   /**
104    * Copies the settings from the specified property store into this builder.
105    *
106    * <h5 class='section'>Example:</h5>
107    * <p class='bcode w800'>
108    *    <jc>// Create a free-form set of properties.</jc>
109    *    PropertyStore ps = PropertyStore
110    *       .<jsm>create</jsm>()
111    *       .set(<jsf>BEAN_sortMaps</jsf>, <jk>true</jk>)
112    *       .set(<jsf>BEAN_sortProperties</jsf>, <jk>true</jk>)
113    *       .build();
114    *
115    *    <jc>// Create a serializer that uses those settings.</jc>
116    *    WriterSerializer s = JsonSerializer
117    *       .<jsm>create</jsm>()
118    *       .apply(ps)
119    *       .build();
120    * </p>
121    *
122    * @param copyFrom The property store whose settings are being copied.
123    * @return This object (for method chaining).
124    */
125   @FluentSetter
126   public ContextBuilder apply(PropertyStore copyFrom) {
127      this.psb.apply(copyFrom);
128      return this;
129   }
130
131   /**
132    * Applies a set of annotations to this property store.
133    *
134    * <p>
135    * The {@link AnnotationList} object is an ordered list of annotations and the classes/methods/packages they were found on.
136    *
137    * <h5 class='section'>Example:</h5>
138    * <p class='bcode w800'>
139    *    <jc>// A class annotated with a config annotation.</jc>
140    *    <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>)
141    *    <jk>public class</jk> MyClass {...}
142    *
143    *    <jc>// Find all annotations that themselves are annotated with @PropertyStoreApply.</jc>
144    *    AnnotationList al = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>)
145    *       .getAnnotationList(ConfigAnnotationFilter.<jsf>INSTANCE</jsf>);
146    *
147    *    <jc>// Use the default VarResolver to resolve any variables in the annotation fields.</jc>
148    *    VarResolverSession vs = VarResolver.<jsf>DEFAULT</jsf>.createSession();
149    *
150    *    <jc>// Apply any settings found on the annotations.</jc>
151    *    WriterSerializer s = JsonSerializer
152    *       .<jsm>create</jsm>()
153    *       .applyAnnotations(al, vs)
154    *       .build();
155    * </p>
156    *
157    * @param al The list of all annotations annotated with {@link PropertyStoreApply}.
158    * @param r The string resolver for resolving variables in annotation values.
159    * @return This object (for method chaining).
160    */
161   @FluentSetter
162   public ContextBuilder applyAnnotations(AnnotationList al, VarResolverSession r) {
163      this.psb.applyAnnotations(al, r);
164      return this;
165   }
166
167   /**
168    * Applies any of the various <ja>@XConfig</ja> annotations on the specified class to this context.
169    *
170    * <p>
171    * Any annotations found that themselves are annotated with {@link PropertyStoreApply} will be resolved and
172    * applied as properties to this builder.  These annotations include:
173    * <ul class='javatree'>
174    *    <li class ='ja'>{@link BeanConfig}
175    *    <li class ='ja'>{@link CsvConfig}
176    *    <li class ='ja'>{@link HtmlConfig}
177    *    <li class ='ja'>{@link HtmlDocConfig}
178    *    <li class ='ja'>{@link JsoConfig}
179    *    <li class ='ja'>{@link JsonConfig}
180    *    <li class ='ja'>{@link JsonSchemaConfig}
181    *    <li class ='ja'>{@link MsgPackConfig}
182    *    <li class ='ja'>{@link OpenApiConfig}
183    *    <li class ='ja'>{@link ParserConfig}
184    *    <li class ='ja'>{@link PlainTextConfig}
185    *    <li class ='ja'>{@link SerializerConfig}
186    *    <li class ='ja'>{@link SoapXmlConfig}
187    *    <li class ='ja'>{@link UonConfig}
188    *    <li class ='ja'>{@link UrlEncodingConfig}
189    *    <li class ='ja'>{@link XmlConfig}
190    *    <li class ='ja'><c>RdfConfig</c>
191    * </ul>
192    *
193    * <p>
194    * Annotations on classes are appended in the following order:
195    * <ol>
196    *    <li>On the package of this class.
197    *    <li>On interfaces ordered parent-to-child.
198    *    <li>On parent classes ordered parent-to-child.
199    *    <li>On this class.
200    * </ol>
201    *
202    * <p>
203    * The default var resolver {@link VarResolver#DEFAULT} is used to resolve any variables in annotation field values.
204    *
205    * <h5 class='section'>Example:</h5>
206    * <p class='bcode w800'>
207    *    <jc>// A class annotated with a config annotation.</jc>
208    *    <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>)
209    *    <jk>public class</jk> MyClass {...}
210    *
211    *    <jc>// Apply any settings found on the annotations.</jc>
212    *    WriterSerializer s = JsonSerializer
213    *       .<jsm>create</jsm>()
214    *       .applyAnnotations(MyClass.<jk>class</jk>)
215    *       .build();
216    * </p>
217    *
218    * @param fromClasses The classes on which the annotations are defined.
219    * @return This object (for method chaining).
220    */
221   @FluentSetter
222   public ContextBuilder applyAnnotations(Class<?>...fromClasses) {
223      for (Class<?> c : fromClasses)
224         applyAnnotations(ClassInfo.of(c).getAnnotationList(ConfigAnnotationFilter.INSTANCE), VarResolver.DEFAULT.createSession());
225      return this;
226   }
227
228   /**
229    * Applies any of the various <ja>@XConfig</ja> annotations on the specified method to this context.
230    *
231    * <p>
232    * Any annotations found that themselves are annotated with {@link PropertyStoreApply} will be resolved and
233    * applied as properties to this builder.  These annotations include:
234    * <ul class='javatree'>
235    *    <li class ='ja'>{@link BeanConfig}
236    *    <li class ='ja'>{@link CsvConfig}
237    *    <li class ='ja'>{@link HtmlConfig}
238    *    <li class ='ja'>{@link HtmlDocConfig}
239    *    <li class ='ja'>{@link JsoConfig}
240    *    <li class ='ja'>{@link JsonConfig}
241    *    <li class ='ja'>{@link JsonSchemaConfig}
242    *    <li class ='ja'>{@link MsgPackConfig}
243    *    <li class ='ja'>{@link OpenApiConfig}
244    *    <li class ='ja'>{@link ParserConfig}
245    *    <li class ='ja'>{@link PlainTextConfig}
246    *    <li class ='ja'>{@link SerializerConfig}
247    *    <li class ='ja'>{@link SoapXmlConfig}
248    *    <li class ='ja'>{@link UonConfig}
249    *    <li class ='ja'>{@link UrlEncodingConfig}
250    *    <li class ='ja'>{@link XmlConfig}
251    *    <li class ='ja'><c>RdfConfig</c>
252    * </ul>
253    *
254    * <p>
255    * Annotations on methods are appended in the following order:
256    * <ol>
257    *    <li>On the package of the method class.
258    *    <li>On interfaces ordered parent-to-child.
259    *    <li>On parent classes ordered parent-to-child.
260    *    <li>On the method class.
261    *    <li>On this method and matching methods ordered parent-to-child.
262    * </ol>
263    *
264    * <p>
265    * The default var resolver {@link VarResolver#DEFAULT} is used to resolve any variables in annotation field values.
266    *
267    * <h5 class='section'>Example:</h5>
268    * <p class='bcode w800'>
269    *    <jc>// A method annotated with a config annotation.</jc>
270    *    <jk>public class</jk> MyClass {
271    *       <ja>@BeanConfig</ja>(sortProperties=<js>"$S{sortProperties,false}"</js>)
272    *       <jk>public void</jk> myMethod() {...}
273    *    }
274    *
275    *    <jc>// Apply any settings found on the annotations.</jc>
276    *    WriterSerializer s = JsonSerializer
277    *       .<jsm>create</jsm>()
278    *       .applyAnnotations(MyClass.<jk>class</jk>.getMethod(<js>"myMethod"</js>))
279    *       .build();
280    * </p>
281    *
282    * @param fromMethods The methods on which the annotations are defined.
283    * @return This object (for method chaining).
284    */
285   @FluentSetter
286   public ContextBuilder applyAnnotations(Method...fromMethods) {
287      for (Method m : fromMethods)
288         applyAnnotations(MethodInfo.of(m).getAnnotationList(ConfigAnnotationFilter.INSTANCE), VarResolver.DEFAULT.createSession());
289      return this;
290   }
291
292   /**
293    * Build a new instance of the specified object.
294    *
295    * <p>
296    * Creates a new instance of the specified context-based class, or an existing instance if one with the equivalent
297    * property store was already created.
298    *
299    * @param c The subclass of {@link Context} to instantiate.
300    * @return A new object using the settings defined in this builder.
301    */
302
303   public <T extends Context> T build(Class<T> c) {
304      return ContextCache.INSTANCE.create(c, getPropertyStore());
305   }
306
307   /**
308    * Returns a read-only snapshot of the current property store on this builder.
309    *
310    * @return A property store object.
311    */
312   public PropertyStore getPropertyStore() {
313      return psb.build();
314   }
315
316   //-----------------------------------------------------------------------------------------------------------------
317   // Properties
318   //-----------------------------------------------------------------------------------------------------------------
319
320   /**
321    * <i><l>Context</l> configuration property:&emsp;</i>  Debug mode.
322    *
323    * <p>
324    * Enables the following additional information during serialization:
325    * <ul class='spaced-list'>
326    *    <li>
327    *       When bean getters throws exceptions, the exception includes the object stack information
328    *       in order to determine how that method was invoked.
329    *    <li>
330    *       Enables {@link Serializer#BEANTRAVERSE_detectRecursions}.
331    * </ul>
332    *
333    * <p>
334    * Enables the following additional information during parsing:
335    * <ul class='spaced-list'>
336    *    <li>
337    *       When bean setters throws exceptions, the exception includes the object stack information
338    *       in order to determine how that method was invoked.
339    * </ul>
340    *
341    * <h5 class='section'>Example:</h5>
342    * <p class='bcode w800'>
343    *    <jc>// Create a serializer with debug enabled.</jc>
344    *    WriterSerializer s = JsonSerializer
345    *       .<jsm>create</jsm>()
346    *       .debug()
347    *       .build();
348    *
349    *    <jc>// Same, but use property.</jc>
350    *    WriterSerializer s = JsonSerializer
351    *       .<jsm>create</jsm>()
352    *       .set(<jsf>BEAN_debug</jsf>, <jk>true</jk>)
353    *       .build();
354    *
355    *    <jc>// Create a POJO model with a recursive loop.</jc>
356    *    <jk>public class</jk> A {
357    *       <jk>public</jk> Object <jf>f</jf>;
358    *    }
359    *    A a = <jk>new</jk> A();
360    *    a.<jf>f</jf> = a;
361    *
362    *    <jc>// Throws a SerializeException and not a StackOverflowError</jc>
363    *    String json = s.serialize(a);
364    * </p>
365    *
366    * <ul class='seealso'>
367    *    <li class='jf'>{@link Context#CONTEXT_debug}
368    * </ul>
369    *
370    * @return This object (for method chaining).
371    */
372   @FluentSetter
373   public ContextBuilder debug() {
374      return set(CONTEXT_debug, true);
375   }
376
377   /**
378    * <i><l>Context</l> configuration property:&emsp;</i>  Locale.
379    *
380    * <p>
381    * Specifies the default locale for serializer and parser sessions when not specified via {@link SessionArgs#locale(Locale)}.
382    * Typically used for POJO swaps that need to deal with locales such as swaps that convert <l>Date</l> and <l>Calendar</l>
383    * objects to strings by accessing it via the session passed into the {@link PojoSwap#swap(BeanSession, Object)} and
384    * {@link PojoSwap#unswap(BeanSession, Object, ClassMeta, String)} methods.
385    *
386    * <h5 class='section'>Example:</h5>
387    * <p class='bcode w800'>
388    *    <jc>// Define a POJO swap that skips serializing beans if we're in the UK.</jc>
389    *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
390    *       <ja>@Override</ja>
391    *       public String swap(BeanSession session, MyBean o) throws Exception {
392    *          <jk>if</jk> (session.getLocale().equals(Locale.<jsf>UK</jsf>))
393    *             <jk>return null</jk>;
394    *          <jk>return</jk> o.toString();
395    *       }
396    *    }
397    *
398    *    <jc>// Create a serializer that uses the specified locale if it's not passed in through session args.</jc>
399    *    WriterSerializer s = JsonSerializer
400    *       .<jsm>create</jsm>()
401    *       .locale(Locale.<jsf>UK</jsf>)
402    *       .pojoSwaps(MyBeanSwap.<jk>class</jk>)
403    *       .build();
404    *
405    *    <jc>// Same, but use property.</jc>
406    *    WriterSerializer s = JsonSerializer
407    *       .<jsm>create</jsm>()
408    *       .set(<jsf>CONTEXT_locale</jsf>, Locale.<jsf>UK</jsf>)
409    *       .addTo(<jsf>BEAN_pojoSwaps</jsf>, MyBeanSwap.<jk>class</jk>)
410    *       .build();
411    *
412    *    <jc>// Define on session-args instead.</jc>
413    *    SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().locale(Locale.<jsf>UK</jsf>);
414    *    <jk>try</jk> (WriterSerializerSession session = s.createSession(sessionArgs)) {
415    *
416    *       <jc>// Produces "null" if in the UK.</jc>
417    *       String json = s.serialize(<jk>new</jk> MyBean());
418    *    }
419    * </p>
420    *
421    * <ul class='seealso'>
422    *    <li class='jf'>{@link Context#CONTEXT_locale}
423    * </ul>
424    *
425    * @param value The new value for this property.
426    * @return This object (for method chaining).
427    */
428   @FluentSetter
429   public ContextBuilder locale(Locale value) {
430      return set(CONTEXT_locale, value);
431   }
432
433   /**
434    * <i><l>Context</l> configuration property:&emsp;</i>  Media type.
435    *
436    * <p>
437    * Specifies the default media type for serializer and parser sessions when not specified via {@link SessionArgs#mediaType(MediaType)}.
438    * Typically used for POJO swaps that need to serialize the same POJO classes differently depending on
439    * the specific requested media type.   For example, a swap could handle a request for media types <js>"application/json"</js>
440    * and <js>"application/json+foo"</js> slightly differently even though they're both being handled by the same JSON
441    * serializer or parser.
442    *
443    * <h5 class='section'>Example:</h5>
444    * <p class='bcode w800'>
445    *    <jc>// Define a POJO swap that skips serializing beans if the media type is application/json.</jc>
446    *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
447    *       <ja>@Override</ja>
448    *       public String swap(BeanSession session, MyBean o) throws Exception {
449    *          <jk>if</jk> (session.getMediaType().equals(<js>"application/json"</js>))
450    *             <jk>return null</jk>;
451    *          <jk>return</jk> o.toString();
452    *       }
453    *    }
454    *
455    *    <jc>// Create a serializer that uses the specified media type if it's not passed in through session args.</jc>
456    *    WriterSerializer s = JsonSerializer
457    *       .<jsm>create</jsm>()
458    *       .mediaType(MediaType.<jsf>JSON</jsf>)
459    *       .build();
460    *
461    *    <jc>// Same, but use property.</jc>
462    *    WriterSerializer s = JsonSerializer
463    *       .<jsm>create</jsm>()
464    *       .set(<jsf>CONTEXT_mediaType</jsf>, MediaType.<jsf>JSON</jsf>)
465    *       .build();
466    *
467    *    <jc>// Define on session-args instead.</jc>
468    *    SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().mediaType(MediaType.<jsf>JSON</jsf>);
469    *    <jk>try</jk> (WriterSerializerSession session = s.createSession(sessionArgs)) {
470    *
471    *       <jc>// Produces "null" since it's JSON.</jc>
472    *       String json = s.serialize(<jk>new</jk> MyBean());
473    *    }
474    * </p>
475    *
476    * <ul class='seealso'>
477    *    <li class='jf'>{@link Context#CONTEXT_mediaType}
478    * </ul>
479    *
480    * @param value The new value for this property.
481    * @return This object (for method chaining).
482    */
483   @FluentSetter
484   public ContextBuilder mediaType(MediaType value) {
485      return set(CONTEXT_mediaType, value);
486   }
487
488   /**
489    * <i><l>Context</l> configuration property:&emsp;</i>  TimeZone.
490    *
491    * <p>
492    * Specifies the default time zone for serializer and parser sessions when not specified via {@link SessionArgs#timeZone(TimeZone)}.
493    * Typically used for POJO swaps that need to deal with timezones such as swaps that convert <l>Date</l> and <l>Calendar</l>
494    * objects to strings by accessing it via the session passed into the {@link PojoSwap#swap(BeanSession, Object)} and
495    * {@link PojoSwap#unswap(BeanSession, Object, ClassMeta, String)} methods.
496    *
497    * <h5 class='section'>Example:</h5>
498    * <p class='bcode w800'>
499    *    <jc>// Define a POJO swap that skips serializing beans if the time zone is GMT.</jc>
500    *    <jk>public class</jk> MyBeanSwap <jk>extends</jk> StringSwap&lt;MyBean&gt; {
501    *       <ja>@Override</ja>
502    *       public String swap(BeanSession session, MyBean o) throws Exception {
503    *          <jk>if</jk> (session.getTimeZone().equals(TimeZone.<jsf>GMT</jsf>))
504    *             <jk>return null</jk>;
505    *          <jk>return</jk> o.toString();
506    *       }
507    *    }
508    *
509    *    <jc>// Create a serializer that uses GMT if the timezone is not specified in the session args.</jc>
510    *    WriterSerializer s = JsonSerializer
511    *       .<jsm>create</jsm>()
512    *       .timeZone(TimeZone.<jsf>GMT</jsf>)
513    *       .build();
514    *
515    *    <jc>// Same, but use property.</jc>
516    *    WriterSerializer s = JsonSerializer
517    *       .<jsm>create</jsm>()
518    *       .set(<jsf>CONTEXT_timeZone</jsf>, TimeZone.<jsf>GMT</jsf>)
519    *       .build();
520    *
521    *    <jc>// Define on session-args instead.</jc>
522    *    SerializerSessionArgs sessionArgs = <jk>new</jk> SerializerSessionArgs().timeZone(TimeZone.<jsf>GMT</jsf>);
523    *    <jk>try</jk> (WriterSerializerSession ss = JsonSerializer.<jsf>DEFAULT</jsf>.createSession(sessionArgs)) {
524    *
525    *       <jc>// Produces "null" since the time zone is GMT.</jc>
526    *       String json = s.serialize(<jk>new</jk> MyBean());
527    *    }
528    * </p>
529    *
530    * <ul class='seealso'>
531    *    <li class='jf'>{@link Context#CONTEXT_timeZone}
532    * </ul>
533    *
534    * @param value The new value for this property.
535    * @return This object (for method chaining).
536    */
537   @FluentSetter
538   public ContextBuilder timeZone(TimeZone value) {
539      return set(CONTEXT_timeZone, value);
540   }
541
542   /**
543    * Sets a free-form configuration property on this object.
544    *
545    * <p>
546    * Provides the ability to specify configuration property values in a generic fashion.
547    *
548    * <p>
549    * Property names must have the following format that identify their datatype...
550    * <p class='bcode w800'>
551    *    <js>"{class}.{name}.{type}"</js>
552    * </p>
553    * <p>
554    * ...where the parts consist of the following...
555    * <ul>
556    *    <li><js>"{class}"</js> - The group name of the property (e.g. <js>"JsonSerializer"</js>).
557    *       <br>It's always going to be the simple class name of the class it's associated with.
558    *    <li><js>"{name}"</js> - The property name (e.g. <js>"useWhitespace"</js>).
559    *    <li><js>"{type}"</js> - The property data type.
560    *       <br>A 1 or 2 character string that identifies the data type of the property.
561    *       <br>Valid values are:
562    *       <ul>
563    *          <li><js>"s"</js> - <c>String</c>
564    *          <li><js>"b"</js> - <c>Boolean</c>
565    *          <li><js>"i"</js> - <c>Integer</c>
566    *          <li><js>"c"</js> - <c>Class</c>
567    *          <li><js>"o"</js> - <c>Object</c>
568    *          <li><js>"ss"</js> - <c>TreeSet&lt;String&gt;</c>
569    *          <li><js>"si"</js> - <c>TreeSet&lt;Integer&gt;</c>
570    *          <li><js>"sc"</js> - <c>TreeSet&lt;Class&gt;</c>
571    *          <li><js>"ls"</js> - <c>Linkedlist&lt;String&gt;</c>
572    *          <li><js>"li"</js> - <c>Linkedlist&lt;Integer&gt;</c>
573    *          <li><js>"lc"</js> - <c>Linkedlist&lt;Class&gt;</c>
574    *          <li><js>"lo"</js> - <c>Linkedlist&lt;Object&gt;</c>
575    *          <li><js>"sms"</js> - <c>TreeMap&lt;String,String&gt;</c>
576    *          <li><js>"smi"</js> - <c>TreeMap&lt;String,Integer&gt;</c>
577    *          <li><js>"smc"</js> - <c>TreeMap&lt;String,Class&gt;</c>
578    *          <li><js>"smo"</js> - <c>TreeMap&lt;String,Object&gt;</c>
579    *          <li><js>"oms"</js> - <c>LinkedHashMap&lt;String,String&gt;</c>
580    *          <li><js>"omi"</js> - <c>LinkedHashMap&lt;String,Integer&gt;</c>
581    *          <li><js>"omc"</js> - <c>LinkedHashMap&lt;String,Class&gt;</c>
582    *          <li><js>"omo"</js> - <c>LinkedHashMap&lt;String,Object&gt;</c>
583    *       </ul>
584    * </ul>
585    *
586    * <p>
587    * For example, <js>"BeanContext.swaps.lc"</js> refers to a property on the <l>BeanContext</l> class
588    * called <l>swaps</l> that has a data type of <l>List&lt;Class&gt;</l>.
589    *
590    * <p>
591    * Property values get 'normalized' when they get set.
592    * For example, calling <c>set(<js>"BeanContext.debug.b"</js>, <js>"true"</js>)</c> will cause the property
593    * value to be converted to a boolean.  This allows the underlying {@link PropertyStore} class to be comparable
594    * and useful in determining whether a cached instance of a context object can be returned.
595    *
596    * <h5 class='section'>Example:</h5>
597    * <p class='bcode w800'>
598    *    <jc>// Create a serializer that sorts maps and bean properties.</jc>
599    *    WriterSerializer s = JsonSerializer
600    *       .<jsm>create</jsm>()
601    *       .sortMaps()
602    *       .sortProperties()
603    *       .build();
604    *
605    *    <jc>// Same, but use generic set() method.</jc>
606    *    WriterSerializer s = JsonSerializer
607    *       .<jsm>create</jsm>()
608    *       .set(<jsf>BEAN_sortMaps</jsf>, <jk>true</jk>)
609    *       .set(<jsf>BEAN_sortProperties</jsf>, <jk>true</jk>)
610    *       .build();
611    * </p>
612    *
613    * <p>
614    * As a general rule, builders don't typically have "unsetter" methods.  For example, once you've set strict
615    * mode on the <l>ParserBuilder</l> class, a method does not exist for unsetting it.
616    * This method can be used in these rare cases where you need to unset a value by setting it to <jk>null</jk>.
617    *
618    * <h5 class='section'>Example:</h5>
619    * <p class='bcode w800'>
620    *    <jc>// Clone an existing serializer and unset the sort settings.</jc>
621    *    s = s.<jsm>builder</jsm>()
622    *       .set(<jsf>BEAN_sortMaps</jsf>, <jk>null</jk>)
623    *       .set(<jsf>BEAN_sortProperties</jsf>, <jk>null</jk>)
624    *       .build();
625    * </p>
626    *
627    * <ul class='seealso'>
628    *    <li class='jc'>{@link PropertyStore}
629    * </ul>
630    *
631    * @param name The property name.
632    * @param value
633    *    The property value.
634    *    <br>The valid value types depend on the property type:
635    *    <ul>
636    *       <li><js>"s"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
637    *       <li><js>"b"</js> - Any <l>Object</l> converted to a <l>Boolean</l> using <c>Boolean.<jsm>parseBoolean</jsm>(value.toString())</c>.
638    *       <li><js>"i"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
639    *       <li><js>"c"</js> - Only <l>Class</l> objects are allowed.
640    *       <li><js>"o"</js> - Left as-is.
641    *       <li><js>"ss"</js>,<js>"si"</js>,<js>"sc"</js> - Any collection or array of any convertible <l>Objects</l> or a JSON Array string.
642    *       <li><js>"ls"</js>,<js>"li"</js>,<js>"lc"</js>,<js>"lo"</js> - Any collection or array of any convertible <l>Objects</l> or a JSON Array string.
643    *       <li><js>"sms"</js>,<js>"smi"</js>,<js>"smc"</js>,<js>"smo"</js> - Any sorted map of any convertible <l>Objects</l> or a JSON Object string.
644    *       <li><js>"oms"</js>,<js>"omi"</js>,<js>"omc"</js>,<js>"omo"</js> - Any ordered map of any convertible <l>Objects</l> or a JSON Object string.
645    *    </ul>
646    *
647    * @return This object (for method chaining).
648    */
649   @FluentSetter
650   public ContextBuilder set(String name, Object value) {
651      psb.set(name, value);
652      return this;
653   }
654
655   /**
656    * Peeks at a free-form configuration property on this object.
657    *
658    * <p>
659    * Allows you to look at the raw value of a configuration property while it's still in the builder.
660    *
661    * @param key The property name.
662    * @return
663    *    The raw value of the configuration property as it was passed in through this API.
664    *    <br><jk>null</jk> if not set.
665    */
666   public Object peek(String key) {
667      return psb.peek(key);
668   }
669
670   /**
671    * Peeks at a configuration property on this object.
672    *
673    * <p>
674    * Allows you to look at the raw value of a configuration property while it's still in the builder.
675    *
676    * <p>
677    * Converts the value from the current raw form into the specified data type.
678    *
679    * @param c The type to convert to.
680    * @param key The property name.
681    * @return
682    *    The converted value of the configuration property after conversion from the raw value.
683    *    <br><jk>null</jk> if not set.
684    * @param <T> The type to convert to.
685    */
686   public <T> T peek(Class<T> c, String key) {
687      return psb.peek(c, key);
688   }
689
690   /**
691    * Sets multiple free-form configuration properties on this object replacing all previous values.
692    *
693    * <p>
694    * Identical in function to {@link #set(String, Object)} but allows you to specify multiple values at once.
695    *
696    * <h5 class='section'>Example:</h5>
697    * <p class='bcode w800'>
698    *    <jc>// Create a serializer that sorts maps and bean properties.</jc>
699    *    WriterSerializer s = JsonSerializer
700    *       .<jsm>create</jsm>()
701    *       .sortMaps()
702    *       .sortProperties()
703    *       .build();
704    *
705    *    <jc>// Same, but use generic set(Map) method.</jc>
706    *    WriterSerializer s = JsonSerializer
707    *       .<jsm>create</jsm>()
708    *       .set(
709    *          AMap.<jsm>of</jsm>(
710    *             <jsf>BEAN_sortMaps</jsf>, <jk>true</jk>,
711    *             <jsf>BEAN_sortProperties</jsf>, <jk>true</jk>
712    *          )
713    *       )
714    *       .build();
715    * </p>
716    *
717    * <ul class='seealso'>
718    *    <li class='jc'>{@link PropertyStore}
719    *    <li class='jm'>{@link #set(String, Object)}
720    * </ul>
721    *
722    * @param properties
723    *    The properties to set on this class.
724    *    <br>The keys must be strings.
725    *    <br>The valid value types depend on the property type:
726    *    <ul>
727    *       <li><js>"s"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
728    *       <li><js>"b"</js> - Any <l>Object</l> converted to a <l>Boolean</l> using <c>Boolean.<jsm>parseBoolean</jsm>(value.toString())</c>.
729    *       <li><js>"i"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
730    *       <li><js>"c"</js> - Only <l>Class</l> objects are allowed.
731    *       <li><js>"o"</js> - Left as-is.
732    *       <li><js>"ss"</js>,<js>"si"</js>,<js>"sc"</js> - Any collection or array of any convertible <l>Objects</l> or a JSON Array string.
733    *       <li><js>"ls"</js>,<js>"li"</js>,<js>"lc"</js>,<js>"lo"</js> - Any collection or array of any convertible <l>Objects</l> or a JSON Array string.
734    *       <li><js>"sms"</js>,<js>"smi"</js>,<js>"smc"</js>,<js>"smo"</js> - Any sorted map of any convertible <l>Objects</l> or a JSON Object string.
735    *       <li><js>"oms"</js>,<js>"omi"</js>,<js>"omc"</js>,<js>"omo"</js> - Any ordered map of any convertible <l>Objects</l> or a JSON Object string.
736    *    </ul>
737    * @return This object (for method chaining).
738    */
739   @FluentSetter
740   public ContextBuilder set(Map<String,Object> properties) {
741      psb.set(properties);
742      return this;
743   }
744
745   /**
746    * Adds multiple free-form configuration properties on this object without first clearing out any previous values.
747    *
748    * <p>
749    * Identical in function to {@link #set(String, Object)} but allows you to specify multiple values at once.
750    *
751    * <h5 class='section'>Example:</h5>
752    * <p class='bcode w800'>
753    *    <jc>// Create a serializer that sorts bean properties.</jc>
754    *    WriterSerializer s = JsonSerializer
755    *       .<jsm>create</jsm>()
756    *       .sortMaps()
757    *       .sortProperties()
758    *       .build();
759    *
760    *    <jc>// Same, but use generic add() method.</jc>
761    *    WriterSerializer s = JsonSerializer
762    *       .<jsm>create</jsm>()
763    *       .add(
764    *          AMap.<jsm>of</jsm>(
765    *             <jsf>BEAN_sortMaps</jsf>, <jk>true</jk>,
766    *             <jsf>BEAN_sortProperties</jsf>, <jk>true</jk>
767    *          )
768    *       )
769    *       .build();
770    * </p>
771    *
772    * <ul class='seealso'>
773    *    <li class='jc'>{@link PropertyStore}
774    *    <li class='jm'>{@link #set(String, Object)}
775    * </ul>
776    *
777    * @param properties
778    *    The properties to set on this class.
779    *    <br>The keys must be strings.
780    *    <br>The valid value types depend on the property type:
781    *    <ul>
782    *       <li><js>"s"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
783    *       <li><js>"b"</js> - Any <l>Object</l> converted to a <l>Boolean</l> using <c>Boolean.<jsm>parseBoolean</jsm>(value.toString())</c>.
784    *       <li><js>"i"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
785    *       <li><js>"c"</js> - Only <l>Class</l> objects are allowed.
786    *       <li><js>"o"</js> - Left as-is.
787    *       <li><js>"ss"</js>,<js>"si"</js>,<js>"sc"</js> - Any collection or array of any convertible <l>Objects</l> or a JSON Array string.
788    *       <li><js>"ls"</js>,<js>"li"</js>,<js>"lc"</js>,<js>"lo"</js> - Any collection or array of any convertible <l>Objects</l> or a JSON Array string.
789    *       <li><js>"sms"</js>,<js>"smi"</js>,<js>"smc"</js>,<js>"smo"</js> - Any sorted map of any convertible <l>Objects</l> or a JSON Object string.
790    *       <li><js>"oms"</js>,<js>"omi"</js>,<js>"omc"</js>,<js>"omo"</js> - Any ordered map of any convertible <l>Objects</l> or a JSON Object string.
791    *    </ul>
792    * @return This object (for method chaining).
793    */
794   @FluentSetter
795   public ContextBuilder add(Map<String,Object> properties) {
796      psb.add(properties);
797      return this;
798   }
799
800   /**
801    * Adds a free-form value to a SET property.
802    *
803    * <p>
804    * SET properties are those properties with one of the following type parts:
805    * <ul>
806    *    <li><js>"ss"</js> - <c>TreeSet&lt;String&gt;</c>
807    *    <li><js>"si"</js> - <c>TreeSet&lt;Integer&gt;</c>
808    *    <li><js>"sc"</js> - <c>TreeSet&lt;Class&gt;</c>
809    * </ul>
810    *
811    * <p>
812    * For example, the {@link BeanContext#BEAN_notBeanClasses} property which has the value <js>"BeanContext.notBeanClasses.sc"</js>.
813    *
814    * <h5 class='section'>Example:</h5>
815    * <p class='bcode w800'>
816    *    <jc>// Create a serializer that forces MyNotBean classes to be converted to strings.</jc>
817    *    WriterSerializer s = JsonSerializer
818    *       .<jsm>create</jsm>()
819    *       .notBeanClasses(MyNotBean.<jk>class</jk>)
820    *       .build();
821    *
822    *    <jc>// Same, but use generic addTo() method.</jc>
823    *    WriterSerializer s = JsonSerializer
824    *       .<jsm>create</jsm>()
825    *       .addTo(<jsf>BEAN_notBeanClasses</jsf>, MyNotBean.<jk>class</jk>)
826    *       .build();
827    * </p>
828    *
829    * <ul class='seealso'>
830    *    <li class='jc'>{@link PropertyStore}
831    *    <li class='jm'>{@link #set(String, Object)}
832    * </ul>
833    *
834    * @param name The property name.
835    * @param value
836    *    The new value to add to the SET property.
837    *    <br>The valid value types depend on the property type:
838    *    <ul>
839    *       <li><js>"ss"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
840    *       <li><js>"si"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
841    *       <li><js>"sc"</js> - Only <l>Class</l> objects are allowed.
842    *    </ul>
843    * @return This object (for method chaining).
844    * @throws ConfigException If property is not a SET property.
845    */
846   @FluentSetter
847   public ContextBuilder addTo(String name, Object value) {
848      psb.addTo(name, value);
849      return this;
850   }
851
852   /**
853    * Adds a free-form value to the end of a LIST property.
854    *
855    * <p>
856    * LIST properties are those properties with one of the following type parts:
857    * <ul>
858    *    <li><js>"ls"</js> - <c>Linkedlist&lt;String&gt;</c>
859    *    <li><js>"li"</js> - <c>Linkedlist&lt;Integer&gt;</c>
860    *    <li><js>"lc"</js> - <c>Linkedlist&lt;Class&gt;</c>
861    *    <li><js>"lo"</js> - <c>Linkedlist&lt;Object&gt;</c>
862    * </ul>
863    *
864    * <p>
865    * For example, the {@link BeanContext#BEAN_swaps} property which has the value <js>"BeanContext.swaps.lo"</js>.
866    *
867    * <h5 class='section'>Example:</h5>
868    * <p class='bcode w800'>
869    *    <jc>// Create a serializer that converts Temporal objects to Basic ISO date strings.</jc>
870    *    WriterSerializer s = JsonSerializer
871    *       .<jsm>create</jsm>()
872    *       .swaps(TemoralCalendarSwap.BasicIsoDate.<jk>class</jk>)
873    *       .build();
874    *
875    *    <jc>// Same, but use generic appendTo() method.</jc>
876    *    WriterSerializer s = JsonSerializer
877    *       .<jsm>create</jsm>()
878    *       .appendTo(<jsf>BEAN_swaps</jsf>, TemoralCalendarSwap.BasicIsoDate.<jk>class</jk>)
879    *       .build();
880    * </p>
881    *
882    * <ul class='seealso'>
883    *    <li class='jc'>{@link PropertyStore}
884    *    <li class='jm'>{@link #set(String, Object)}
885    * </ul>
886    *
887    * @param name The property name.
888    * @param value
889    * The new value to add to the LIST property.
890    *    <br>The valid value types depend on the property type:
891    *    <ul>
892    *       <li><js>"ls"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
893    *       <li><js>"li"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
894    *       <li><js>"lc"</js> - Only <l>Class</l> objects are allowed.
895    *       <li><js>"lo"</js> - Left as-is.
896    *    </ul>
897    * @return This object (for method chaining).
898    * @throws ConfigException If property is not a LIST property.
899    */
900   @FluentSetter
901   public ContextBuilder appendTo(String name, Object value) {
902      psb.appendTo(name, value);
903      return this;
904   }
905
906   /**
907    * Adds a free-form value to the beginning of a LIST property.
908    *
909    * <p>
910    * LIST properties are those properties with one of the following type parts:
911    * <ul>
912    *    <li><js>"ls"</js> - <c>Linkedlist&lt;String&gt;</c>
913    *    <li><js>"li"</js> - <c>Linkedlist&lt;Integer&gt;</c>
914    *    <li><js>"lc"</js> - <c>Linkedlist&lt;Class&gt;</c>
915    *    <li><js>"lo"</js> - <c>Linkedlist&lt;Object&gt;</c>
916    * </ul>
917    *
918    * <p>
919    * For example, the {@link BeanContext#BEAN_swaps} property which has the value <js>"BeanContext.swaps.lo"</js>.
920    *
921    * <h5 class='section'>Example:</h5>
922    * <p class='bcode w800'>
923    *    <jc>// Create a serializer that converts Temporal objects to Basic ISO date strings.</jc>
924    *    WriterSerializer s = JsonSerializer
925    *       .<jsm>create</jsm>()
926    *       .swaps(TemoralCalendarSwap.BasicIsoDate.<jk>class</jk>)
927    *       .build();
928    *
929    *    <jc>// Same, but use generic prependTo() method.</jc>
930    *    WriterSerializer s = JsonSerializer
931    *       .<jsm>create</jsm>()
932    *       .prependTo(<jsf>BEAN_swaps</jsf>, TemoralCalendarSwap.BasicIsoDate.<jk>class</jk>)
933    *       .build();
934    * </p>
935    *
936    * <ul class='seealso'>
937    *    <li class='jc'>{@link PropertyStore}
938    *    <li class='jm'>{@link #set(String, Object)}
939    * </ul>
940    *
941    * @param name The property name.
942    * @param value
943    *    The new value to add to the LIST property.
944    *    <br>The valid value types depend on the property type:
945    *    <ul>
946    *       <li><js>"ls"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
947    *       <li><js>"li"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
948    *       <li><js>"lc"</js> - Only <l>Class</l> objects are allowed.
949    *       <li><js>"lo"</js> - Left as-is.
950    *    </ul>
951    * @return This object (for method chaining).
952    * @throws ConfigException If property is not a LIST property.
953    */
954   @FluentSetter
955   public ContextBuilder prependTo(String name, Object value) {
956      psb.prependTo(name, value);
957      return this;
958   }
959
960   /**
961    * Adds or overwrites a free-form entry in a MAP property.
962    *
963    * <p>
964    * MAP properties are those properties with one of the following type parts:
965    * <ul>
966    *    <li><js>"sms"</js> - <c>TreeMap&lt;String,String&gt;</c>
967    *    <li><js>"smi"</js> - <c>TreeMap&lt;String,Integer&gt;</c>
968    *    <li><js>"smc"</js> - <c>TreeMap&lt;String,Class&gt;</c>
969    *    <li><js>"smo"</js> - <c>TreeMap&lt;String,Object&gt;</c>
970    *    <li><js>"oms"</js> - <c>LinkedHashMap&lt;String,String&gt;</c>
971    *    <li><js>"omi"</js> - <c>LinkedHashMap&lt;String,Integer&gt;</c>
972    *    <li><js>"omc"</js> - <c>LinkedHashMap&lt;String,Class&gt;</c>
973    *    <li><js>"omo"</js> - <c>LinkedHashMap&lt;String,Object&gt;</c>
974    * </ul>
975    *
976    * <p>
977    * For example, the {@link BeanContext#BEAN_implClasses} property which has the value <js>"BeanContext.implClasses.smc"</js>.
978    *
979    * <h5 class='section'>Example:</h5>
980    * <p class='bcode w800'>
981    *    <jc>// Create a serializer that specifies the concrete implementation class for an interface.</jc>
982    *    WriterSerializer s = JsonSerializer
983    *       .<jsm>create</jsm>()
984    *       .implClass(MyInterface.<jk>class</jk>, MyImplementation.<jk>class</jk>)
985    *       .build();
986    *
987    *    <jc>// Same, but use generic putTo() method.</jc>
988    *    WriterSerializer s = JsonSerializer
989    *       .<jsm>create</jsm>()
990    *       .putTo(<jsf>BEAN_implClasses</jsf>, MyInterface.<jk>class</jk>.getName(), MyImplementation.<jk>class</jk>)
991    *       .build();
992    * </p>
993    *
994    * <ul class='seealso'>
995    *    <li class='jc'>{@link PropertyStore}
996    *    <li class='jm'>{@link #set(String, Object)}
997    * </ul>
998    *
999    * @param name The property name.
1000    * @param key The property value map key.
1001    * @param value
1002    *    The property value map value.
1003    *    <br>The valid value types depend on the property type:
1004    *    <ul>
1005    *       <li><js>"sms"</js>,<js>"oms"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
1006    *       <li><js>"smi"</js>,<js>"omi"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
1007    *       <li><js>"smc"</js>,<js>"omc"</js> - Only <l>Class</l> objects are allowed.
1008    *       <li><js>"smo"</js>,<js>"omo"</js> - Left as-is.
1009    *    </ul>
1010    * @return This object (for method chaining).
1011    * @throws ConfigException If property is not a MAP property.
1012    */
1013   @FluentSetter
1014   public ContextBuilder putTo(String name, String key, Object value) {
1015      psb.putTo(name, key, value);
1016      return this;
1017   }
1018
1019   /**
1020    * Adds or overwrites multiple free-form entries in a MAP property.
1021    *
1022    * <p>
1023    * MAP properties are those properties with one of the following type parts:
1024    * <ul>
1025    *    <li><js>"sms"</js> - <c>TreeMap&lt;String,String&gt;</c>
1026    *    <li><js>"smi"</js> - <c>TreeMap&lt;String,Integer&gt;</c>
1027    *    <li><js>"smc"</js> - <c>TreeMap&lt;String,Class&gt;</c>
1028    *    <li><js>"smo"</js> - <c>TreeMap&lt;String,Object&gt;</c>
1029    *    <li><js>"oms"</js> - <c>LinkedHashMap&lt;String,String&gt;</c>
1030    *    <li><js>"omi"</js> - <c>LinkedHashMap&lt;String,Integer&gt;</c>
1031    *    <li><js>"omc"</js> - <c>LinkedHashMap&lt;String,Class&gt;</c>
1032    *    <li><js>"omo"</js> - <c>LinkedHashMap&lt;String,Object&gt;</c>
1033    * </ul>
1034    *
1035    * <p>
1036    * For example, the {@link BeanContext#BEAN_implClasses} property which has the value <js>"BeanContext.implClasses.smc"</js>.
1037    *
1038    * <h5 class='section'>Example:</h5>
1039    * <p class='bcode w800'>
1040    *    <jc>// Create a serializer that specifies the concrete implementation class for an interface.</jc>
1041    *    WriterSerializer s = JsonSerializer
1042    *       .<jsm>create</jsm>()
1043    *       .implClass(MyInterface.<jk>class</jk>, MyImplementation.<jk>class</jk>)
1044    *       .build();
1045    *
1046    *    <jc>// Same, but use generic putAllTo() method.</jc>
1047    *    WriterSerializer s = JsonSerializer
1048    *       .<jsm>create</jsm>()
1049    *       .putAllTo(<jsf>BEAN_implClasses</jsf>,
1050    *          AMap.<jsm>of</jsm>(MyInterface.<jk>class</jk>.getName(), MyImplementation.<jk>class</jk>)
1051    *       )
1052    *       .build();
1053    * </p>
1054    *
1055    * <ul class='seealso'>
1056    *    <li class='jc'>{@link PropertyStore}
1057    *    <li class='jm'>{@link #set(String, Object)}
1058    * </ul>
1059    *
1060    * @param name The property name.
1061    * @param value
1062    *    Either a JSON Object string or a {@link Map} whose valid value types depend on the property type:
1063    *    <ul>
1064    *       <li><js>"sms"</js>,<js>"oms"</js> - Any <l>Object</l> converted to a <l>String</l> using <c>value.toString()</c>.
1065    *       <li><js>"smi"</js>,<js>"omi"</js> - Any <l>Object</l> converted to an <l>Integer</l> using <c>Integer.<jsm>valueOf</jsm>(value.toString())</c>.
1066    *       <li><js>"smc"</js>,<js>"omc"</js> - Only <l>Class</l> objects are allowed.
1067    *       <li><js>"smo"</js>,<js>"omo"</js> - Left as-is.
1068    *    </ul>
1069    * @return This object (for method chaining).
1070    * @throws ConfigException If property is not a MAP property.
1071    */
1072   @FluentSetter
1073   public ContextBuilder putAllTo(String name, Object value) {
1074      psb.putAllTo(name, value);
1075      return this;
1076   }
1077
1078   /**
1079    * Removes a free-form value from a SET, LIST, or MAP property.
1080    *
1081    * <h5 class='section'>Example:</h5>
1082    * <p class='bcode w800'>
1083    *    <jc>// Create a serializer that specifies the concrete implementation class for an interface.</jc>
1084    *    WriterSerializer s = JsonSerializer
1085    *       .<jsm>create</jsm>()
1086    *       .swaps(TemoralCalendarSwap.BasicIsoDate.<jk>class</jk>)
1087    *       .build();
1088    *
1089    *    <jc>// Clone the previous serializer but remove the swap.</jc>
1090    *    s = s
1091    *       .<jsm>builder</jsm>()
1092    *       .removeFrom(<jsf>BEAN_swaps</jsf>, TemoralCalendarSwap.BasicIsoDate.<jk>class</jk>)
1093    *       .build();
1094    * </p>
1095    *
1096    * <ul class='seealso'>
1097    *    <li class='jc'>{@link PropertyStore}
1098    *    <li class='jm'>{@link #set(String, Object)}
1099    * </ul>
1100    *
1101    * @param name The property name.
1102    * @param value The property value in the SET/LIST/MAP property.
1103    * @return This object (for method chaining).
1104    * @throws ConfigException If property is not a SET/LIST/MAP property.
1105    */
1106   @FluentSetter
1107   public ContextBuilder removeFrom(String name, Object value) {
1108      psb.removeFrom(name, value);
1109      return this;
1110   }
1111
1112   // <FluentSetters>
1113
1114   // </FluentSetters>
1115}