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