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