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<MyBean> { 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<MyBean> { 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<A> { 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<C3> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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<MyBean> { 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}