This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new a6b6859  Simplify BeanConfig APIs
a6b6859 is described below

commit a6b68594985c8e00fb03f4c3238190b4a8bd1bbd
Author: JamesBognar <[email protected]>
AuthorDate: Thu Oct 15 13:56:30 2020 -0400

    Simplify BeanConfig APIs
---
 .../apache/juneau/BeanConfigAnnotationTest.java    |   4 +-
 .../java/org/apache/juneau/BeanConfigTest.java     |   6 +-
 .../main/java/org/apache/juneau/BeanContext.java   |  42 +-
 .../src/main/java/org/apache/juneau/BeanMap.java   |   2 +-
 .../src/main/java/org/apache/juneau/BeanMeta.java  |  12 +-
 .../main/java/org/apache/juneau/BeanSession.java   |   2 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |  12 +-
 .../org/apache/juneau/annotation/BeanConfig.java   |   4 +-
 .../transform/AnnotationBeanFilterBuilder.java     |  82 --
 .../org/apache/juneau/transform/BeanFilter.java    | 955 ++++++++++++++++-----
 .../apache/juneau/transform/BeanFilterBuilder.java | 672 ---------------
 .../transform/InterfaceBeanFilterBuilder.java      |  99 ---
 ...BeanFilter.java => UnmodifiableBeanFilter.java} |  10 +-
 .../apache/juneau/rest/jaxrs/JuneauProvider.java   |   4 +-
 14 files changed, 782 insertions(+), 1124 deletions(-)

diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
index 96998e7..f8d367c 100644
--- 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigAnnotationTest.java
@@ -64,8 +64,8 @@ public class BeanConfigAnnotationTest {
                                Map.Entry e = (Map.Entry)t;
                                return apply(e.getKey()) + "=" + 
apply(e.getValue());
                        }
-                       if (t instanceof BeanFilter)
-                               return 
((BeanFilter)t).getBeanClass().getSimpleName();
+                       if (t instanceof UnmodifiableBeanFilter)
+                               return 
((UnmodifiableBeanFilter)t).getBeanClass().getSimpleName();
                        if (t instanceof Class)
                                return ((Class<?>)t).getSimpleName();
                        if (t instanceof ClassInfo)
diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigTest.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigTest.java
index 5207b6e..393c919 100755
--- 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigTest.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/BeanConfigTest.java
@@ -770,9 +770,9 @@ public class BeanConfigTest {
        public static class DummyPojoSwapA extends MapSwap<A> {}
        public static class DummyPojoSwapB extends MapSwap<B> {}
        public static class DummyPojoSwapC extends MapSwap<C> {}
-       public static class DummyBeanFilterA extends BeanFilterBuilder<A> {}
-       public static class DummyBeanFilterB extends BeanFilterBuilder<B> {}
-       public static class DummyBeanFilterC extends BeanFilterBuilder<C> {}
+       public static class DummyBeanFilterA extends BeanFilter<A> {}
+       public static class DummyBeanFilterB extends BeanFilter<B> {}
+       public static class DummyBeanFilterC extends BeanFilter<C> {}
        public static class C {}
 
        private void assertSameCache(ParserBuilder p1b, ParserBuilder p2b) {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 59eae57..6afb857 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -40,7 +40,7 @@ import org.apache.juneau.utils.*;
  *     <li>
  *             Provides the ability to wrap beans inside {@link Map} 
interfaces.
  *     <li>
- *             Serves as a repository for metadata on POJOs, such as 
associated {@link BeanFilter BeanFilters},
+ *             Serves as a repository for metadata on POJOs, such as 
associated {@link UnmodifiableBeanFilter BeanFilters},
  *             {@link PropertyNamer PropertyNamers}, etc...  which are used to 
tailor how POJOs are serialized and parsed.
  * </ul>
  *
@@ -485,7 +485,7 @@ public class BeanContext extends Context implements 
MetaProvider {
         *      <li><b>Methods:</b>
         *              <ul>
         *                      <li class='jm'>{@link 
org.apache.juneau.BeanContextBuilder#dictionary(Object...)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilterBuilder#dictionary(Class...)}
+        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilter#dictionary(Class...)}
         *              </ul>
         * </ul>
         *
@@ -1244,8 +1244,8 @@ public class BeanContext extends Context implements 
MetaProvider {
         *      <li><b>Methods:</b>
         *              <ul>
         *                      <li class='jm'>{@link 
org.apache.juneau.BeanContextBuilder#fluentSetters()}
-        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilterBuilder#fluentSetters(boolean)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilterBuilder#fluentSetters()}
+        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilter#fluentSetters(boolean)}
+        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilter#fluentSetters()}
         *              </ul>
         * </ul>
         *
@@ -1853,7 +1853,7 @@ public class BeanContext extends Context implements 
MetaProvider {
         *      <li><b>Methods:</b>
         *              <ul>
         *                      <li class='jm'>{@link 
org.apache.juneau.BeanContextBuilder#propertyNamer(Class)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilterBuilder#propertyNamer(Class)}
+        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilter#propertyNamer(Class)}
         *              </ul>
         * </ul>
         *
@@ -1916,8 +1916,8 @@ public class BeanContext extends Context implements 
MetaProvider {
         *      <li><b>Methods:</b>
         *              <ul>
         *                      <li class='jm'>{@link 
org.apache.juneau.BeanContextBuilder#sortProperties()}
-        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilterBuilder#sortProperties(boolean)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilterBuilder#sortProperties()}
+        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilter#sortProperties(boolean)}
+        *                      <li class='jm'>{@link 
org.apache.juneau.transform.BeanFilter#sortProperties()}
         *              </ul>
         * </ul>
         *
@@ -2317,7 +2317,7 @@ public class BeanContext extends Context implements 
MetaProvider {
        private final Class<?>[] notBeanClasses;
        private final List<Class<?>> beanDictionaryClasses;
        private final String[] notBeanPackageNames, notBeanPackagePrefixes;
-       private final BeanFilter[] beanFilters;
+       private final UnmodifiableBeanFilter[] beanFilters;
        private final PojoSwap<?,?>[] swaps;
        private final Map<String,?> examples;
        private final BeanRegistry beanRegistry;
@@ -2405,17 +2405,19 @@ public class BeanContext extends Context implements 
MetaProvider {
                notBeanPackageNames = l1.toArray(new String[l1.size()]);
                notBeanPackagePrefixes = l2.toArray(new String[l2.size()]);
 
-               LinkedList<BeanFilter> lbf = new LinkedList<>();
+               LinkedList<UnmodifiableBeanFilter> lbf = new LinkedList<>();
                for (Object o : getListProperty(BEAN_beanFilters, 
Object[].class)) {
                        ClassInfo ci = o instanceof Class ? 
ClassInfo.of((Class)o) : ClassInfo.of(o);
-                       if (ci.isChildOf(BeanFilter.class))
-                               lbf.add(castOrCreate(BeanFilter.class, o));
-                       else if (ci.isChildOf(BeanFilterBuilder.class))
-                               lbf.add(castOrCreate(BeanFilterBuilder.class, 
o).build());
-                       else if (o instanceof Class)
-                               lbf.add(new 
InterfaceBeanFilterBuilder((Class<?>)o, this).build());
+                       if (ci.isChildOf(UnmodifiableBeanFilter.class))
+                               
lbf.add(castOrCreate(UnmodifiableBeanFilter.class, o));
+                       else if (ci.isChildOf(BeanFilter.class))
+                               lbf.add(castOrCreate(BeanFilter.class, 
o).build());
+                       else if (o instanceof Class) {
+                               Class<?> ic = (Class<?>) o;
+                               
lbf.add(BeanFilter.create(ic).interfaceClass(ic).applyAnnotations(ClassInfo.of(ic).getAnnotations(Bean.class,
 this)).build());
+                       }
                }
-               beanFilters = lbf.toArray(new BeanFilter[0]);
+               beanFilters = lbf.toArray(new UnmodifiableBeanFilter[0]);
 
                LinkedList<PojoSwap<?,?>> lpf = new LinkedList<>();
                for (Object o : getListProperty(BEAN_swaps, Object.class)) {
@@ -3046,16 +3048,16 @@ public class BeanContext extends Context implements 
MetaProvider {
        }
 
        /**
-        * Returns the {@link BeanFilter} associated with the specified class, 
or <jk>null</jk> if there is no bean filter
+        * Returns the {@link UnmodifiableBeanFilter} associated with the 
specified class, or <jk>null</jk> if there is no bean filter
         * associated with the class.
         *
         * @param <T> The class associated with the bean filter.
         * @param c The class associated with the bean filter.
         * @return The bean filter associated with the class, or null if there 
is no association.
         */
-       private final <T> BeanFilter findBeanFilter(Class<T> c) {
+       private final <T> UnmodifiableBeanFilter findBeanFilter(Class<T> c) {
                if (c != null)
-                       for (BeanFilter f : beanFilters)
+                       for (UnmodifiableBeanFilter f : beanFilters)
                                if 
(ClassInfo.of(f.getBeanClass()).isParentOf(c))
                                        return f;
                return null;
@@ -3642,7 +3644,7 @@ public class BeanContext extends Context implements 
MetaProvider {
         * @return
         *      Only look for bean fields with this specified minimum 
visibility.
         */
-       protected final BeanFilter[] getBeanFilters() {
+       protected final UnmodifiableBeanFilter[] getBeanFilters() {
                return beanFilters;
        }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
index 40e8008..c273208 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMap.java
@@ -51,7 +51,7 @@ import org.apache.juneau.xml.annotation.*;
  * </ul>
  *
  * <p>
- * <br>The order can also be overridden through the use of a {@link 
BeanFilter}.
+ * <br>The order can also be overridden through the use of a {@link 
UnmodifiableBeanFilter}.
  *
  * <h5 class='topic'>POJO swaps</h5>
  *
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index 2e4d9a1..a9cdd93 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -35,7 +35,7 @@ import org.apache.juneau.transform.*;
  * <h5 class='topic'>Description</h5>
  *
  * Uses introspection to find all the properties associated with this class.  
If the {@link Bean @Bean} annotation
- *     is present on the class, or the class has a {@link BeanFilter} 
registered with it in the bean context,
+ *     is present on the class, or the class has a {@link 
UnmodifiableBeanFilter} registered with it in the bean context,
  *     then that information is used to determine the properties on the class.
  * Otherwise, the {@code BeanInfo} functionality in Java is used to determine 
the properties on the class.
  *
@@ -56,7 +56,7 @@ import org.apache.juneau.transform.*;
  * </ul>
  *
  * <p>
- * The order can also be overridden through the use of an {@link BeanFilter}.
+ * The order can also be overridden through the use of an {@link 
UnmodifiableBeanFilter}.
  *
  * @param <T> The class type that this metadata applies to.
  */
@@ -84,7 +84,7 @@ public class BeanMeta<T> {
        protected final BeanContext ctx;
 
        /** Optional bean filter associated with the target class. */
-       protected final BeanFilter beanFilter;
+       protected final UnmodifiableBeanFilter beanFilter;
 
        /** Type variables implemented by this bean. */
        protected final Map<Class<?>,Class<?>[]> typeVarImpls;
@@ -113,7 +113,7 @@ public class BeanMeta<T> {
         * @param beanFilter Optional bean filter associated with the target 
class.  Can be <jk>null</jk>.
         * @param pNames Explicit list of property names and order of 
properties.  If <jk>null</jk>, determine automatically.
         */
-       protected BeanMeta(final ClassMeta<T> classMeta, BeanContext ctx, 
BeanFilter beanFilter, String[] pNames) {
+       protected BeanMeta(final ClassMeta<T> classMeta, BeanContext ctx, 
UnmodifiableBeanFilter beanFilter, String[] pNames) {
                this.classMeta = classMeta;
                this.ctx = ctx;
                this.c = classMeta.getInnerClass();
@@ -141,7 +141,7 @@ public class BeanMeta<T> {
        private static final class Builder<T> {
                ClassMeta<T> classMeta;
                BeanContext ctx;
-               BeanFilter beanFilter;
+               UnmodifiableBeanFilter beanFilter;
                String[] pNames;
                Map<String,BeanPropertyMeta> properties;
                AMap<String,BeanPropertyMeta> hiddenProperties = AMap.of();
@@ -157,7 +157,7 @@ public class BeanMeta<T> {
                String dictionaryName, typePropertyName;
                boolean sortProperties, fluentSetters;
 
-               Builder(ClassMeta<T> classMeta, BeanContext ctx, BeanFilter 
beanFilter, String[] pNames) {
+               Builder(ClassMeta<T> classMeta, BeanContext ctx, 
UnmodifiableBeanFilter beanFilter, String[] pNames) {
                        this.classMeta = classMeta;
                        this.ctx = ctx;
                        this.beanFilter = beanFilter;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 3fbb500..0effc4a 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -1222,7 +1222,7 @@ public class BeanSession extends Session {
         * @return
         *      Only look for bean fields with this specified minimum 
visibility.
         */
-       protected BeanFilter[] getBeanFilters() {
+       protected UnmodifiableBeanFilter[] getBeanFilters() {
                return ctx.getBeanFilters();
        }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 3b2a814..025407d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -93,7 +93,7 @@ public final class ClassMeta<T> implements Type {
                childSwapMap,                                        // Maps 
normal subclasses to PojoSwaps.
                childUnswapMap;                                      // Maps 
swap subclasses to PojoSwaps.
        private final PojoSwap<T,?>[] swaps;                     // The object 
POJO swaps associated with this bean (if it has any).
-       private final BeanFilter beanFilter;                    // The bean 
filter associated with this bean (if it has one).
+       private final UnmodifiableBeanFilter beanFilter;                    // 
The bean filter associated with this bean (if it has one).
        private final BuilderSwap<T,?> builderSwap;             // The builder 
swap associated with this bean (if it has one).
        private final BeanContext beanContext;                  // The bean 
context that created this object.
        private final ClassMeta<?>
@@ -126,7 +126,7 @@ public final class ClassMeta<T> implements Type {
         *      For interfaces and abstract classes, this represents the "real" 
class to instantiate.
         *      Can be <jk>null</jk>.
         * @param beanFilter
-        *      The {@link BeanFilter} programmatically associated with this 
class.
+        *      The {@link UnmodifiableBeanFilter} programmatically associated 
with this class.
         *      Can be <jk>null</jk>.
         * @param pojoSwap
         *      The {@link PojoSwap} programmatically associated with this 
class.
@@ -140,7 +140,7 @@ public final class ClassMeta<T> implements Type {
         *      Used for delayed initialization when the possibility of class 
reference loops exist.
         */
        @SuppressWarnings({ "rawtypes", "unchecked" })
-       ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends 
T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] swaps, PojoSwap<?,?>[] 
childPojoSwaps, Object example) {
+       ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends 
T> implClass, UnmodifiableBeanFilter beanFilter, PojoSwap<T,?>[] swaps, 
PojoSwap<?,?>[] childPojoSwaps, Object example) {
                this.innerClass = innerClass;
                this.info = ClassInfo.of(innerClass);
                this.beanContext = beanContext;
@@ -350,7 +350,7 @@ public final class ClassMeta<T> implements Type {
                Object example;
                Mutater<String,T> stringMutater;
 
-               ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, 
Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] swaps, 
PojoSwap<?,?>[] childPojoSwaps, Object example) {
+               ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, 
Class<? extends T> implClass, UnmodifiableBeanFilter beanFilter, 
PojoSwap<T,?>[] swaps, PojoSwap<?,?>[] childPojoSwaps, Object example) {
                        this.innerClass = innerClass;
                        this.beanContext = beanContext;
                        BeanContext bc = beanContext;
@@ -684,11 +684,11 @@ public final class ClassMeta<T> implements Type {
                        this.stringMutater = Mutaters.get(String.class, c);
                }
 
-               private BeanFilter findBeanFilter(BeanContext bc) {
+               private UnmodifiableBeanFilter findBeanFilter(BeanContext bc) {
                        try {
                                List<Bean> ba = info.getAnnotations(Bean.class, 
bc);
                                if (! ba.isEmpty())
-                                       return new 
AnnotationBeanFilterBuilder(innerClass, ba).build();
+                                       return 
BeanFilter.create(innerClass).applyAnnotations(ba).build();
                        } catch (Exception e) {
                                throw new RuntimeException(e);
                        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java
index a548a48..10e06d5 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanConfig.java
@@ -269,10 +269,10 @@ public @interface BeanConfig {
         *      <li>
         *              Values can consist of any of the following types:
         *              <ul class='spaced-list'>
-        *                      <li>Any subclass of {@link BeanFilterBuilder}.
+        *                      <li>Any subclass of {@link BeanFilter}.
         *                              <br>These must have a public no-arg 
constructor.
         *                      <li>Any bean interfaces.
-        *                              <br>A shortcut for defining a {@link 
InterfaceBeanFilterBuilder}.
+        *                              <br>A shortcut for defining a {@link 
BeanFilter} with {@link BeanFilter#interfaceClass(Class)}.
         *                              <br>Any subclasses of an interface 
class will only have properties defined on the interface.
         *                              <br>All other bean properties will be 
ignored.
         *              </ul>
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AnnotationBeanFilterBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AnnotationBeanFilterBuilder.java
deleted file mode 100644
index c3951eb..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AnnotationBeanFilterBuilder.java
+++ /dev/null
@@ -1,82 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.transform;
-
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.annotation.*;
-
-/**
- * Bean filter builder initialized from the contents of a {@link Bean @Bean} 
annotation found on a class.
- *
- * <p>
- * <b>*** Internal class - Not intended for external use ***</b>
- *
- * @param <T> Annotated bean class.
- */
-public final class AnnotationBeanFilterBuilder<T> extends BeanFilterBuilder<T> 
{
-
-       /**
-        * Constructor.
-        *
-        * @param annotatedClass The class found to have a {@link Bean @Bean} 
annotation.
-        * @param annotations
-        *      The {@link Bean @Bean} annotations found on the class and all 
parent classes in child-to-parent order.
-        * @throws Exception Thrown from property namer constructor.
-        */
-       public AnnotationBeanFilterBuilder(Class<T> annotatedClass, List<Bean> 
annotations) throws Exception {
-               super(annotatedClass);
-
-               for (Bean b : annotations) {
-
-                       if (! b.bpi().isEmpty())
-                               bpi(split(b.bpi()));
-
-                       if (! b.typeName().isEmpty())
-                               typeName(b.typeName());
-
-                       if (b.sort())
-                               sortProperties(true);
-
-                       if (b.fluentSetters())
-                               fluentSetters(true);
-
-                       if (! b.bpx().isEmpty())
-                               bpx(split(b.bpx()));
-
-                       if (! b.bpro().isEmpty())
-                               bpro(split(b.bpro()));
-
-                       if (! b.bpwo().isEmpty())
-                               bpwo(split(b.bpwo()));
-
-                       if (b.propertyNamer() != PropertyNamerDefault.class)
-                               propertyNamer(b.propertyNamer());
-
-                       if (b.interfaceClass() != Object.class)
-                               interfaceClass(b.interfaceClass());
-
-                       if (b.stopClass() != Object.class)
-                               stopClass(b.stopClass());
-
-                       if (b.dictionary().length > 0)
-                               dictionary(b.dictionary());
-
-                       if (b.interceptor() != BeanInterceptor.Default.class)
-                               interceptor(b.interceptor());
-               }
-       }
-}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilter.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilter.java
index f2e0d50..52082ad 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilter.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilter.java
@@ -1,223 +1,732 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.transform;
-
-import java.util.*;
-
-import static org.apache.juneau.internal.ClassUtils.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.annotation.*;
-
-/**
- * Parent class for all bean filters.
- *
- * <p>
- * Bean filters are used to control aspects of how beans are handled during 
serialization and parsing.
- *
- * <p>
- * Bean filters are created by {@link BeanFilterBuilder} which is the 
programmatic equivalent to the {@link Bean @Bean}
- * annotation.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc BeanFilters}
- * </ul>
- */
-public final class BeanFilter {
-
-       private final Class<?> beanClass;
-       private final Set<String> bpi, bpx, bpro, bpwo;
-       private final PropertyNamer propertyNamer;
-       private final Class<?> interfaceClass, stopClass;
-       private final boolean sortProperties, fluentSetters;
-       private final String typeName;
-       private final Class<?>[] beanDictionary;
-       @SuppressWarnings("rawtypes")
-       private final BeanInterceptor interceptor;
-
-       /**
-        * Constructor.
-        */
-       BeanFilter(BeanFilterBuilder<?> builder) {
-               this.beanClass = builder.beanClass;
-               this.typeName = builder.typeName;
-               this.bpi = new LinkedHashSet<>(builder.bpi);
-               this.bpx = new LinkedHashSet<>(builder.bpx);
-               this.bpro = new LinkedHashSet<>(builder.bpro);
-               this.bpwo = new LinkedHashSet<>(builder.bpwo);
-               this.interfaceClass = builder.interfaceClass;
-               this.stopClass = builder.stopClass;
-               this.sortProperties = builder.sortProperties;
-               this.fluentSetters = builder.fluentSetters;
-               this.propertyNamer = castOrCreate(PropertyNamer.class, 
builder.propertyNamer);
-               this.beanDictionary =
-                       builder.dictionary == null
-                       ? null
-                       : builder.dictionary.toArray(new 
Class<?>[builder.dictionary.size()]);
-               this.interceptor =
-                       builder.interceptor == null
-                       ? BeanInterceptor.DEFAULT
-                       : castOrCreate(BeanInterceptor.class, 
builder.interceptor);
-       }
-
-       /**
-        * Static creator.
-        *
-        * @param <T> The class being filtered.
-        * @param c The class being filtered.
-        * @return A new instance of BeanFilterBuilder.
-        */
-       public static <T> BeanFilterBuilder<T> create(Class<T> c) {
-               return new BeanFilterBuilder<>(c);
-       }
-
-       /**
-        * Returns the bean class that this filter applies to.
-        *
-        * @return The bean class that this filter applies to.
-        */
-       public Class<?> getBeanClass() {
-               return beanClass;
-       }
-
-       /**
-        * Returns the dictionary name associated with this bean.
-        *
-        * @return The dictionary name associated with this bean, or 
<jk>null</jk> if no name is defined.
-        */
-       public String getTypeName() {
-               return typeName;
-       }
-
-       /**
-        * Returns the bean dictionary defined on this bean.
-        *
-        * @return The bean dictionary defined on this bean, or <jk>null</jk> 
if no bean dictionary is defined.
-        */
-       public Class<?>[] getBeanDictionary() {
-               return beanDictionary;
-       }
-
-       /**
-        * Returns the set and order of names of properties associated with a 
bean class.
-        *
-        * @return
-        *      The names of the properties associated with a bean class, or 
and empty set if all bean properties should
-        *      be used.
-        */
-       public Set<String> getBpi() {
-               return bpi;
-       }
-
-       /**
-        * Returns the list of properties to ignore on a bean.
-        *
-        * @return The names of the properties to ignore on a bean, or an empty 
set to not ignore any properties.
-        */
-       public Set<String> getBpx() {
-               return bpx;
-       }
-
-       /**
-        * Returns the list of read-only properties on a bean.
-        *
-        * @return The names of the read-only properties on a bean, or an empty 
set to not have any read-only properties.
-        */
-       public Set<String> getBpro() {
-               return bpro;
-       }
-
-       /**
-        * Returns the list of write-only properties on a bean.
-        *
-        * @return The names of the write-only properties on a bean, or an 
empty set to not have any write-only properties.
-        */
-       public Set<String> getBpwo() {
-               return bpwo;
-       }
-
-       /**
-        * Returns <jk>true</jk> if the properties defined on this bean class 
should be ordered alphabetically.
-        *
-        * <p>
-        * This method is only used when the {@link #getBpi()} method returns 
<jk>null</jk>.
-        * Otherwise, the ordering of the properties in the returned value is 
used.
-        *
-        * @return <jk>true</jk> if bean properties should be sorted.
-        */
-       public boolean isSortProperties() {
-               return sortProperties;
-       }
-
-       /**
-        * Returns <jk>true</jk> if we should find fluent setters.
-        *
-        * @return <jk>true</jk> if fluent setters should be found.
-        */
-       public boolean isFluentSetters() {
-               return fluentSetters;
-       }
-
-       /**
-        * Returns the {@link PropertyNamer} associated with the bean to tailor 
the names of bean properties.
-        *
-        * @return The property namer class, or <jk>null</jk> if no property 
namer is associated with this bean property.
-        */
-       public PropertyNamer getPropertyNamer() {
-               return propertyNamer;
-       }
-
-       /**
-        * Returns the interface class associated with this class.
-        *
-        * @return The interface class associated with this class, or 
<jk>null</jk> if no interface class is associated.
-        */
-       public Class<?> getInterfaceClass() {
-               return interfaceClass;
-       }
-
-       /**
-        * Returns the stop class associated with this class.
-        *
-        * @return The stop class associated with this class, or <jk>null</jk> 
if no stop class is associated.
-        */
-       public Class<?> getStopClass() {
-               return stopClass;
-       }
-
-       /**
-        * Calls the {@link BeanInterceptor#readProperty(Object, String, 
Object)} method on the registered property filters.
-        *
-        * @param bean The bean from which the property was read.
-        * @param name The property name.
-        * @param value The value just extracted from calling the bean getter.
-        * @return The value to serialize.  Default is just to return the 
existing value.
-        */
-       @SuppressWarnings("unchecked")
-       public Object readProperty(Object bean, String name, Object value) {
-               return interceptor.readProperty(bean, name, value);
-       }
-
-       /**
-        * Calls the {@link BeanInterceptor#writeProperty(Object, String, 
Object)} method on the registered property filters.
-        *
-        * @param bean The bean from which the property was read.
-        * @param name The property name.
-        * @param value The value just parsed.
-        * @return The value to serialize.  Default is just to return the 
existing value.
-        */
-       @SuppressWarnings("unchecked")
-       public Object writeProperty(Object bean, String name, Object value) {
-               return interceptor.writeProperty(bean, name, value);
-       }
-}
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.beans.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.collections.*;
+import org.apache.juneau.reflect.*;
+
+/**
+ * Builder class for {@link UnmodifiableBeanFilter} objects.
+ *
+ * <p>
+ * This class is the programmatic equivalent to the {@link Bean @Bean} 
annotation.
+ *
+ * <p>
+ * The general approach to defining bean filters is to create subclasses from 
this class and call methods to
+ * set various attributes
+ * <p class='bcode w800'>
+ *     <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+ *
+ *             <jc>// Must provide a no-arg constructor!</jc>
+ *             <jk>public</jk> MyFilter() {
+ *
+ *                     <jc>// Call one or more configuration methods.</jc>
+ *                     bpi(<js>"foo,bar,baz"</js>);
+ *                     sortProperties();
+ *                     propertyNamer(PropertyNamerULC.<jk>class</jk>);
+ *             }
+ *     }
+ *
+ *     <jc>// Register it with a serializer or parser.</jc>
+ *     WriterSerializer s = JsonSerializer
+ *             .<jsm>create</jsm>()
+ *             .beanFilters(MyFilter.<jk>class</jk>)
+ *             .build();
+ * </p>
+ *
+ * <ul class='seealso'>
+ *     <li class='link'>{@doc BeanFilters}
+ * </ul>
+ *
+ * @param <T> The bean type that this filter applies to.
+ */
+public class BeanFilter<T> {
+
+       Class<?> beanClass;
+       String typeName;
+       ASet<String>
+               bpi = ASet.of(),
+               bpx = ASet.of(),
+               bpro = ASet.of(),
+               bpwo = ASet.of();
+       Class<?> interfaceClass, stopClass;
+       boolean sortProperties, fluentSetters;
+       Object propertyNamer;
+       List<Class<?>> dictionary;
+       Object interceptor;
+
+       /**
+        * Constructor.
+        *
+        * <p>
+        * Bean class is determined through reflection of the parameter type.
+        */
+       protected BeanFilter() {
+               beanClass = ClassInfo.of(this.getClass()).getParameterType(0, 
BeanFilter.class);
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param beanClass The bean class that this filter applies to.
+        */
+       protected BeanFilter(Class<?> beanClass) {
+               this.beanClass = beanClass;
+       }
+
+       /**
+        * Create a new instance of this bean filter.
+        *
+        * @param <T> The bean class being filtered.
+        * @param beanClass The bean class being filtered.
+        * @return A new {@link BeanFilter} object.
+        */
+       public static <T> BeanFilter<T> create(Class<T> beanClass) {
+               return new BeanFilter<>(beanClass);
+       }
+
+       /**
+        * Applies the information in the specified list of {@link Bean @Bean} 
annotations to this filter.
+        *
+        * @param annotations The annotations to apply.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> applyAnnotations(List<Bean> annotations) {
+
+               for (Bean b : annotations) {
+
+                       if (! b.bpi().isEmpty())
+                               bpi(split(b.bpi()));
+
+                       if (! b.typeName().isEmpty())
+                               typeName(b.typeName());
+
+                       if (b.sort())
+                               sortProperties(true);
+
+                       if (b.fluentSetters())
+                               fluentSetters(true);
+
+                       if (! b.bpx().isEmpty())
+                               bpx(split(b.bpx()));
+
+                       if (! b.bpro().isEmpty())
+                               bpro(split(b.bpro()));
+
+                       if (! b.bpwo().isEmpty())
+                               bpwo(split(b.bpwo()));
+
+                       if (b.propertyNamer() != PropertyNamerDefault.class)
+                               propertyNamer(b.propertyNamer());
+
+                       if (b.interfaceClass() != Object.class)
+                               interfaceClass(b.interfaceClass());
+
+                       if (b.stopClass() != Object.class)
+                               stopClass(b.stopClass());
+
+                       if (b.dictionary().length > 0)
+                               dictionary(b.dictionary());
+
+                       if (b.interceptor() != BeanInterceptor.Default.class)
+                               interceptor(b.interceptor());
+               }
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean dictionary type name.
+        *
+        * <p>
+        * Specifies the dictionary type name for this bean.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      typeName(<js>"mybean"</js>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer or parser.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Produces:  "{_type:'mybean', ...}"</jc>
+        *      String json = s.serialize(<jk>new</jk> MyBean());
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#typeName()}
+        * </ul>
+        *
+        * @param value The new value for this setting.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> typeName(String value) {
+               this.typeName = value;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean interface class.
+        *
+        * Identifies a class to be used as the interface class for this and 
all subclasses.
+        *
+        * <p>
+        * When specified, only the list of properties defined on the interface 
class will be used during serialization.
+        * <br>Additional properties on subclasses will be ignored.
+        *
+        * <p class='bcode w800'>
+        *      <jc>// Parent class</jc>
+        *      <jk>public abstract class</jk> A {
+        *              <jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
+        *      }
+        *
+        *      <jc>// Sub class</jc>
+        *      <jk>public class</jk> A1 <jk>extends</jk> A {
+        *              <jk>public</jk> String <jf>f1</jf> = <js>"f1"</js>;
+        *      }
+        *
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> AFilter <jk>extends</jk> 
BeanFilterBuilder&lt;A&gt; {
+        *              <jk>public</jk> AFilter() {
+        *                      interfaceClass(A.<jk>class</jk>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(AFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Use it.</jc>
+        *      A1 a1 = <jk>new</jk> A1();
+        *      String r = s.serialize(a1);
+        *      <jsm>assertEquals</jsm>(<js>"{f0:'f0'}"</js>, r);  <jc>// Note 
f1 is not serialized</jc>
+        * </p>
+        *
+        * <p>
+        * Note that this filter can be used on the parent class so that it 
filters to all child classes, or can be set
+        * individually on the child classes.
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#interfaceClass()}
+        * </ul>
+        *
+        * @param value The new value for this setting.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> interfaceClass(Class<?> value) {
+               this.interfaceClass = value;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean stop class.
+        *
+        * <p>
+        * Identifies a stop class for this class and all subclasses.
+        *
+        * <p>
+        * Identical in purpose to the stop class specified by {@link 
Introspector#getBeanInfo(Class, Class)}.
+        * <br>Any properties in the stop class or in its base classes will be 
ignored during analysis.
+        *
+        * <p>
+        * For example, in the following class hierarchy, instances of 
<c>C3</c> will include property <c>p3</c>,
+        * but not <c>p1</c> or <c>p2</c>.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jk>public class</jk> C1 {
+        *              <jk>public int</jk> getP1();
+        *      }
+        *
+        *      <jk>public class</jk> C2 <jk>extends</jk> C1 {
+        *              <jk>public int</jk> getP2();
+        *      }
+        *
+        *      <jk>public class</jk> C3 <jk>extends</jk> C2 {
+        *              <jk>public int</jk> getP3();
+        *      }
+        *
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> C3Filter <jk>extends</jk> 
BeanFilterBuilder&lt;C3&gt; {
+        *              <jk>public</jk> C3Filter() {
+        *                      stopClass(C2.<jk>class</jk>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(C3Filter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Serializes property 'p3', but NOT 'p1' or 'p2'.</jc>
+        *      String json = s.serialize(<jk>new</jk> C3());
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#stopClass()}
+        * </ul>
+        *
+        * @param value The new value for this setting.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> stopClass(Class<?> value) {
+               this.stopClass = value;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Sort bean properties.
+        *
+        * <p>
+        * When <jk>true</jk>, all bean properties will be serialized and 
access in alphabetical order.
+        * <br>Otherwise, the natural order of the bean properties is used 
which is dependent on the JVM vendor.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      sortProperties();
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Properties will be sorted alphabetically.</jc>
+        *      String json = s.serialize(<jk>new</jk> MyBean());
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#sort()}
+        *      <li class='jf'>{@link BeanContext#BEAN_sortProperties}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this property.
+        *      <br>The default is <jk>false</jk>.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> sortProperties(boolean value) {
+               this.sortProperties = value;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Sort bean properties.
+        *
+        * <p>
+        * Shortcut for calling <code>sortProperties(<jk>true</jk>)</code>.
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#sort()}
+        *      <li class='jf'>{@link BeanContext#BEAN_sortProperties}
+        * </ul>
+        *
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> sortProperties() {
+               this.sortProperties = true;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Find fluent setters.
+        *
+        * <p>
+        * When enabled, fluent setters are detected on beans.
+        *
+        * <p>
+        * Fluent setters must have the following attributes:
+        * <ul>
+        *      <li>Public.
+        *      <li>Not static.
+        *      <li>Take in one parameter.
+        *      <li>Return the bean itself.
+        * </ul>
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      fluentSetters();
+        *              }
+        *      }
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#fluentSetters()}
+        *      <li class='jf'>{@link BeanContext#BEAN_fluentSetters}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this property.
+        *      <br>The default is <jk>false</jk>.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> fluentSetters(boolean value) {
+               this.fluentSetters = value;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Find fluent setters.
+        *
+        * <p>
+        * Shortcut for calling <code>fluentSetters(<jk>true</jk>)</code>.
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#fluentSetters()}
+        *      <li class='jf'>{@link BeanContext#BEAN_fluentSetters}
+        * </ul>
+        *
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> fluentSetters() {
+               this.fluentSetters = true;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean property namer
+        *
+        * <p>
+        * The class to use for calculating bean property names.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      <jc>// Use Dashed-Lower-Case property 
names.</jc>
+        *                      <jc>// (e.g. "foo-bar-url" instead of 
"fooBarURL")</jc>
+        *                      propertyNamer(PropertyNamerDLC.<jk>class</jk>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer or parser.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Properties names will be Dashed-Lower-Case.</jc>
+        *      String json = s.serialize(<jk>new</jk> MyBean());
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#propertyNamer()}
+        *      <li class='jf'>{@link BeanContext#BEAN_propertyNamer}
+        *      <li class='jc'>{@link PropertyNamer}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this setting.
+        *      <br>The default is {@link PropertyNamerDefault}.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> propertyNamer(Class<? extends PropertyNamer> 
value) {
+               this.propertyNamer = value;
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean property includes.
+        *
+        * <p>
+        * Specifies the set and order of names of properties associated with 
the bean class.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      bpi(<js>"foo,bar,baz"</js>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Only serializes the properties 'foo', 'bar', and 
'baz'.</jc>
+        *      String json = s.serialize(<jk>new</jk> MyBean());
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#bpi()}
+        *      <li class='jm'>{@link BeanContextBuilder#bpi(Class, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpi(String, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpi(Map)}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this setting.
+        *      <br>Values can contain comma-delimited list of property names.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> bpi(String...value) {
+               this.bpi = ASet.of();
+               for (String v : value)
+                       bpi.a(split(v));
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean property excludes.
+        *
+        * <p>
+        * Specifies properties to exclude from the bean class.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      bpx(<js>"foo,bar"</js>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Serializes all properties except for 'foo' and 
'bar'.</jc>
+        *      String json = s.serialize(<jk>new</jk> MyBean());
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#bpx()}
+        *      <li class='jm'>{@link BeanContextBuilder#bpx(Class, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpx(String, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpx(Map)}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this setting.
+        *      <br>Values can contain comma-delimited list of property names.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> bpx(String...value) {
+               this.bpx = ASet.of();
+               for (String v : value)
+                       bpx.a(split(v));
+               return this;
+       }
+
+       /**
+        * Configuration property:  Read-only bean properties.
+        *
+        * <p>
+        * Specifies one or more properties on a bean that are read-only 
despite having valid getters.
+        * Serializers will serialize such properties as usual, but parsers 
will silently ignore them.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      bpro(<js>"foo,bar"</js>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a parser.</jc>
+        *  ReaderParser p = JsonParser
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Parsers all properties except for 'foo' and 'bar'.</jc>
+        *      MyBean b = p.parse(<js>"..."</js>, MyBean.<jk>class</jk>);
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#bpro()}
+        *      <li class='ja'>{@link Beanp#ro()}
+        *      <li class='jm'>{@link BeanContextBuilder#bpro(Class, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpro(String, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpro(Map)}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this setting.
+        *      <br>Values can contain comma-delimited list of property names.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> bpro(String...value) {
+               this.bpro = ASet.of();
+               for (String v : value)
+                       bpro.a(split(v));
+               return this;
+       }
+
+       /**
+        * Configuration property:  Write-only bean properties.
+        *
+        * <p>
+        * Specifies one or more properties on a bean that are write-only 
despite having valid setters.
+        * Parsers will parse such properties as usual, but serializers will 
silently ignore them.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      bpwo(<js>"foo,bar"</js>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer.</jc>
+        *  WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Serializes all properties except for 'foo' and 
'bar'.</jc>
+        *      String json = s.serialize(<jk>new</jk> MyBean());
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#bpwo()}
+        *      <li class='ja'>{@link Beanp#wo()}
+        *      <li class='jm'>{@link BeanContextBuilder#bpwo(Class, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpwo(String, String)}
+        *      <li class='jm'>{@link BeanContextBuilder#bpwo(Map)}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this setting.
+        *      <br>Values can contain comma-delimited list of property names.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> bpwo(String...value) {
+               this.bpwo = ASet.of();
+               for (String v : value)
+                       bpwo.a(split(v));
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean dictionary.
+        *
+        * <p>
+        * Adds to the list of classes that make up the bean dictionary for 
this bean.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      <jc>// Our bean contains generic collections of 
Foo and Bar objects.</jc>
+        *                      beanDictionary(Foo.<jk>class</jk>, 
Bar.<jk>class</jk>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a parser.</jc>
+        *      ReaderParser p = JsonParser
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        *
+        *      <jc>// Instantiate our bean.</jc>
+        *      MyBean myBean = p.parse(json);
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#dictionary()}
+        *      <li class='jf'>{@link BeanContext#BEAN_beanDictionary}
+        * </ul>
+        *
+        * @param values
+        *      The values to add to this property.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> dictionary(Class<?>...values) {
+               if (dictionary == null)
+                       dictionary = Arrays.asList(values);
+               else for (Class<?> cc : values)
+                       dictionary.add(cc);
+               return this;
+       }
+
+       /**
+        * Configuration property:  Bean interceptor.
+        *
+        * <p>
+        * The interceptor to use for intercepting and altering getter and 
setter calls.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define our filter.</jc>
+        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
+        *              <jk>public</jk> MyFilter() {
+        *                      <jc>// Our bean contains generic collections of 
Foo and Bar objects.</jc>
+        *                      interceptor(AddressInterceptor.<jk>class</jk>);
+        *              }
+        *      }
+        *
+        *      <jc>// Register it with a serializer or parser.</jc>
+        *      WriterSerializer s = JsonSerializer
+        *              .<jsm>create</jsm>()
+        *              .beanFilters(MyFilter.<jk>class</jk>)
+        *              .build();
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='ja'>{@link Bean#interceptor()}
+        *      <li class='jc'>{@link BeanInterceptor}
+        * </ul>
+        *
+        * @param value
+        *      The new value for this setting.
+        *      <br>The default value is {@link BeanInterceptor}.
+        * @return This object (for method chaining).
+        */
+       public BeanFilter<T> interceptor(Class<?> value) {
+               this.interceptor = value;
+               return this;
+       }
+
+       /**
+        * Creates a {@link UnmodifiableBeanFilter} with settings in this 
builder class.
+        *
+        * @return A new {@link UnmodifiableBeanFilter} instance.
+        */
+       public UnmodifiableBeanFilter build() {
+               return new UnmodifiableBeanFilter(this);
+       }
+}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilterBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilterBuilder.java
deleted file mode 100644
index f78cd50..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilterBuilder.java
+++ /dev/null
@@ -1,672 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.transform;
-
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.beans.*;
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.collections.*;
-import org.apache.juneau.reflect.*;
-
-/**
- * Builder class for {@link BeanFilter} objects.
- *
- * <p>
- * This class is the programmatic equivalent to the {@link Bean @Bean} 
annotation.
- *
- * <p>
- * The general approach to defining bean filters is to create subclasses from 
this class and call methods to
- * set various attributes
- * <p class='bcode w800'>
- *     <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
- *
- *             <jc>// Must provide a no-arg constructor!</jc>
- *             <jk>public</jk> MyFilter() {
- *
- *                     <jc>// Call one or more configuration methods.</jc>
- *                     bpi(<js>"foo,bar,baz"</js>);
- *                     sortProperties();
- *                     propertyNamer(PropertyNamerULC.<jk>class</jk>);
- *             }
- *     }
- *
- *     <jc>// Register it with a serializer or parser.</jc>
- *     WriterSerializer s = JsonSerializer
- *             .<jsm>create</jsm>()
- *             .beanFilters(MyFilter.<jk>class</jk>)
- *             .build();
- * </p>
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc BeanFilters}
- * </ul>
- *
- * @param <T> The bean type that this filter applies to.
- */
-public class BeanFilterBuilder<T> {
-
-       Class<?> beanClass;
-       String typeName;
-       ASet<String>
-               bpi = ASet.of(),
-               bpx = ASet.of(),
-               bpro = ASet.of(),
-               bpwo = ASet.of();
-       Class<?> interfaceClass, stopClass;
-       boolean sortProperties, fluentSetters;
-       Object propertyNamer;
-       List<Class<?>> dictionary;
-       Object interceptor;
-
-       /**
-        * Constructor.
-        *
-        * <p>
-        * Bean class is determined through reflection of the parameter type.
-        */
-       protected BeanFilterBuilder() {
-               beanClass = ClassInfo.of(this.getClass()).getParameterType(0, 
BeanFilterBuilder.class);
-       }
-
-       /**
-        * Constructor.
-        *
-        * @param beanClass The bean class that this filter applies to.
-        */
-       protected BeanFilterBuilder(Class<?> beanClass) {
-               this.beanClass = beanClass;
-       }
-
-       /**
-        * Configuration property:  Bean dictionary type name.
-        *
-        * <p>
-        * Specifies the dictionary type name for this bean.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      typeName(<js>"mybean"</js>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer or parser.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Produces:  "{_type:'mybean', ...}"</jc>
-        *      String json = s.serialize(<jk>new</jk> MyBean());
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#typeName()}
-        * </ul>
-        *
-        * @param value The new value for this setting.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> typeName(String value) {
-               this.typeName = value;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Bean interface class.
-        *
-        * Identifies a class to be used as the interface class for this and 
all subclasses.
-        *
-        * <p>
-        * When specified, only the list of properties defined on the interface 
class will be used during serialization.
-        * <br>Additional properties on subclasses will be ignored.
-        *
-        * <p class='bcode w800'>
-        *      <jc>// Parent class</jc>
-        *      <jk>public abstract class</jk> A {
-        *              <jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
-        *      }
-        *
-        *      <jc>// Sub class</jc>
-        *      <jk>public class</jk> A1 <jk>extends</jk> A {
-        *              <jk>public</jk> String <jf>f1</jf> = <js>"f1"</js>;
-        *      }
-        *
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> AFilter <jk>extends</jk> 
BeanFilterBuilder&lt;A&gt; {
-        *              <jk>public</jk> AFilter() {
-        *                      interfaceClass(A.<jk>class</jk>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(AFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Use it.</jc>
-        *      A1 a1 = <jk>new</jk> A1();
-        *      String r = s.serialize(a1);
-        *      <jsm>assertEquals</jsm>(<js>"{f0:'f0'}"</js>, r);  <jc>// Note 
f1 is not serialized</jc>
-        * </p>
-        *
-        * <p>
-        * Note that this filter can be used on the parent class so that it 
filters to all child classes, or can be set
-        * individually on the child classes.
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#interfaceClass()}
-        * </ul>
-        *
-        * @param value The new value for this setting.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> interfaceClass(Class<?> value) {
-               this.interfaceClass = value;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Bean stop class.
-        *
-        * <p>
-        * Identifies a stop class for this class and all subclasses.
-        *
-        * <p>
-        * Identical in purpose to the stop class specified by {@link 
Introspector#getBeanInfo(Class, Class)}.
-        * <br>Any properties in the stop class or in its base classes will be 
ignored during analysis.
-        *
-        * <p>
-        * For example, in the following class hierarchy, instances of 
<c>C3</c> will include property <c>p3</c>,
-        * but not <c>p1</c> or <c>p2</c>.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jk>public class</jk> C1 {
-        *              <jk>public int</jk> getP1();
-        *      }
-        *
-        *      <jk>public class</jk> C2 <jk>extends</jk> C1 {
-        *              <jk>public int</jk> getP2();
-        *      }
-        *
-        *      <jk>public class</jk> C3 <jk>extends</jk> C2 {
-        *              <jk>public int</jk> getP3();
-        *      }
-        *
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> C3Filter <jk>extends</jk> 
BeanFilterBuilder&lt;C3&gt; {
-        *              <jk>public</jk> C3Filter() {
-        *                      stopClass(C2.<jk>class</jk>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(C3Filter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Serializes property 'p3', but NOT 'p1' or 'p2'.</jc>
-        *      String json = s.serialize(<jk>new</jk> C3());
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#stopClass()}
-        * </ul>
-        *
-        * @param value The new value for this setting.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> stopClass(Class<?> value) {
-               this.stopClass = value;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Sort bean properties.
-        *
-        * <p>
-        * When <jk>true</jk>, all bean properties will be serialized and 
access in alphabetical order.
-        * <br>Otherwise, the natural order of the bean properties is used 
which is dependent on the JVM vendor.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      sortProperties();
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Properties will be sorted alphabetically.</jc>
-        *      String json = s.serialize(<jk>new</jk> MyBean());
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#sort()}
-        *      <li class='jf'>{@link BeanContext#BEAN_sortProperties}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this property.
-        *      <br>The default is <jk>false</jk>.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> sortProperties(boolean value) {
-               this.sortProperties = value;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Sort bean properties.
-        *
-        * <p>
-        * Shortcut for calling <code>sortProperties(<jk>true</jk>)</code>.
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#sort()}
-        *      <li class='jf'>{@link BeanContext#BEAN_sortProperties}
-        * </ul>
-        *
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> sortProperties() {
-               this.sortProperties = true;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Find fluent setters.
-        *
-        * <p>
-        * When enabled, fluent setters are detected on beans.
-        *
-        * <p>
-        * Fluent setters must have the following attributes:
-        * <ul>
-        *      <li>Public.
-        *      <li>Not static.
-        *      <li>Take in one parameter.
-        *      <li>Return the bean itself.
-        * </ul>
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      fluentSetters();
-        *              }
-        *      }
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#fluentSetters()}
-        *      <li class='jf'>{@link BeanContext#BEAN_fluentSetters}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this property.
-        *      <br>The default is <jk>false</jk>.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> fluentSetters(boolean value) {
-               this.fluentSetters = value;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Find fluent setters.
-        *
-        * <p>
-        * Shortcut for calling <code>fluentSetters(<jk>true</jk>)</code>.
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#fluentSetters()}
-        *      <li class='jf'>{@link BeanContext#BEAN_fluentSetters}
-        * </ul>
-        *
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> fluentSetters() {
-               this.fluentSetters = true;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Bean property namer
-        *
-        * <p>
-        * The class to use for calculating bean property names.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      <jc>// Use Dashed-Lower-Case property 
names.</jc>
-        *                      <jc>// (e.g. "foo-bar-url" instead of 
"fooBarURL")</jc>
-        *                      propertyNamer(PropertyNamerDLC.<jk>class</jk>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer or parser.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Properties names will be Dashed-Lower-Case.</jc>
-        *      String json = s.serialize(<jk>new</jk> MyBean());
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#propertyNamer()}
-        *      <li class='jf'>{@link BeanContext#BEAN_propertyNamer}
-        *      <li class='jc'>{@link PropertyNamer}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>The default is {@link PropertyNamerDefault}.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> propertyNamer(Class<? extends 
PropertyNamer> value) {
-               this.propertyNamer = value;
-               return this;
-       }
-
-       /**
-        * Configuration property:  Bean property includes.
-        *
-        * <p>
-        * Specifies the set and order of names of properties associated with 
the bean class.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      bpi(<js>"foo,bar,baz"</js>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Only serializes the properties 'foo', 'bar', and 
'baz'.</jc>
-        *      String json = s.serialize(<jk>new</jk> MyBean());
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#bpi()}
-        *      <li class='jm'>{@link BeanContextBuilder#bpi(Class, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpi(String, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpi(Map)}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>Values can contain comma-delimited list of property names.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> bpi(String...value) {
-               this.bpi = ASet.of();
-               for (String v : value)
-                       bpi.a(split(v));
-               return this;
-       }
-
-       /**
-        * Configuration property:  Bean property excludes.
-        *
-        * <p>
-        * Specifies properties to exclude from the bean class.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      bpx(<js>"foo,bar"</js>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Serializes all properties except for 'foo' and 
'bar'.</jc>
-        *      String json = s.serialize(<jk>new</jk> MyBean());
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#bpx()}
-        *      <li class='jm'>{@link BeanContextBuilder#bpx(Class, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpx(String, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpx(Map)}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>Values can contain comma-delimited list of property names.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> bpx(String...value) {
-               this.bpx = ASet.of();
-               for (String v : value)
-                       bpx.a(split(v));
-               return this;
-       }
-
-       /**
-        * Configuration property:  Read-only bean properties.
-        *
-        * <p>
-        * Specifies one or more properties on a bean that are read-only 
despite having valid getters.
-        * Serializers will serialize such properties as usual, but parsers 
will silently ignore them.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      bpro(<js>"foo,bar"</js>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a parser.</jc>
-        *  ReaderParser p = JsonParser
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Parsers all properties except for 'foo' and 'bar'.</jc>
-        *      MyBean b = p.parse(<js>"..."</js>, MyBean.<jk>class</jk>);
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#bpro()}
-        *      <li class='ja'>{@link Beanp#ro()}
-        *      <li class='jm'>{@link BeanContextBuilder#bpro(Class, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpro(String, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpro(Map)}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>Values can contain comma-delimited list of property names.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> bpro(String...value) {
-               this.bpro = ASet.of();
-               for (String v : value)
-                       bpro.a(split(v));
-               return this;
-       }
-
-       /**
-        * Configuration property:  Write-only bean properties.
-        *
-        * <p>
-        * Specifies one or more properties on a bean that are write-only 
despite having valid setters.
-        * Parsers will parse such properties as usual, but serializers will 
silently ignore them.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      bpwo(<js>"foo,bar"</js>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer.</jc>
-        *  WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Serializes all properties except for 'foo' and 
'bar'.</jc>
-        *      String json = s.serialize(<jk>new</jk> MyBean());
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#bpwo()}
-        *      <li class='ja'>{@link Beanp#wo()}
-        *      <li class='jm'>{@link BeanContextBuilder#bpwo(Class, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpwo(String, String)}
-        *      <li class='jm'>{@link BeanContextBuilder#bpwo(Map)}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>Values can contain comma-delimited list of property names.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> bpwo(String...value) {
-               this.bpwo = ASet.of();
-               for (String v : value)
-                       bpwo.a(split(v));
-               return this;
-       }
-
-       /**
-        * Configuration property:  Bean dictionary.
-        *
-        * <p>
-        * Adds to the list of classes that make up the bean dictionary for 
this bean.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      <jc>// Our bean contains generic collections of 
Foo and Bar objects.</jc>
-        *                      beanDictionary(Foo.<jk>class</jk>, 
Bar.<jk>class</jk>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a parser.</jc>
-        *      ReaderParser p = JsonParser
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        *
-        *      <jc>// Instantiate our bean.</jc>
-        *      MyBean myBean = p.parse(json);
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#dictionary()}
-        *      <li class='jf'>{@link BeanContext#BEAN_beanDictionary}
-        * </ul>
-        *
-        * @param values
-        *      The values to add to this property.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> dictionary(Class<?>...values) {
-               if (dictionary == null)
-                       dictionary = Arrays.asList(values);
-               else for (Class<?> cc : values)
-                       dictionary.add(cc);
-               return this;
-       }
-
-       /**
-        * Configuration property:  Bean interceptor.
-        *
-        * <p>
-        * The interceptor to use for intercepting and altering getter and 
setter calls.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Define our filter.</jc>
-        *      <jk>public class</jk> MyFilter <jk>extends</jk> 
BeanFilterBuilder&lt;MyBean&gt; {
-        *              <jk>public</jk> MyFilter() {
-        *                      <jc>// Our bean contains generic collections of 
Foo and Bar objects.</jc>
-        *                      interceptor(AddressInterceptor.<jk>class</jk>);
-        *              }
-        *      }
-        *
-        *      <jc>// Register it with a serializer or parser.</jc>
-        *      WriterSerializer s = JsonSerializer
-        *              .<jsm>create</jsm>()
-        *              .beanFilters(MyFilter.<jk>class</jk>)
-        *              .build();
-        * </p>
-        *
-        * <ul class='seealso'>
-        *      <li class='ja'>{@link Bean#interceptor()}
-        *      <li class='jc'>{@link BeanInterceptor}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>The default value is {@link BeanInterceptor}.
-        * @return This object (for method chaining).
-        */
-       public BeanFilterBuilder<T> interceptor(Class<?> value) {
-               this.interceptor = value;
-               return this;
-       }
-
-       /**
-        * Creates a {@link BeanFilter} with settings in this builder class.
-        *
-        * @return A new {@link BeanFilter} instance.
-        */
-       public BeanFilter build() {
-               return new BeanFilter(this);
-       }
-}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/InterfaceBeanFilterBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/InterfaceBeanFilterBuilder.java
deleted file mode 100644
index 2f436bc..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/InterfaceBeanFilterBuilder.java
+++ /dev/null
@@ -1,99 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.transform;
-
-import static org.apache.juneau.internal.StringUtils.*;
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.reflect.*;
-
-/**
- * Simple bean filter that simply identifies a class to be used as an 
interface class for all child classes.
- *
- * <p>
- * These objects are created when you pass in non-<c>BeanFilterBuilder</c> 
classes to
- * {@link BeanContextBuilder#interfaceClass(Class, Class)}, and are equivalent 
to adding a
- * <code><ja>@Bean</ja>(interfaceClass=Foo.<jk>class</jk>)</code> annotation 
on the <c>Foo</c> class.
- *
- * @param <T> The interface class.
- */
-public class InterfaceBeanFilterBuilder<T> extends BeanFilterBuilder<T> {
-
-       /**
-        * Constructor.
-        *
-        * <p>
-        * Interface class is determined through reflection.
-        */
-       protected InterfaceBeanFilterBuilder() {
-               init(beanClass, BeanContext.DEFAULT);
-       }
-
-       /**
-        * Constructor.
-        *
-        * @param interfaceClass The class to use as an interface on all child 
classes.
-        * @param bc The bean context to use for looking up annotations.
-        */
-       public InterfaceBeanFilterBuilder(Class<T> interfaceClass, BeanContext 
bc) {
-               super(interfaceClass);
-               init(interfaceClass, bc);
-       }
-
-       private void init(Class<?> interfaceClass, BeanContext bc) {
-               interfaceClass(interfaceClass);
-               List<Bean> annotations = 
ClassInfo.of(interfaceClass).getAnnotations(Bean.class, bc);
-
-               for (Bean b : annotations) {
-
-                       if (! b.bpi().isEmpty())
-                               bpi(split(b.bpi()));
-
-                       if (! b.bpx().isEmpty())
-                               bpx(split(b.bpx()));
-
-                       if (! b.bpro().isEmpty())
-                               bpro(split(b.bpro()));
-
-                       if (! b.bpwo().isEmpty())
-                               bpwo(split(b.bpwo()));
-
-                       if (! b.typeName().isEmpty())
-                               typeName(b.typeName());
-
-                       if (b.sort())
-                               sortProperties(true);
-
-                       if (b.fluentSetters())
-                               fluentSetters(true);
-
-                       try {
-                               if (b.propertyNamer() != 
PropertyNamerDefault.class)
-                                       propertyNamer(b.propertyNamer());
-                       } catch (Exception e) {
-                               throw new RuntimeException(e);
-                       }
-
-                       if (b.interfaceClass() != Object.class)
-                               interfaceClass(b.interfaceClass());
-
-                       if (b.stopClass() != Object.class)
-                               stopClass(b.stopClass());
-
-                       if (b.dictionary().length > 0)
-                               dictionary(b.dictionary());
-               }
-       }
-}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilter.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/UnmodifiableBeanFilter.java
similarity index 93%
copy from 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilter.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/UnmodifiableBeanFilter.java
index f2e0d50..ea8825d 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/BeanFilter.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/UnmodifiableBeanFilter.java
@@ -26,14 +26,14 @@ import org.apache.juneau.annotation.*;
  * Bean filters are used to control aspects of how beans are handled during 
serialization and parsing.
  *
  * <p>
- * Bean filters are created by {@link BeanFilterBuilder} which is the 
programmatic equivalent to the {@link Bean @Bean}
+ * Bean filters are created by {@link BeanFilter} which is the programmatic 
equivalent to the {@link Bean @Bean}
  * annotation.
  *
  * <ul class='seealso'>
  *     <li class='link'>{@doc BeanFilters}
  * </ul>
  */
-public final class BeanFilter {
+public final class UnmodifiableBeanFilter {
 
        private final Class<?> beanClass;
        private final Set<String> bpi, bpx, bpro, bpwo;
@@ -48,7 +48,7 @@ public final class BeanFilter {
        /**
         * Constructor.
         */
-       BeanFilter(BeanFilterBuilder<?> builder) {
+       UnmodifiableBeanFilter(BeanFilter<?> builder) {
                this.beanClass = builder.beanClass;
                this.typeName = builder.typeName;
                this.bpi = new LinkedHashSet<>(builder.bpi);
@@ -77,8 +77,8 @@ public final class BeanFilter {
         * @param c The class being filtered.
         * @return A new instance of BeanFilterBuilder.
         */
-       public static <T> BeanFilterBuilder<T> create(Class<T> c) {
-               return new BeanFilterBuilder<>(c);
+       public static <T> BeanFilter<T> create(Class<T> c) {
+               return new BeanFilter<>(c);
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/JuneauProvider.java
 
b/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/JuneauProvider.java
index 8c62363..77b6e71 100644
--- 
a/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/JuneauProvider.java
+++ 
b/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/JuneauProvider.java
@@ -46,8 +46,8 @@ public @interface JuneauProvider {
         * These filters are applied to all serializers and parsers being used 
by the provider.
         *
         * <p>
-        * If the specified class is an instance of {@link BeanFilterBuilder}, 
then a filter built from that builder is added.
-        * Any other classes are wrapped in a {@link 
InterfaceBeanFilterBuilder} to indicate that subclasses should
+        * If the specified class is an instance of {@link BeanFilter}, then a 
filter built from that builder is added.
+        * Any other classes are wrapped in a {@link BeanFilter} with {@link 
BeanFilter#interfaceClass(Class)} to indicate that subclasses should
         * be treated as the specified class type.
         */
        Class<?>[] beanFilters() default {};

Reply via email to