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.transform;
014
015import static org.apache.juneau.internal.StringUtils.*;
016import static java.util.Arrays.*;
017
018import java.beans.*;
019import java.util.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.annotation.*;
023import org.apache.juneau.reflect.*;
024
025/**
026 * Builder class for {@link BeanFilter} objects.
027 *
028 * <p>
029 * This class is the programmatic equivalent to the {@link Bean @Bean} annotation.
030 *
031 * <p>
032 * The general approach to defining bean filters is to create subclasses from this class and call methods to
033 * set various attributes
034 * <p class='bcode w800'>
035 *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
036 *
037 *       <jc>// Must provide a no-arg constructor!</jc>
038 *       <jk>public</jk> MyFilter() {
039 *
040 *          <jc>// Call one or more configuration methods.</jc>
041 *          bpi(<js>"foo,bar,baz"</js>);
042 *          sortProperties();
043 *          propertyNamer(PropertyNamerULC.<jk>class</jk>);
044 *       }
045 *    }
046 *
047 *    <jc>// Register it with a serializer or parser.</jc>
048 *    WriterSerializer s = JsonSerializer
049 *       .<jsm>create</jsm>()
050 *       .beanFilters(MyFilter.<jk>class</jk>)
051 *       .build();
052 * </p>
053 *
054 * <ul class='seealso'>
055 *    <li class='link'>{@doc juneau-marshall.Transforms.BeanFilters}
056 * </ul>
057 *
058 * @param <T> The bean type that this filter applies to.
059 */
060public class BeanFilterBuilder<T> {
061
062   Class<?> beanClass;
063   String typeName;
064   Set<String>
065      bpi = new LinkedHashSet<>(),
066      bpx = new LinkedHashSet<>(),
067      bpro = new LinkedHashSet<>(),
068      bpwo = new LinkedHashSet<>();
069   Class<?> interfaceClass, stopClass;
070   boolean sortProperties, fluentSetters;
071   Object propertyNamer;
072   List<Class<?>> dictionary;
073   Object propertyFilter;
074
075   /**
076    * Constructor.
077    *
078    * <p>
079    * Bean class is determined through reflection of the parameter type.
080    */
081   protected BeanFilterBuilder() {
082      beanClass = ClassInfo.of(this.getClass()).getParameterType(0, BeanFilterBuilder.class);
083   }
084
085   /**
086    * Constructor.
087    *
088    * @param beanClass The bean class that this filter applies to.
089    */
090   protected BeanFilterBuilder(Class<?> beanClass) {
091      this.beanClass = beanClass;
092   }
093
094   /**
095    * Configuration property:  Bean dictionary type name.
096    *
097    * <p>
098    * Specifies the dictionary type name for this bean.
099    *
100    * <h5 class='section'>Example:</h5>
101    * <p class='bcode w800'>
102    *    <jc>// Define our filter.</jc>
103    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
104    *       <jk>public</jk> MyFilter() {
105    *          typeName(<js>"mybean"</js>);
106    *       }
107    *    }
108    *
109    *    <jc>// Register it with a serializer or parser.</jc>
110    *    WriterSerializer s = JsonSerializer
111    *       .<jsm>create</jsm>()
112    *       .beanFilters(MyFilter.<jk>class</jk>)
113    *       .build();
114    *
115    *    <jc>// Produces:  "{_type:'mybean', ...}"</jc>
116    *    String json = s.serialize(<jk>new</jk> MyBean());
117    * </p>
118    *
119    * <ul class='seealso'>
120    *    <li class='ja'>{@link Bean#typeName()}
121    * </ul>
122    *
123    * @param value The new value for this setting.
124    * @return This object (for method chaining).
125    */
126   public BeanFilterBuilder<T> typeName(String value) {
127      this.typeName = value;
128      return this;
129   }
130
131   /**
132    * Configuration property:  Bean property includes.
133    *
134    * @deprecated Use {@link #bpi(String...)}
135    */
136   @SuppressWarnings("javadoc")
137   @Deprecated public BeanFilterBuilder<T> properties(String...value) {
138      this.bpi = new LinkedHashSet<>();
139      for (String v : value)
140         bpi.addAll(asList(split(v)));
141      return this;
142   }
143
144   /**
145    * Configuration property:  Bean property excludes.
146    *
147    * @deprecated Use {@link #bpx(String...)}
148    */
149   @SuppressWarnings("javadoc")
150   @Deprecated public BeanFilterBuilder<T> excludeProperties(String...value) {
151      this.bpx = new LinkedHashSet<>();
152      for (String v : value)
153         bpx.addAll(asList(split(v)));
154      return this;
155   }
156
157   /**
158    * Configuration property:  Bean interface class.
159    *
160    * Identifies a class to be used as the interface class for this and all subclasses.
161    *
162    * <p>
163    * When specified, only the list of properties defined on the interface class will be used during serialization.
164    * <br>Additional properties on subclasses will be ignored.
165    *
166    * <p class='bcode w800'>
167    *    <jc>// Parent class</jc>
168    *    <jk>public abstract class</jk> A {
169    *       <jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
170    *    }
171    *
172    *    <jc>// Sub class</jc>
173    *    <jk>public class</jk> A1 <jk>extends</jk> A {
174    *       <jk>public</jk> String <jf>f1</jf> = <js>"f1"</js>;
175    *    }
176    *
177    *    <jc>// Define our filter.</jc>
178    *    <jk>public class</jk> AFilter <jk>extends</jk> BeanFilterBuilder&lt;A&gt; {
179    *       <jk>public</jk> AFilter() {
180    *          interfaceClass(A.<jk>class</jk>);
181    *       }
182    *    }
183    *
184    *    <jc>// Register it with a serializer.</jc>
185    *    WriterSerializer s = JsonSerializer
186    *       .<jsm>create</jsm>()
187    *       .beanFilters(AFilter.<jk>class</jk>)
188    *       .build();
189    *
190    *    <jc>// Use it.</jc>
191    *    A1 a1 = <jk>new</jk> A1();
192    *    String r = s.serialize(a1);
193    *    <jsm>assertEquals</jsm>(<js>"{f0:'f0'}"</js>, r);  <jc>// Note f1 is not serialized</jc>
194    * </p>
195    *
196    * <p>
197    * Note that this filter can be used on the parent class so that it filters to all child classes, or can be set
198    * individually on the child classes.
199    *
200    * <ul class='seealso'>
201    *    <li class='ja'>{@link Bean#interfaceClass()}
202    *    <li class='jf'>{@link BeanContext#BEAN_beanFilters}
203    * </ul>
204    *
205    * @param value The new value for this setting.
206    * @return This object (for method chaining).
207    */
208   public BeanFilterBuilder<T> interfaceClass(Class<?> value) {
209      this.interfaceClass = value;
210      return this;
211   }
212
213   /**
214    * Configuration property:  Bean stop class.
215    *
216    * <p>
217    * Identifies a stop class for this class and all subclasses.
218    *
219    * <p>
220    * Identical in purpose to the stop class specified by {@link Introspector#getBeanInfo(Class, Class)}.
221    * <br>Any properties in the stop class or in its base classes will be ignored during analysis.
222    *
223    * <p>
224    * For example, in the following class hierarchy, instances of <c>C3</c> will include property <c>p3</c>,
225    * but not <c>p1</c> or <c>p2</c>.
226    *
227    * <h5 class='section'>Example:</h5>
228    * <p class='bcode w800'>
229    *    <jk>public class</jk> C1 {
230    *       <jk>public int</jk> getP1();
231    *    }
232    *
233    *    <jk>public class</jk> C2 <jk>extends</jk> C1 {
234    *       <jk>public int</jk> getP2();
235    *    }
236    *
237    *    <jk>public class</jk> C3 <jk>extends</jk> C2 {
238    *       <jk>public int</jk> getP3();
239    *    }
240    *
241    *    <jc>// Define our filter.</jc>
242    *    <jk>public class</jk> C3Filter <jk>extends</jk> BeanFilterBuilder&lt;C3&gt; {
243    *       <jk>public</jk> C3Filter() {
244    *          stopClass(C2.<jk>class</jk>);
245    *       }
246    *    }
247    *
248    *    <jc>// Register it with a serializer.</jc>
249    *    WriterSerializer s = JsonSerializer
250    *       .<jsm>create</jsm>()
251    *       .beanFilters(C3Filter.<jk>class</jk>)
252    *       .build();
253    *
254    *    <jc>// Serializes property 'p3', but NOT 'p1' or 'p2'.</jc>
255    *    String json = s.serialize(<jk>new</jk> C3());
256    * </p>
257    *
258    * <ul class='seealso'>
259    *    <li class='ja'>{@link Bean#stopClass()}
260    * </ul>
261    *
262    * @param value The new value for this setting.
263    * @return This object (for method chaining).
264    */
265   public BeanFilterBuilder<T> stopClass(Class<?> value) {
266      this.stopClass = value;
267      return this;
268   }
269
270   /**
271    * Configuration property:  Sort bean properties.
272    *
273    * <p>
274    * When <jk>true</jk>, all bean properties will be serialized and access in alphabetical order.
275    * <br>Otherwise, the natural order of the bean properties is used which is dependent on the JVM vendor.
276    *
277    * <h5 class='section'>Example:</h5>
278    * <p class='bcode w800'>
279    *    <jc>// Define our filter.</jc>
280    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
281    *       <jk>public</jk> MyFilter() {
282    *          sortProperties();
283    *       }
284    *    }
285    *
286    *    <jc>// Register it with a serializer.</jc>
287    *    WriterSerializer s = JsonSerializer
288    *       .<jsm>create</jsm>()
289    *       .beanFilters(MyFilter.<jk>class</jk>)
290    *       .build();
291    *
292    *    <jc>// Properties will be sorted alphabetically.</jc>
293    *    String json = s.serialize(<jk>new</jk> MyBean());
294    * </p>
295    *
296    * <ul class='seealso'>
297    *    <li class='ja'>{@link Bean#sort()}
298    *    <li class='jf'>{@link BeanContext#BEAN_sortProperties}
299    * </ul>
300    *
301    * @param value
302    *    The new value for this property.
303    *    <br>The default is <jk>false</jk>.
304    * @return This object (for method chaining).
305    */
306   public BeanFilterBuilder<T> sortProperties(boolean value) {
307      this.sortProperties = value;
308      return this;
309   }
310
311   /**
312    * Configuration property:  Sort bean properties.
313    *
314    * <p>
315    * Shortcut for calling <code>sortProperties(<jk>true</jk>)</code>.
316    *
317    * <ul class='seealso'>
318    *    <li class='ja'>{@link Bean#sort()}
319    *    <li class='jf'>{@link BeanContext#BEAN_sortProperties}
320    * </ul>
321    *
322    * @return This object (for method chaining).
323    */
324   public BeanFilterBuilder<T> sortProperties() {
325      this.sortProperties = true;
326      return this;
327   }
328
329   /**
330    * Configuration property:  Find fluent setters.
331    *
332    * <p>
333    * When enabled, fluent setters are detected on beans.
334    *
335    * <p>
336    * Fluent setters must have the following attributes:
337    * <ul>
338    *    <li>Public.
339    *    <li>Not static.
340    *    <li>Take in one parameter.
341    *    <li>Return the bean itself.
342    * </ul>
343    *
344    * <h5 class='section'>Example:</h5>
345    * <p class='bcode w800'>
346    *    <jc>// Define our filter.</jc>
347    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
348    *       <jk>public</jk> MyFilter() {
349    *          fluentSetters();
350    *       }
351    *    }
352    * </p>
353    *
354    * <ul class='seealso'>
355    *    <li class='ja'>{@link Bean#fluentSetters()}
356    *    <li class='jf'>{@link BeanContext#BEAN_fluentSetters}
357    * </ul>
358    *
359    * @param value
360    *    The new value for this property.
361    *    <br>The default is <jk>false</jk>.
362    * @return This object (for method chaining).
363    */
364   public BeanFilterBuilder<T> fluentSetters(boolean value) {
365      this.fluentSetters = value;
366      return this;
367   }
368
369   /**
370    * Configuration property:  Find fluent setters.
371    *
372    * <p>
373    * Shortcut for calling <code>fluentSetters(<jk>true</jk>)</code>.
374    *
375    * <ul class='seealso'>
376    *    <li class='ja'>{@link Bean#fluentSetters()}
377    *    <li class='jf'>{@link BeanContext#BEAN_fluentSetters}
378    * </ul>
379    *
380    * @return This object (for method chaining).
381    */
382   public BeanFilterBuilder<T> fluentSetters() {
383      this.fluentSetters = true;
384      return this;
385   }
386
387   /**
388    * Configuration property:  Bean property namer
389    *
390    * <p>
391    * The class to use for calculating bean property names.
392    *
393    * <h5 class='section'>Example:</h5>
394    * <p class='bcode w800'>
395    *    <jc>// Define our filter.</jc>
396    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
397    *       <jk>public</jk> MyFilter() {
398    *          <jc>// Use Dashed-Lower-Case property names.</jc>
399    *          <jc>// (e.g. "foo-bar-url" instead of "fooBarURL")</jc>
400    *          propertyNamer(PropertyNamerDLC.<jk>class</jk>);
401    *       }
402    *    }
403    *
404    *    <jc>// Register it with a serializer or parser.</jc>
405    *    WriterSerializer s = JsonSerializer
406    *       .<jsm>create</jsm>()
407    *       .beanFilters(MyFilter.<jk>class</jk>)
408    *       .build();
409    *
410    *    <jc>// Properties names will be Dashed-Lower-Case.</jc>
411    *    String json = s.serialize(<jk>new</jk> MyBean());
412    * </p>
413    *
414    * <ul class='seealso'>
415    *    <li class='ja'>{@link Bean#propertyNamer()}
416    *    <li class='jf'>{@link BeanContext#BEAN_propertyNamer}
417    *    <li class='jc'>{@link PropertyNamer}
418    * </ul>
419    *
420    * @param value
421    *    The new value for this setting.
422    *    <br>The default is {@link PropertyNamerDefault}.
423    * @return This object (for method chaining).
424    */
425   public BeanFilterBuilder<T> propertyNamer(Class<? extends PropertyNamer> value) {
426      this.propertyNamer = value;
427      return this;
428   }
429
430   /**
431    * Configuration property:  Bean dictionary.
432    *
433    * <p>
434    * Adds to the list of classes that make up the bean dictionary for this bean.
435    *
436    * <h5 class='section'>Example:</h5>
437    * <p class='bcode w800'>
438    *    <jc>// Define our filter.</jc>
439    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
440    *       <jk>public</jk> MyFilter() {
441    *          <jc>// Our bean contains generic collections of Foo and Bar objects.</jc>
442    *          beanDictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>);
443    *       }
444    *    }
445    *
446    *    <jc>// Register it with a parser.</jc>
447    *    ReaderParser p = JsonParser
448    *       .<jsm>create</jsm>()
449    *       .beanFilters(MyFilter.<jk>class</jk>)
450    *       .build();
451    *
452    *    <jc>// Instantiate our bean.</jc>
453    *    MyBean myBean = p.parse(json);
454    * </p>
455    *
456    * <ul class='seealso'>
457    *    <li class='ja'>{@link Bean#dictionary()}
458    *    <li class='jf'>{@link BeanContext#BEAN_beanDictionary}
459    * </ul>
460    *
461    * @param values
462    *    The values to add to this property.
463    * @return This object (for method chaining).
464    * @deprecated Use {@link #dictionary(Class...)}.
465    */
466   @Deprecated
467   public BeanFilterBuilder<T> beanDictionary(Class<?>...values) {
468      if (dictionary == null)
469         dictionary = new ArrayList<>(Arrays.asList(values));
470      else for (Class<?> cc : values)
471         dictionary.add(cc);
472      return this;
473   }
474
475   /**
476    * Configuration property:  Bean property includes.
477    *
478    * <p>
479    * Specifies the set and order of names of properties associated with the bean class.
480    *
481    * <h5 class='section'>Example:</h5>
482    * <p class='bcode w800'>
483    *    <jc>// Define our filter.</jc>
484    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
485    *       <jk>public</jk> MyFilter() {
486    *          bpi(<js>"foo,bar,baz"</js>);
487    *       }
488    *    }
489    *
490    *    <jc>// Register it with a serializer.</jc>
491    *    WriterSerializer s = JsonSerializer
492    *       .<jsm>create</jsm>()
493    *       .beanFilters(MyFilter.<jk>class</jk>)
494    *       .build();
495    *
496    *    <jc>// Only serializes the properties 'foo', 'bar', and 'baz'.</jc>
497    *    String json = s.serialize(<jk>new</jk> MyBean());
498    * </p>
499    *
500    * <ul class='seealso'>
501    *    <li class='ja'>{@link Bean#bpi()}
502    *    <li class='jf'>{@link BeanContext#BEAN_bpi}
503    * </ul>
504    *
505    * @param value
506    *    The new value for this setting.
507    *    <br>Values can contain comma-delimited list of property names.
508    * @return This object (for method chaining).
509    */
510   public BeanFilterBuilder<T> bpi(String...value) {
511      this.bpi = new LinkedHashSet<>();
512      for (String v : value)
513         bpi.addAll(asList(split(v)));
514      return this;
515   }
516
517   /**
518    * Configuration property:  Bean property excludes.
519    *
520    * <p>
521    * Specifies properties to exclude from the bean class.
522    *
523    * <h5 class='section'>Example:</h5>
524    * <p class='bcode w800'>
525    *    <jc>// Define our filter.</jc>
526    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
527    *       <jk>public</jk> MyFilter() {
528    *          bpx(<js>"foo,bar"</js>);
529    *       }
530    *    }
531    *
532    *    <jc>// Register it with a serializer.</jc>
533    *    WriterSerializer s = JsonSerializer
534    *       .<jsm>create</jsm>()
535    *       .beanFilters(MyFilter.<jk>class</jk>)
536    *       .build();
537    *
538    *    <jc>// Serializes all properties except for 'foo' and 'bar'.</jc>
539    *    String json = s.serialize(<jk>new</jk> MyBean());
540    * </p>
541    *
542    * <ul class='seealso'>
543    *    <li class='ja'>{@link Bean#bpx()}
544    *    <li class='jf'>{@link BeanContext#BEAN_bpx}
545    * </ul>
546    *
547    * @param value
548    *    The new value for this setting.
549    *    <br>Values can contain comma-delimited list of property names.
550    * @return This object (for method chaining).
551    */
552   public BeanFilterBuilder<T> bpx(String...value) {
553      this.bpx = new LinkedHashSet<>();
554      for (String v : value)
555         bpx.addAll(asList(split(v)));
556      return this;
557   }
558
559   /**
560    * Configuration property:  Read-only bean properties.
561    *
562    * <p>
563    * Specifies one or more properties on a bean that are read-only despite having valid getters.
564    * Serializers will serialize such properties as usual, but parsers will silently ignore them.
565    *
566    * <h5 class='section'>Example:</h5>
567    * <p class='bcode w800'>
568    *    <jc>// Define our filter.</jc>
569    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
570    *       <jk>public</jk> MyFilter() {
571    *          bpro(<js>"foo,bar"</js>);
572    *       }
573    *    }
574    *
575    *    <jc>// Register it with a parser.</jc>
576    *  ReaderParser p = JsonParser
577    *       .<jsm>create</jsm>()
578    *       .beanFilters(MyFilter.<jk>class</jk>)
579    *       .build();
580    *
581    *    <jc>// Parsers all properties except for 'foo' and 'bar'.</jc>
582    *    MyBean b = p.parse(<js>"..."</js>, MyBean.<jk>class</jk>);
583    * </p>
584    *
585    * <ul class='seealso'>
586    *    <li class='ja'>{@link Bean#bpro()}
587    *    <li class='ja'>{@link Beanp#ro()}
588    *    <li class='jf'>{@link BeanContext#BEAN_bpro}
589    * </ul>
590    *
591    * @param value
592    *    The new value for this setting.
593    *    <br>Values can contain comma-delimited list of property names.
594    * @return This object (for method chaining).
595    */
596   public BeanFilterBuilder<T> bpro(String...value) {
597      this.bpro = new LinkedHashSet<>();
598      for (String v : value)
599         bpro.addAll(asList(split(v)));
600      return this;
601   }
602
603   /**
604    * Configuration property:  Write-only bean properties.
605    *
606    * <p>
607    * Specifies one or more properties on a bean that are write-only despite having valid setters.
608    * Parsers will parse such properties as usual, but serializers will silently ignore them.
609    *
610    * <h5 class='section'>Example:</h5>
611    * <p class='bcode w800'>
612    *    <jc>// Define our filter.</jc>
613    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
614    *       <jk>public</jk> MyFilter() {
615    *          bpwo(<js>"foo,bar"</js>);
616    *       }
617    *    }
618    *
619    *    <jc>// Register it with a serializer.</jc>
620    *  WriterSerializer s = JsonSerializer
621    *       .<jsm>create</jsm>()
622    *       .beanFilters(MyFilter.<jk>class</jk>)
623    *       .build();
624    *
625    *    <jc>// Serializes all properties except for 'foo' and 'bar'.</jc>
626    *    String json = s.serialize(<jk>new</jk> MyBean());
627    * </p>
628    *
629    * <ul class='seealso'>
630    *    <li class='ja'>{@link Bean#bpwo()}
631    *    <li class='ja'>{@link Beanp#wo()}
632    *    <li class='jf'>{@link BeanContext#BEAN_bpwo}
633    * </ul>
634    *
635    * @param value
636    *    The new value for this setting.
637    *    <br>Values can contain comma-delimited list of property names.
638    * @return This object (for method chaining).
639    */
640   public BeanFilterBuilder<T> bpwo(String...value) {
641      this.bpwo = new LinkedHashSet<>();
642      for (String v : value)
643         bpwo.addAll(asList(split(v)));
644      return this;
645   }
646
647   /**
648    * Configuration property:  Bean dictionary.
649    *
650    * <p>
651    * Adds to the list of classes that make up the bean dictionary for this bean.
652    *
653    * <h5 class='section'>Example:</h5>
654    * <p class='bcode w800'>
655    *    <jc>// Define our filter.</jc>
656    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
657    *       <jk>public</jk> MyFilter() {
658    *          <jc>// Our bean contains generic collections of Foo and Bar objects.</jc>
659    *          beanDictionary(Foo.<jk>class</jk>, Bar.<jk>class</jk>);
660    *       }
661    *    }
662    *
663    *    <jc>// Register it with a parser.</jc>
664    *    ReaderParser p = JsonParser
665    *       .<jsm>create</jsm>()
666    *       .beanFilters(MyFilter.<jk>class</jk>)
667    *       .build();
668    *
669    *    <jc>// Instantiate our bean.</jc>
670    *    MyBean myBean = p.parse(json);
671    * </p>
672    *
673    * <ul class='seealso'>
674    *    <li class='ja'>{@link Bean#dictionary()}
675    *    <li class='jf'>{@link BeanContext#BEAN_beanDictionary}
676    * </ul>
677    *
678    * @param values
679    *    The values to add to this property.
680    * @return This object (for method chaining).
681    */
682   public BeanFilterBuilder<T> dictionary(Class<?>...values) {
683      if (dictionary == null)
684         dictionary = new ArrayList<>(Arrays.asList(values));
685      else for (Class<?> cc : values)
686         dictionary.add(cc);
687      return this;
688   }
689
690   /**
691    * Configuration property:  Property filter.
692    *
693    * <p>
694    * The property filter to use for intercepting and altering getter and setter calls.
695    *
696    * <h5 class='section'>Example:</h5>
697    * <p class='bcode w800'>
698    *    <jc>// Define our filter.</jc>
699    *    <jk>public class</jk> MyFilter <jk>extends</jk> BeanFilterBuilder&lt;MyBean&gt; {
700    *       <jk>public</jk> MyFilter() {
701    *          <jc>// Our bean contains generic collections of Foo and Bar objects.</jc>
702    *          propertyFilter(AddressPropertyFilter.<jk>class</jk>);
703    *       }
704    *    }
705    *
706    *    <jc>// Register it with a serializer or parser.</jc>
707    *    WriterSerializer s = JsonSerializer
708    *       .<jsm>create</jsm>()
709    *       .beanFilters(MyFilter.<jk>class</jk>)
710    *       .build();
711    * </p>
712    *
713    * <ul class='seealso'>
714    *    <li class='ja'>{@link Bean#propertyFilter()}
715    *    <li class='jc'>{@link PropertyFilter}
716    * </ul>
717    *
718    * @param value
719    *    The new value for this setting.
720    *    <br>The default value is {@link PropertyFilter}.
721    * @return This object (for method chaining).
722    */
723   public BeanFilterBuilder<T> propertyFilter(Class<? extends PropertyFilter> value) {
724      this.propertyFilter = value;
725      return this;
726   }
727
728   /**
729    * Creates a {@link BeanFilter} with settings in this builder class.
730    *
731    * @return A new {@link BeanFilter} instance.
732    */
733   public BeanFilter build() {
734      return new BeanFilter(this);
735   }
736}