You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2020/10/15 17:56:36 UTC
[juneau] branch master updated: Simplify BeanConfig APIs
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 <ja...@salesforce.com>
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<MyBean> {
+ *
+ * <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<MyBean> {
+ * <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<A> {
+ * <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<C3> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
+ * <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<MyBean> {
- *
- * <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<MyBean> {
- * <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<A> {
- * <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<C3> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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<MyBean> {
- * <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 {};