JUNEAU-155 Split bpi/bpx into serializer and parser configuration
properties.
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 4bf8b23..ee506b4 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
@@ -120,9 +120,9 @@
 		beansRequireSomeProperties="$X{true}",
 		beanTypePropertyName="$X{foo}",
 		bpiMap=@CS(k=A1.class,v="$X{foo}"),
-		bpxMap=@CS(k=A1.class,v="$X{foo}"),
-		bproMap=@CS(k=A1.class,v="$X{foo}"),
-		bpwoMap=@CS(k=A1.class,v="$X{foo}"),
+		bpxMap=@CS(k=A1.class,v="$X{bar}"),
+		bproMap=@CS(k=A1.class,v="$X{baz}"),
+		bpwoMap=@CS(k=A1.class,v="$X{qux}"),
 		debug="$X{true}",
 		detectRecursions="$X{true}",
 		examples="$X{A1}: {foo:1}",
@@ -174,10 +174,10 @@
 		check("true", bc.isBeansRequireSettersForGetters());
 		check("true", bc.isBeansRequireSomeProperties());
 		check("foo", bc.getBeanTypePropertyName());
-		check("org.apache.juneau.BeanConfigAnnotationTest$A1=foo", bc.getBpi());
-		check("org.apache.juneau.BeanConfigAnnotationTest$A1=foo", bc.getBpx());
-		check("org.apache.juneau.BeanConfigAnnotationTest$A1=foo", bc.getBpro());
-		check("org.apache.juneau.BeanConfigAnnotationTest$A1=foo", bc.getBpwo());
+		check("org.apache.juneau.BeanConfigAnnotationTest$A1=[foo]", bc.getBpi());
+		check("org.apache.juneau.BeanConfigAnnotationTest$A1=[bar]", bc.getBpx());
+		check("org.apache.juneau.BeanConfigAnnotationTest$A1=[baz]", bc.getBpro());
+		check("org.apache.juneau.BeanConfigAnnotationTest$A1=[qux]", bc.getBpwo());
 		check("true", bc.isDebug());
 		check("true", bc.isDetectRecursions());
 		check("A1={foo:1}", bc.getExamples());
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 5034982..bbd653d 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
@@ -1962,7 +1962,7 @@
 	private final Locale locale;
 	private final TimeZone timeZone;
 	private final MediaType mediaType;
-	private final Map<String,String[]> bpi, bpx, bpro, bpwo;
+	private final Map<String,Set<String>> bpi, bpx, bpro, bpwo;
 	private final PropertyNamer propertyNamer;
 	private final String beanTypePropertyName;
 	private final int beanHashCode;
@@ -2062,24 +2062,24 @@
 			icm.put(e.getKey(), ClassInfo.of(e.getValue()));
 		implClasses = unmodifiableMap(icm);
 
-		Map<String,String[]> m2 = new HashMap<>();
+		Map<String,Set<String>> m2 = new HashMap<>();
 		for (Map.Entry<String,String> e : getMapProperty(BEAN_bpi, String.class).entrySet())
-			m2.put(e.getKey(), StringUtils.split(e.getValue()));
+			m2.put(e.getKey(), newUnmodifiableLinkedHashSet(split(e.getValue())));
 		bpi = unmodifiableMap(m2);
 
 		m2 = new HashMap<>();
 		for (Map.Entry<String,String> e : getMapProperty(BEAN_bpx, String.class).entrySet())
-			m2.put(e.getKey(), StringUtils.split(e.getValue()));
+			m2.put(e.getKey(), newUnmodifiableLinkedHashSet(split(e.getValue())));
 		bpx = unmodifiableMap(m2);
 
 		m2 = new HashMap<>();
 		for (Map.Entry<String,String> e : getMapProperty(BEAN_bpro, String.class).entrySet())
-			m2.put(e.getKey(), StringUtils.split(e.getValue()));
+			m2.put(e.getKey(), newUnmodifiableLinkedHashSet(split(e.getValue())));
 		bpro = unmodifiableMap(m2);
 
 		m2 = new HashMap<>();
 		for (Map.Entry<String,String> e : getMapProperty(BEAN_bpwo, String.class).entrySet())
-			m2.put(e.getKey(), StringUtils.split(e.getValue()));
+			m2.put(e.getKey(), newUnmodifiableLinkedHashSet(split(e.getValue())));
 		bpwo = unmodifiableMap(m2);
 
 		locale = getInstanceProperty(BEAN_locale, Locale.class, Locale.getDefault());
@@ -2973,7 +2973,7 @@
 	 * @return
 	 * 	Include properties keyed by class name.
 	 */
-	protected final Map<String,String[]> getBpi() {
+	protected final Map<String,Set<String>> getBpi() {
 		return bpi;
 	}
 
@@ -2981,20 +2981,22 @@
 	 * Returns the {@link #BEAN_bpi} setting for the specified class.
 	 *
 	 * @param c The class.
-	 * @return The properties to include for the specified class, or <jk>null</jk> if it's not defined for the class.
+	 * @return The properties to include for the specified class, or an empty set if it's not defined for the class.
 	 */
-	protected String[] getBpi(Class<?> c) {
+	protected Set<String> getBpi(Class<?> c) {
 		if (bpi.isEmpty())
-			return null;
+			return emptySet();
 		ClassInfo ci = ClassInfo.of(c);
 		for (ClassInfo c2 : ci.getAllParents()) {
 			for (String n : c2.getNames()) {
-				String[] s = bpi.get(n);
+				Set<String> s = bpi.get(n);
 				if (s != null)
 					return s;
 			}
 		}
-		return bpi.get("*");
+		if (bpi.containsKey("*"))
+			return bpi.get("*");
+		return emptySet();
 	}
 
 	/**
@@ -3004,7 +3006,7 @@
 	 * @return
 	 * 	The list of property names to exclude keyed by class name.
 	 */
-	protected final Map<String,String[]> getBpx() {
+	protected final Map<String,Set<String>> getBpx() {
 		return bpx;
 	}
 
@@ -3012,56 +3014,62 @@
 	 * Returns the {@link #BEAN_bpx} setting for the specified class.
 	 *
 	 * @param c The class.
-	 * @return The properties to exclude for the specified class, or <jk>null</jk> if it's not defined for the class.
+	 * @return The properties to exclude for the specified class, or an empty set if it's not defined for the class.
 	 */
-	protected String[] getBpx(Class<?> c) {
+	protected Set<String> getBpx(Class<?> c) {
 		if (bpx.isEmpty())
-			return null;
+			return emptySet();
 		ClassInfo ci = ClassInfo.of(c);
 		for (ClassInfo c2 : ci.getAllParents()) {
 			for (String n : c2.getNames()) {
-				String[] s = bpx.get(n);
+				Set<String> s = bpx.get(n);
 				if (s != null)
 					return s;
 			}
 		}
-		return bpx.get("*");
+		if (bpx.containsKey("*"))
+			return bpx.get("*");
+		return emptySet();
 	}
 
-	protected final Map<String,String[]> getBpro() {
+	protected final Map<String,Set<String>> getBpro() {
 		return bpro;
 	}
 
-	protected String[] getBpro(Class<?> c) {
+	protected Set<String> getBpro(Class<?> c) {
 		if (bpro.isEmpty())
-			return null;
+			return emptySet();
 		ClassInfo ci = ClassInfo.of(c);
 		for (ClassInfo c2 : ci.getAllParents()) {
 			for (String n : c2.getNames()) {
-				String[] s = bpro.get(n);
+				Set<String> s = bpro.get(n);
 				if (s != null)
 					return s;
 			}
 		}
-		return bpro.get("*");
+		if (bpro.containsKey("*"))
+			return bpro.get("*");
+		return emptySet();
 	}
 
-	protected final Map<String,String[]> getBpwo() {
+	protected final Map<String,Set<String>> getBpwo() {
 		return bpwo;
 	}
 
-	protected String[] getBpwo(Class<?> c) {
+	protected Set<String> getBpwo(Class<?> c) {
 		if (bpwo.isEmpty())
-			return null;
+			return emptySet();
 		ClassInfo ci = ClassInfo.of(c);
 		for (ClassInfo c2 : ci.getAllParents()) {
 			for (String n : c2.getNames()) {
-				String[] s = bpwo.get(n);
+				Set<String> s = bpwo.get(n);
 				if (s != null)
 					return s;
 			}
 		}
-		return bpwo.get("*");
+		if (bpwo.containsKey("*"))
+			return bpwo.get("*");
+		return emptySet();
 	}
 
 	/**
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 ccf973e..a00ca80 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
@@ -255,35 +255,31 @@
 

 				// Explicitly defined property names in @Bean annotation.

 				Set<String> fixedBeanProps = new LinkedHashSet<>();

-				String[] bpi = ctx.getBpi(c);

-				String[] bpx = ctx.getBpx(c);

-				Set<String> bpro = ctx.getBpro(c) == null ? newHashSet() : newHashSet(ctx.getBpro(c));

-				Set<String> bpwo = ctx.getBpwo(c) == null ? newHashSet() : newHashSet(ctx.getBpwo(c));

+				Set<String> bpi = new LinkedHashSet<>(ctx.getBpi(c));

+				Set<String> bpx = new LinkedHashSet<>(ctx.getBpx(c));

+				Set<String> bpro = new LinkedHashSet<>(ctx.getBpro(c));

+				Set<String> bpwo = new LinkedHashSet<>(ctx.getBpwo(c));

 

 				Set<String> filterProps = new HashSet<>();  // Names of properties defined in @Bean(properties)

 

 				if (beanFilter != null) {

 

-					if (beanFilter.getBpi() != null)

-						filterProps.addAll(Arrays.asList(beanFilter.getBpi()));

+					Set<String> bfbpi = beanFilter.getBpi();

+

+					filterProps.addAll(bfbpi);

 

 					// Get the 'properties' attribute if specified.

-					if (beanFilter.getBpi() != null && bpi == null)

-						for (String p : beanFilter.getBpi())

-							fixedBeanProps.add(p);

+					if (bpi.isEmpty())

+						fixedBeanProps.addAll(bfbpi);

 

 					if (beanFilter.getPropertyNamer() != null)

 						propertyNamer = beanFilter.getPropertyNamer();

 

-					if (beanFilter.getBpro() != null)

-						bpro.addAll(Arrays.asList(beanFilter.getBpro()));

-					

-					if (beanFilter.getBpwo() != null)

-						bpwo.addAll(Arrays.asList(beanFilter.getBpwo()));

+					bpro.addAll(beanFilter.getBpro());

+					bpwo.addAll(beanFilter.getBpwo());

 				}

 

-				if (bpi != null)

-					fixedBeanProps.addAll(Arrays.asList(bpi));

+				fixedBeanProps.addAll(bpi);

 

 				if (propertyNamer == null)

 					propertyNamer = ctx.getPropertyNamer();

@@ -431,16 +427,17 @@
 				if (beanFilter != null) {

 

 					// Eliminated excluded properties if BeanFilter.excludeKeys is specified.

-					String[] bfbpi = beanFilter.getBpi();

-					String[] bfbpx = beanFilter.getBpx();

+					Set<String> bfbpi = beanFilter.getBpi();

+					Set<String> bfbpx = beanFilter.getBpx();

 

-					if (bfbpx != null && bpx == null) {

+					if (bpx.isEmpty() && ! bfbpx.isEmpty()) {

+

 						for (String k : bfbpx)

 							properties.remove(k);

 

 					// Only include specified properties if BeanFilter.includeKeys is specified.

 					// Note that the order must match includeKeys.

-					} else if (bfbpi != null) {

+					} else if (! bfbpi.isEmpty()) {

 						Map<String,BeanPropertyMeta> properties2 = new LinkedHashMap<>();

 						for (String k : bfbpi) {

 							if (properties.containsKey(k))

@@ -450,9 +447,8 @@
 					}

 				}

 

-				if (bpx != null)

-					for (String ep : bpx)

-						properties.remove(ep);

+				for (String ep : bpx)

+					properties.remove(ep);

 

 				if (pNames != null) {

 					Map<String,BeanPropertyMeta> properties2 = new LinkedHashMap<>();

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index c7604a8..fd31ca6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -582,7 +582,7 @@
 	 *

 	 * @param m The bean map to get the transformed value from.

 	 * @param pName The property name.

-	 * @return 

+	 * @return

 	 * 	The property value.

 	 * 	<br>Returns <jk>null</jk> if this is a write-only property.

 	 */

@@ -675,7 +675,7 @@
 	/**

 	 * Equivalent to calling {@link BeanMap#put(String, Object)}, but is faster since it avoids looking up the property

 	 * meta.

-	 * 

+	 *

 	 * <p>

 	 * This is a no-op on a read-only property.

 	 *

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 36a14fc..f94f15b 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
@@ -1276,21 +1276,32 @@
 	}

 

 	/**

+	 * Configuration property:  Bean property includes.

+	 *

+	 * @see BeanContext#BEAN_bpi

+	 * @return

+	 * 	Include properties keyed by class name.

+	 */

+	protected final Map<String,Set<String>> getBpi() {

+		return ctx.getBpi();

+	}

+

+	/**

 	 * Configuration property:  Bean property excludes.

 	 *

 	 * @see BeanContext#BEAN_bpx

 	 * @return

 	 * 	The list of property names to exclude keyed by class name.

 	 */

-	protected final Map<String,String[]> getBpx() {

+	protected final Map<String,Set<String>> getBpx() {

 		return ctx.getBpx();

 	}

 

-	protected final Map<String,String[]> getBpro() {

+	protected final Map<String,Set<String>> getBpro() {

 		return ctx.getBpro();

 	}

 

-	protected final Map<String,String[]> getBpwo() {

+	protected final Map<String,Set<String>> getBpwo() {

 		return ctx.getBpwo();

 	}

 

@@ -1400,17 +1411,6 @@
 	}

 

 	/**

-	 * Configuration property:  Bean property includes.

-	 *

-	 * @see BeanContext#BEAN_bpi

-	 * @return

-	 * 	Include properties keyed by class name.

-	 */

-	protected final Map<String,String[]> getBpi() {

-		return ctx.getBpi();

-	}

-

-	/**

 	 * Configuration property:  Locale.

 	 *

 	 * <p>

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
index d04e618..58cbe4f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
@@ -516,4 +516,53 @@
 	public static <T> Set<T> newHashSet(T...values) {

 		return new HashSet<>(Arrays.asList(values));

 	}

+

+	/**

+	 * Converts the specified arguments into an unmodifiable {@link LinkedHashSet}.

+	 *

+	 * @param values The entries to populate the hashset with.

+	 * @return A new {@link LinkedHashSet} populated with the specified arguments.

+	 */

+	@SafeVarargs

+	public static <T> Set<T> newUnmodifiableLinkedHashSet(T...values) {

+		return Collections.unmodifiableSet(newLinkedHashSet(values));

+	}

+

+	/**

+	 * Converts the specified arguments into a modifiable {@link LinkedHashSet}.

+	 *

+	 * @param values The entries to populate the hashset with.

+	 * @return A new {@link LinkedHashSet} populated with the specified arguments.

+	 */

+	@SafeVarargs

+	public static <T> Set<T> newLinkedHashSet(T...values) {

+		return new LinkedHashSet<>(Arrays.asList(values));

+	}

+

+	/**

+	 * Simple passthrough to {@link Collections#emptySet()}

+	 *

+	 * @return A new unmodifiable empty set.

+	 */

+	public static <T> Set<T> emptySet() {

+		return Collections.emptySet();

+	}

+

+	/**

+	 * Simple passthrough to {@link Collections#emptyList()}

+	 *

+	 * @return A new unmodifiable empty list.

+	 */

+	public static <T> List<T> emptyList() {

+		return Collections.emptyList();

+	}

+

+	/**

+	 * Simple passthrough to {@link Collections#emptyMap()}

+	 *

+	 * @return A new unmodifiable empty set.

+	 */

+	public static <K,V> Map<K,V> emptyMap() {

+		return Collections.emptyMap();

+	}

 }

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 bac9b4d..e76004c 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
@@ -12,7 +12,8 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.transform;

 

-import static org.apache.juneau.internal.StringUtils.*;

+import java.util.*;

+

 import static org.apache.juneau.internal.ClassUtils.*;

 

 import org.apache.juneau.*;

@@ -35,7 +36,7 @@
 public final class BeanFilter {

 

 	private final Class<?> beanClass;

-	private final String[] bpi, bpx, bpro, bpwo;

+	private final Set<String> bpi, bpx, bpro, bpwo;

 	private final PropertyNamer propertyNamer;

 	private final Class<?> interfaceClass, stopClass;

 	private final boolean sortProperties, fluentSetters;

@@ -49,10 +50,10 @@
 	BeanFilter(BeanFilterBuilder<?> builder) {

 		this.beanClass = builder.beanClass;

 		this.typeName = builder.typeName;

-		this.bpi = split(builder.bpi, ',');

-		this.bpx = split(builder.bpx, ',');

-		this.bpro = split(builder.bpro, ',');

-		this.bpwo = split(builder.bpwo, ',');

+		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;

@@ -102,7 +103,7 @@
 	 * 	The name of the properties associated with a bean class, or <jk>null</jk> if all bean properties should

 	 * 	be used.

 	 */

-	public String[] getBpi() {

+	public Set<String> getBpi() {

 		return bpi;

 	}

 

@@ -111,15 +112,15 @@
 	 *

 	 * @return The name of the properties to ignore on a bean, or <jk>null</jk> to not ignore any properties.

 	 */

-	public String[] getBpx() {

+	public Set<String> getBpx() {

 		return bpx;

 	}

 

-	public String[] getBpro() {

+	public Set<String> getBpro() {

 		return bpro;

 	}

 

-	public String[] getBpwo() {

+	public Set<String> getBpwo() {

 		return bpwo;

 	}

 

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
index f6ab71f..9588b9f 100644
--- 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
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.transform;
 
+import static org.apache.juneau.internal.StringUtils.*;
+import static java.util.Arrays.*;
+
 import java.beans.*;
 import java.util.*;
 
@@ -58,7 +61,11 @@
 
 	Class<?> beanClass;
 	String typeName;
-	String[] bpi, bpx, bpro, bpwo;
+	Set<String>
+		bpi = new LinkedHashSet<>(),
+		bpx = new LinkedHashSet<>(),
+		bpro = new LinkedHashSet<>(),
+		bpwo = new LinkedHashSet<>();
 	Class<?> interfaceClass, stopClass;
 	boolean sortProperties, fluentSetters;
 	Object propertyNamer;
@@ -128,7 +135,9 @@
 	 */
 	@SuppressWarnings("javadoc")
 	@Deprecated public BeanFilterBuilder<T> properties(String...value) {
-		this.bpi = value;
+		this.bpi = new LinkedHashSet<>();
+		for (String v : value)
+			bpi.addAll(asList(split(v)));
 		return this;
 	}
 
@@ -139,7 +148,9 @@
 	 */
 	@SuppressWarnings("javadoc")
 	@Deprecated public BeanFilterBuilder<T> excludeProperties(String...value) {
-		this.bpx = value;
+		this.bpx = new LinkedHashSet<>();
+		for (String v : value)
+			bpx.addAll(asList(split(v)));
 		return this;
 	}
 
@@ -497,7 +508,9 @@
 	 * @return This object (for method chaining).
 	 */
 	public BeanFilterBuilder<T> bpi(String...value) {
-		this.bpi = value;
+		this.bpi = new LinkedHashSet<>();
+		for (String v : value)
+			bpi.addAll(asList(split(v)));
 		return this;
 	}
 
@@ -537,17 +550,23 @@
 	 * @return This object (for method chaining).
 	 */
 	public BeanFilterBuilder<T> bpx(String...value) {
-		this.bpx = value;
+		this.bpx = new LinkedHashSet<>();
+		for (String v : value)
+			bpx.addAll(asList(split(v)));
 		return this;
 	}
 
 	public BeanFilterBuilder<T> bpro(String...value) {
-		this.bpro = value;
+		this.bpro = new LinkedHashSet<>();
+		for (String v : value)
+			bpro.addAll(asList(split(v)));
 		return this;
 	}
 
 	public BeanFilterBuilder<T> bpwo(String...value) {
-		this.bpwo = value;
+		this.bpwo = new LinkedHashSet<>();
+		for (String v : value)
+			bpwo.addAll(asList(split(v)));
 		return this;
 	}