juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject juneau git commit: Improvements to PropertyStoreBuilder.
Date Sun, 07 Jan 2018 00:34:26 GMT
Repository: juneau
Updated Branches:
  refs/heads/master 972d4695e -> ea8b33982


Improvements to PropertyStoreBuilder.

Project: http://git-wip-us.apache.org/repos/asf/juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/juneau/commit/ea8b3398
Tree: http://git-wip-us.apache.org/repos/asf/juneau/tree/ea8b3398
Diff: http://git-wip-us.apache.org/repos/asf/juneau/diff/ea8b3398

Branch: refs/heads/master
Commit: ea8b339821d48b0a8c7d42ec21e3e92c93da293b
Parents: 972d469
Author: JamesBognar <jamesbognar@apache.org>
Authored: Sat Jan 6 19:34:21 2018 -0500
Committer: JamesBognar <jamesbognar@apache.org>
Committed: Sat Jan 6 19:34:21 2018 -0500

----------------------------------------------------------------------
 .../org/apache/juneau/PropertyStoreTest.java    |  18 +-
 .../juneau/utils/CollectionUtilsTest.java       |  39 +++
 .../java/org/apache/juneau/ConfigException.java |  24 +-
 .../org/apache/juneau/PropertyStoreBuilder.java | 253 ++++++++++---------
 .../org/apache/juneau/PropertyStoreUtils.java   | 146 -----------
 .../apache/juneau/internal/CollectionUtils.java |  70 +++++
 6 files changed, 277 insertions(+), 273 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/juneau/blob/ea8b3398/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PropertyStoreTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PropertyStoreTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PropertyStoreTest.java
index 212f0dc..1fdda30 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PropertyStoreTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/PropertyStoreTest.java
@@ -394,8 +394,8 @@ public class PropertyStoreTest {
 		assertObjectEquals("{A:{'f1.sc':['java.lang.String']}}", b.build());
 		
 		b.clear();
-		testError(b, "A.f1.sc/add", "['java.lang.Integer']", "Cannot add value '[\\'java.lang.Integer\\']'
(String) to property 'f1.sc' (Set<Class>).");  
-		testError(b, "A.f1.sc/add", "java.lang.Integer", "Value 'java.lang.Integer' (String) cannot
be converted to a Class.");
+		testError(b, "A.f1.sc/add", "['java.lang.Integer']", "Cannot add value '[\\'java.lang.Integer\\']'
(String) to property 'f1.sc' (Set<Class>).  Value 'java.lang.Integer' (String) cannot
be converted to a Class.");  
+		testError(b, "A.f1.sc/add", "java.lang.Integer", "Cannot add value 'java.lang.Integer'
(String) to property 'f1.sc' (Set<Class>).  Value 'java.lang.Integer' (String) cannot
be converted to a Class.");
 
 		b.clear();
 		b.set("A.f1.sc/add", new AList<Class<?>>().appendAll(Integer.class, String.class));
 
@@ -608,7 +608,7 @@ public class PropertyStoreTest {
 		b.set("A.f1.ls/add.1", "['8','9']");  
 		assertObjectEquals("{A:{'f1.ls':['7','8','9','6','1','5','2','3','4']}}", b.build());
 
-		testError(b, "A.f1.li/add.123", "foo", "Value 'foo' (String) cannot be converted to an
Integer.");
+		testError(b, "A.f1.li/add.123", "foo", "Cannot add value 'foo' (String) to property 'f1.li'
(List<Integer>).  Value 'foo' (String) cannot be converted to an Integer.");
 		try {
 			b.addTo("A.f1.li", "foo", "bar");
 			fail("Exception expected.");
@@ -637,8 +637,8 @@ public class PropertyStoreTest {
 		assertObjectEquals("{A:{'f1.lc':['java.lang.String']}}", b.build());
 		
 		b.clear();
-		testError(b, "A.f1.lc/add", "['java.lang.Integer']", "Cannot add value '[\\'java.lang.Integer\\']'
(String) to property 'f1.lc' (List<Class>).");  
-		testError(b, "A.f1.lc/add", "java.lang.Integer", "Value 'java.lang.Integer' (String) cannot
be converted to a Class.");
+		testError(b, "A.f1.lc/add", "['java.lang.Integer']", "Cannot add value '[\\'java.lang.Integer\\']'
(String) to property 'f1.lc' (List<Class>).  Value 'java.lang.Integer' (String) cannot
be converted to a Class.");  
+		testError(b, "A.f1.lc/add", "java.lang.Integer", "Cannot add value 'java.lang.Integer'
(String) to property 'f1.lc' (List<Class>).  Value 'java.lang.Integer' (String) cannot
be converted to a Class.");
 
 		b.clear();
 		b.set("A.f1.lc/add", new AList<Class<?>>().appendAll(Integer.class, String.class));
 
@@ -681,7 +681,7 @@ public class PropertyStoreTest {
 		b.set("A.f1.lc/add.-10", Object.class);
 		assertObjectEquals("{A:{'f1.lc':['java.lang.Object','java.util.List','java.lang.String','java.util.Map','java.lang.Integer']}}",
b.build());
 
-		testError(b, "A.f1.lc/add.123", "foo", "Value 'foo' (String) cannot be converted to a Class.");
+		testError(b, "A.f1.lc/add.123", "foo", "Cannot add value 'foo' (String) to property 'f1.lc'
(List<Class>).  Value 'foo' (String) cannot be converted to a Class.");
 		try {
 			b.addTo("A.f1.lc", "foo", "bar");
 			fail("Exception expected.");
@@ -1584,13 +1584,13 @@ public class PropertyStoreTest {
 			b.removeFrom("A.foo.ss", "[xxx]");
 			fail("Exception expected.");
 		} catch (ConfigException e) {
-			assertEquals("Cannot remove value '[xxx]' (String) from property 'foo.ss' (Set<String>)
because it's not a valid JSON array.", e.getMessage());
+			assertTrue(e.getMessage().startsWith("Cannot remove value '[xxx]' (String) from property
'foo.ss' (Set<String>).  Invalid input for JsonParser parser."));
 		}
 		try {
 			b.removeFrom("A.foo.ls", "[xxx]");
 			fail("Exception expected.");
 		} catch (ConfigException e) {
-			assertEquals("Cannot remove value '[xxx]' (String) from property 'foo.ls' (List<String>)
because it's not a valid JSON array.", e.getMessage());
+			assertTrue(e.getMessage().startsWith("Cannot remove value '[xxx]' (String) from property
'foo.ls' (List<String>).  Invalid input for JsonParser parser."));
 		}
 	}
 
@@ -1601,7 +1601,7 @@ public class PropertyStoreTest {
 			b.addTo("A.foo.sms", "{xxx}");
 			fail("Exception expected.");
 		} catch (ConfigException e) {
-			assertEquals("Cannot add '{xxx}' (String) to property 'foo.sms' (Map<String,String>)
because it's not a valid JSON object.", e.getMessage());
+			assertTrue(e.getMessage().startsWith("Cannot add '{xxx}' (String) to property 'foo.sms'
(Map<String,String>) .  Invalid input for JsonParser parser."));
 		}
 		try {
 			b.addTo("A.foo.sms", "xxx");

http://git-wip-us.apache.org/repos/asf/juneau/blob/ea8b3398/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/CollectionUtilsTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/CollectionUtilsTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/CollectionUtilsTest.java
index 7bd042e..9be8d6e 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/CollectionUtilsTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/CollectionUtilsTest.java
@@ -34,4 +34,43 @@ public class CollectionUtilsTest {
 		assertObjectEquals("{b:2,a:1}", reverse(new ObjectMap("{a:1,b:2}")));
 		assertObjectEquals("{}", reverse(new ObjectMap("{}")));
 	}
+	
+	@Test
+	public void testCollapse() throws Exception {
+		assertObjectEquals("[]", collapse());
+		assertObjectEquals("[1,2,3]", collapse(1,2,3));
+		assertObjectEquals("[1,2,3,4,5,6,7,8,9,10,11,12]", collapse(1, 2, null, new int[]{3,4},
new int[][]{null,{},{5,6}}, null, new ObjectList("[null,7,8,[9,10,[11,12,null]]]")));
+	}
+	
+	@Test
+	public void testAssertTypes() throws Exception {
+		assertTypes(new AList<Object>().appendAll(1,2,3), Integer.class);
+		assertTypes(new AList<Object>().appendAll(1,2,3), Object.class);
+		assertTypes(new AList<Object>().appendAll(String.class), String.class);
+		assertTypes(new AList<Object>().appendAll(String.class), CharSequence.class);
+		
+		try {
+			assertTypes(new AList<Object>().appendAll(1,2,3), Long.class);
+		} catch (Exception e) {
+			assertEquals("Invalid list entry '1' (Integer).  Not one of the following types: ['java.lang.Long']",
e.getMessage());
+		}
+
+		try {
+			assertTypes(new AList<Object>().appendAll(1,2,3), String.class);
+		} catch (Exception e) {
+			assertEquals("Invalid list entry '1' (Integer).  Not one of the following types: ['java.lang.String']",
e.getMessage());
+		}
+		
+		try {
+			assertTypes(new AList<Object>().appendAll(String.class), StringBuilder.class);
+		} catch (Exception e) {
+			assertEquals("Invalid list entry ''java.lang.String'' (Class).  Not one of the following
types: ['java.lang.StringBuilder']", e.getMessage());
+		}
+		
+		try {
+			assertTypes(new AList<Object>().appendAll(CharSequence.class), String.class);
+		} catch (Exception e) {
+			assertEquals("Invalid list entry ''java.lang.CharSequence'' (Class).  Not one of the following
types: ['java.lang.String']", e.getMessage());
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/juneau/blob/ea8b3398/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigException.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigException.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigException.java
index 88a77c9..10e44f6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ConfigException.java
@@ -30,9 +30,27 @@ public class ConfigException extends FormattedRuntimeException {
 		super(message, args);
 	}
 
+	/**
+	 * Constructor
+	 * 
+	 * @param t The init cause.  Can be <jk>null</jk>. 
+	 * @param message The error message.
+	 * @param args Optional {@link MessageFormat}-style arguments.
+	 */
+	public ConfigException(Throwable t, String message, Object...args) {
+		super(t, message, args);
+	}
+	
 	@Override
-	public synchronized ConfigException initCause(Throwable t) {
-		super.initCause(t);
-		return this;
+	public String getMessage() {
+		Throwable t = getCause();
+		if (t == null)
+			return super.getMessage();
+		StringBuilder sb = new StringBuilder(super.getMessage());
+		while (t != null) {
+			sb.append("  ").append(t.getMessage());
+			t = t.getCause();
+		}
+		return sb.toString();
 	}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/juneau/blob/ea8b3398/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreBuilder.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreBuilder.java
index 391a201..2705db0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreBuilder.java
@@ -12,14 +12,16 @@
 // ***************************************************************************************************************************
 package org.apache.juneau;
 
+import static java.util.Collections.*;
+
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.regex.*;
 
 import org.apache.juneau.PropertyStore.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
-import org.apache.juneau.parser.*;
 
 /**
  * A builder for {@link PropertyStore} objects.
@@ -331,7 +333,7 @@ public class PropertyStoreBuilder {
 		final Map<String,MutableProperty> properties = new ConcurrentSkipListMap<>();
 		
 		PropertyGroupBuilder() {
-			this(Collections.EMPTY_MAP);
+			this(EMPTY_MAP);
 		}
 		
 		synchronized void apply(PropertyGroup copyFrom) {
@@ -517,7 +519,6 @@ public class PropertyStoreBuilder {
 	// MutableSetProperty
 	//-------------------------------------------------------------------------------------------------------------------
 	
-	@SuppressWarnings("unchecked")
 	static class MutableSetProperty extends MutableProperty {
 		private final Set<Object> set;
 
@@ -529,67 +530,42 @@ public class PropertyStoreBuilder {
 		
 		@Override /* MutableProperty */
 		synchronized Property build() {
-			return new Property(name, Collections.unmodifiableSet(new LinkedHashSet<>(set)),
type);
+			return new Property(name, unmodifiableSet(new LinkedHashSet<>(set)), type);
 		}
 
 		@Override /* MutableProperty */
 		synchronized void set(Object value) {
 			try {
-				Set<Object> newSet = PropertyStoreUtils.merge(set, type.converter, value);
+				Set<Object> newSet = merge(set, type.converter, value);
 				set.clear();
 				set.addAll(newSet);
-			} catch (ParseException e) {
-				throw new ConfigException("Cannot set value {0} ({1}) on property ''{2}'' ({3}).", string(value),
className(value), name, type).initCause(e);
+			} catch (Exception e) {
+				throw new ConfigException(e, "Cannot set value {0} ({1}) on property ''{2}'' ({3}).",
string(value), className(value), name, type);
 			}
 		}
 		
 		@Override /* MutableProperty */
 		synchronized void apply(Object values) {
-			for (Object o : ((Set<?>)values)) 
-				add(null, o);
+			set.addAll((Set<?>)values);
 		}
 		
 		@Override /* MutableProperty */
 		synchronized void add(String arg, Object o) {
 			if (arg != null)
 				throw new ConfigException("Cannot use argument ''{0}'' on add command for property ''{1}''
({2})", arg, name, type);
-			if (o != null) {
-				if (o.getClass().isArray()) {
-					for (int i = 0; i < Array.getLength(o); i++)
-						add(null, Array.get(o, i));
-				} else if (o instanceof Collection) {
-					for (Object o2 : (Collection<Object>)o)
-						add(null, o2);
-				} else if (isObjectList(o)) {
-					try {
-						add(null, new ObjectList(o.toString()));
-					} catch (Exception e) {
-						throw new ConfigException("Cannot add value {0} ({1}) to property ''{2}'' ({3}).",
string(o), className(o), name, type);
-					}
-				} else {
-					set.add(convert(o));
-				}
+			try {
+				set.addAll(normalize(type.converter, o));
+			} catch (Exception e) {
+				throw new ConfigException(e, "Cannot add value {0} ({1}) to property ''{2}'' ({3}).",
string(o), className(o), name, type);
 			}
 		}
 		
 		@Override /* MutableProperty */
 		synchronized void remove(Object o) {
-			if (o != null) {
-				if (o.getClass().isArray()) {
-					for (int i = 0; i < Array.getLength(o); i++)
-						remove(Array.get(o, i));
-				} else if (o instanceof Collection) {
-					for (Object o2 : (Collection<Object>)o)
-						remove(o2);
-				} else if (isObjectList(o)) {
-					try {
-						remove(new ObjectList(o.toString()));
-					} catch (Exception e) {
-						throw new ConfigException("Cannot remove value {0} ({1}) from property ''{2}'' ({3})
because it''s not a valid JSON array.", string(o), className(o), name, type);
-					}					
-				} else {
-					set.remove(convert(o));
-				}
+			try {
+				set.removeAll(normalize(type.converter, o));
+			} catch (Exception e) {
+				throw new ConfigException(e, "Cannot remove value {0} ({1}) from property ''{2}'' ({3}).",
string(o), className(o), name, type);
 			}
 		}
 		
@@ -608,9 +584,8 @@ public class PropertyStoreBuilder {
 	// MutableListProperty
 	//-------------------------------------------------------------------------------------------------------------------
 	
-	@SuppressWarnings("unchecked")
 	static class MutableListProperty extends MutableProperty {
-		private final List<Object> list = new CopyOnWriteArrayList<>();
+		private final List<Object> list = synchronizedList(new LinkedList<>());
 
 		MutableListProperty(String name, PropertyType type, Object value) {
 			super(name, type);
@@ -619,25 +594,23 @@ public class PropertyStoreBuilder {
 		
 		@Override /* MutableProperty */
 		synchronized Property build() {
-			return new Property(name, Collections.unmodifiableList(CollectionUtils.reverse(new ArrayList<>(list))),
type);
+			return new Property(name, unmodifiableList(new ArrayList<>(list)), type);
 		}
 
 		@Override /* MutableProperty */
 		synchronized void set(Object value) {
 			try {
-				List<Object> oldList = CollectionUtils.reverseCopy(list);
-				List<Object> newList = PropertyStoreUtils.merge(oldList, type.converter, value);
-				Collections.reverse(newList);
+				List<Object> newList = merge(list, type.converter, value);
 				list.clear();
 				list.addAll(newList);
-			} catch (ParseException e) {
-				throw new ConfigException("Cannot set value {0} ({1}) on property ''{2}'' ({3}).", string(value),
className(value), name, type).initCause(e);
+			} catch (Exception e) {
+				throw new ConfigException(e, "Cannot set value {0} ({1}) on property ''{2}'' ({3}).",
string(value), className(value), name, type);
 			}
 		}
 		
 		@Override /* MutableProperty */
 		synchronized void apply(Object values) {
-			add(null, values);
+			list.addAll((List<?>)values);
 		}
 
 		@Override /* MutableProperty */
@@ -645,70 +618,28 @@ public class PropertyStoreBuilder {
 			if (arg != null && ! StringUtils.isNumeric(arg))
 				throw new ConfigException("Invalid argument ''{0}'' on add command for property ''{1}''
({2})", arg, name, type);
 			
-			// Note that since lists are stored in reverse-order, the index should be the compliment.
-			
-			int index = arg == null ? list.size() : list.size() - Integer.parseInt(arg);
+			int index = arg == null ? 0 : Integer.parseInt(arg);
 			if (index < 0)
 				index = 0;
 			else if (index > list.size())
 				index = list.size();
-			add(index, o);
-		}
-		
-		private synchronized int add(int index, Object o) {
-			if (o != null) {
-				
-				// Important!
-				// Arrays and collections are inserted in REVERSE order.
-				// So if you call addTo(X, "['a','b','c']").addTo(X, "['d','e','f']"), the list will
end up
-				// containing ['c','b','a','f','e','d'].
-				// This ensures entries in the incoming value takes precedence in first-to-last order,
but
-				// subsequent calls to addTo() are added to the end.
-				// What you get is a list ordered in least-to-most important.
-				
-				if (o.getClass().isArray()) {
-					for (int i = Array.getLength(o) - 1; i >= 0; i--)
-						index = add(index, Array.get(o, i));
-				} else if (o instanceof Collection) {
-					for (Object o2 : CollectionUtils.reverseIterable((Collection<Object>)o))
-						index = add(index, o2);
-				} else if (isObjectList(o)) {
-					try {
-						index = add(index, new ObjectList(o.toString()));
-					} catch (Exception e) {
-						throw new ConfigException("Cannot add value {0} ({1}) to property ''{2}'' ({3}).",
string(o), className(o), name, type);
-					}
-				} else {
-					o = convert(o);
-					boolean replaced = list.remove(o);
-					if (replaced)
-						index--;
-					list.add(index, o);
-					index++;
-				}
+			
+			try {
+				List<Object> l = normalize(type.converter, o);
+				list.removeAll(l);
+				list.addAll(index, l);
+			} catch (Exception e) {
+				throw new ConfigException(e, "Cannot add value {0} ({1}) to property ''{2}'' ({3}).",
string(o), className(o), name, type);
 			}
-			return index;
 		}
-
+		
 		@Override /* MutableProperty */
 		synchronized void remove(Object o) {
-			if (o != null) {
-				if (o.getClass().isArray()) {
-					for (int i = 0; i < Array.getLength(o); i++)
-						remove(Array.get(o, i));
-				} else if (o instanceof Collection) {
-					for (Object o2 : (Collection<Object>)o)
-						remove(o2);
-				} else if (isObjectList(o)) {
-					try {
-						remove(new ObjectList(o.toString()));
-					} catch (Exception e) {
-						throw new ConfigException("Cannot remove value {0} ({1}) from property ''{2}'' ({3})
because it''s not a valid JSON array.", string(o), className(o), name, type);
-					}					
-				} else {
-					list.remove(convert(o));
-				}
-			}
+			try {
+				list.removeAll(normalize(type.converter, o));
+			} catch (Exception e) {
+				throw new ConfigException(e, "Cannot remove value {0} ({1}) from property ''{2}'' ({3}).",
string(o), className(o), name, type);
+			}					
 		}
 
 		@Override /* MutableProperty */
@@ -742,7 +673,7 @@ public class PropertyStoreBuilder {
 		
 		@Override /* MutableProperty */
 		synchronized Property build() {
-			return new Property(name, Collections.unmodifiableMap(new TreeMap<>(map)), type);
+			return new Property(name, unmodifiableMap(new TreeMap<>(map)), type);
 		}
 
 		@Override /* MutableProperty */
@@ -777,7 +708,7 @@ public class PropertyStoreBuilder {
 					try {
 						add(null, new ObjectMap(o.toString()));
 					} catch (Exception e) {
-						throw new ConfigException("Cannot add {0} ({1}) to property ''{2}'' ({3}) because it''s
not a valid JSON object.", string(o), className(o), name, type);
+						throw new ConfigException(e, "Cannot add {0} ({1}) to property ''{2}'' ({3}) .", string(o),
className(o), name, type);
 					}
 				} else {
 					throw new ConfigException("Cannot add {0} ({1}) to property ''{2}'' ({3}).", string(o),
className(o), name, type);
@@ -809,12 +740,12 @@ public class PropertyStoreBuilder {
 		
 		@Override
 		protected Map<String,Object> createMap() {
-			return Collections.synchronizedMap(new LinkedHashMap<String,Object>());
+			return synchronizedMap(new LinkedHashMap<String,Object>());
 		}
 		
 		@Override /* MutableProperty */
 		synchronized Property build() {
-			return new Property(name, Collections.unmodifiableMap(new LinkedHashMap<>(map)),
type);
+			return new Property(name, unmodifiableMap(new LinkedHashMap<>(map)), type);
 		}
 	}
 	
@@ -823,12 +754,70 @@ public class PropertyStoreBuilder {
 	// Utility methods
 	//-------------------------------------------------------------------------------------------------------------------
 	
-	static boolean isObjectList(Object o) {
-		if (o instanceof CharSequence) {
-			String s = o.toString();
-			return (s.startsWith("[") && s.endsWith("]") && BeanContext.DEFAULT !=
null);
+	static Set<Object> merge(Set<Object> oldSet, PropertyConverter<?> pc,
Object o) throws Exception {
+		return merge(oldSet, new LinkedHashSet<>(), normalize(pc, o));
+	}
+
+	private static Set<Object> merge(Set<Object> oldSet, Set<Object> newSet,
List<Object> l) {
+		for (Object o : l) {
+			if (isNone(o))
+				newSet.clear();
+			else if (isInherit(o))
+				newSet.addAll(oldSet);
+			else
+				newSet.add(o);
 		}
-		return false;
+		return newSet;
+	}
+
+	static List<Object> merge(List<Object> oldList, PropertyConverter<?> pc,
Object o) throws Exception {
+		return merge(oldList, new ArrayList<>(), normalize(pc, o));
+	}
+
+	private static List<Object> merge(List<Object> oldList, List<Object> newList,
List<Object> l) {
+		for (Object o : l) {
+			if (isIndexed(o)) {
+				Matcher lm = INDEXED_LINK_PATTERN.matcher(o.toString());
+				lm.matches();
+				String key = lm.group(1);
+				int i2 = Math.min(newList.size(), Integer.parseInt(lm.group(2)));
+				String remainder = lm.group(3);
+				newList.add(i2, key.isEmpty() ? remainder : key + ":" + remainder);
+			} else if (isNone(o)) {
+				newList.clear();
+			} else if (isInherit(o)) {
+				if (oldList != null)
+					for (Object o2 : oldList)
+						newList.add(o2);
+			} else {
+				newList.remove(o);
+				newList.add(o);
+			}
+		}
+		
+		return newList;
+	}
+	
+	static List<Object> normalize(PropertyConverter<?> pc, Object o) throws Exception
{
+		return normalize(new ArrayList<>(), pc, o);
+	}
+
+	@SuppressWarnings("unchecked")
+	static List<Object> normalize(List<Object> l, PropertyConverter<?> pc,
Object o) throws Exception {
+		if (o != null) {
+			if (o.getClass().isArray()) {
+				for (int i = 0; i < Array.getLength(o); i++)
+					normalize(l, pc, Array.get(o, i));
+			} else if (o instanceof Collection) {
+				for (Object o2 : (Collection<Object>)o) 
+					normalize(l, pc, o2);
+			} else if (isObjectList(o)) {
+				normalize(l, pc, new ObjectList(o.toString()));
+			} else {
+				l.add(pc == null ? o : pc.convert(o));
+			}
+		}
+		return l;
 	}
 	
 	static String string(Object value) {
@@ -852,4 +841,38 @@ public class PropertyStoreBuilder {
 			return "";
 		return key.substring(0, key.indexOf('.'));
 	}
+
+	static boolean isObjectList(Object o) {
+		if (o instanceof CharSequence) {
+			String s = o.toString();
+			return (s.startsWith("[") && s.endsWith("]") && BeanContext.DEFAULT !=
null);
+		}
+		return false;
+	}
+
+	private static boolean isNone(Object o) {
+		if (o instanceof CharSequence) {
+			String s = o.toString();
+			return "NONE".equals(s);
+		}
+		return false;
+	}
+
+	private static boolean isIndexed(Object o) {
+		if (o instanceof CharSequence) {
+			String s = o.toString();
+			return s.indexOf('[') != -1 && INDEXED_LINK_PATTERN.matcher(s).matches();
+		}
+		return false;
+	}
+
+	private static final Pattern INDEXED_LINK_PATTERN = Pattern.compile("(?s)(\\S*)\\[(\\d+)\\]\\:(.*)");
+	
+	private static boolean isInherit(Object o) {
+		if (o instanceof CharSequence) {
+			String s = o.toString();
+			return "INHERIT".equals(s);
+		}
+		return false;
+	}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/juneau/blob/ea8b3398/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreUtils.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreUtils.java
deleted file mode 100644
index d65bca0..0000000
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStoreUtils.java
+++ /dev/null
@@ -1,146 +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;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.regex.*;
-
-import org.apache.juneau.parser.*;
-
-/**
- * Utility methods for working with property store properties.
- */
-public class PropertyStoreUtils {
-	
-	/**
-	 * Merges a new object into an existing set.
-	 * 
-	 * @param oldSet The previous set.
-	 * @param pc The property converter to use to convert values in the new value.
-	 * @param o The new value to add.
-	 * @return A new set containing the merged contents.
-	 * @throws ParseException
-	 */
-	public static Set<Object> merge(Set<Object> oldSet, PropertyConverter<?>
pc, Object o) throws ParseException {
-		return merge(oldSet, new LinkedHashSet<>(), pc, o);
-	}
-
-	@SuppressWarnings("unchecked")
-	static Set<Object> merge(Set<Object> oldSet, Set<Object> newSet, PropertyConverter<?>
pc, Object o) throws ParseException {
-		if (o == null) {
-			// Ignore.
-		} else if (o.getClass().isArray()) {
-			for (int i = 0; i < Array.getLength(o); i++)
-				merge(oldSet, newSet, pc, Array.get(o, i));
-		} else if (o instanceof Collection) {
-			for (Object o2 : (Collection<Object>)o)
-				merge(oldSet, newSet, pc, o2);
-		} else if (isObjectList(o)) {
-			merge(oldSet, newSet, pc, new ObjectList(o.toString()));
-		} else if (isNone(o)) {
-			newSet.clear();
-		} else if (isInherit(o)) {
-			if (oldSet != null)
-				for (Object o2 : oldSet)
-					newSet.add(o2);
-		} else {
-			newSet.add(pc == null ? o : pc.convert(o));
-		}
-		return newSet;
-	}
-
-	/**
-	 * Merges a new object into an existing list.
-	 * 
-	 * @param oldList The previous list.
-	 * @param pc The property converter to use to convert values in the new value.
-	 * @param o The new value to add.
-	 * @return A new list containing the merged contents.
-	 * @throws ParseException
-	 */
-	public static List<Object> merge(List<Object> oldList, PropertyConverter<?>
pc, Object o) throws ParseException {
-		return merge(oldList, new ArrayList<>(), pc, o);
-	}
-
-	@SuppressWarnings("unchecked")
-	private static List<Object> merge(List<Object> oldList, List<Object> newList,
PropertyConverter<?> pc, Object o) throws ParseException {
-		if (o == null) {
-			// Ignore
-		} else if (o.getClass().isArray()) {
-			for (int i = 0; i < Array.getLength(o); i++)
-				merge(oldList, newList, pc, Array.get(o, i));
-		} else if (o instanceof Collection) {
-			for (Object o2 : (Collection<Object>)o)
-				merge(oldList, newList, pc, o2);
-		} else if (isIndexed(o)) {
-			Matcher lm = INDEXED_LINK_PATTERN.matcher(o.toString());
-			lm.matches();
-			String key = lm.group(1);
-			int i2 = Math.min(newList.size(), Integer.parseInt(lm.group(2)));
-			String remainder = lm.group(3);
-			newList.add(i2, key.isEmpty() ? remainder : key + ":" + remainder);
-		} else if (isObjectList(o)) {
-			merge(oldList, newList, pc, new ObjectList(o.toString()));
-		} else if (isNone(o)) {
-			newList.clear();
-		} else if (isInherit(o)) {
-			if (oldList != null)
-				for (Object o2 : oldList)
-					newList.add(o2);
-		} else {
-			o = pc == null ? o : pc.convert(o);
-			newList.remove(o);
-			newList.add(o);
-		}
-		return newList;
-	}
-	
-	//-------------------------------------------------------------------------------------------------------------------
-	// Utility methods
-	//-------------------------------------------------------------------------------------------------------------------
-	
-	private static boolean isObjectList(Object o) {
-		if (o instanceof CharSequence) {
-			String s = o.toString();
-			return (s.startsWith("[") && s.endsWith("]") && BeanContext.DEFAULT !=
null);
-		}
-		return false;
-	}
-
-	private static boolean isNone(Object o) {
-		if (o instanceof CharSequence) {
-			String s = o.toString();
-			return "NONE".equals(s);
-		}
-		return false;
-	}
-
-	private static boolean isIndexed(Object o) {
-		if (o instanceof CharSequence) {
-			String s = o.toString();
-			return s.indexOf('[') != -1 && INDEXED_LINK_PATTERN.matcher(s).matches();
-		}
-		return false;
-	}
-
-	private static final Pattern INDEXED_LINK_PATTERN = Pattern.compile("(?s)(\\S*)\\[(\\d+)\\]\\:(.*)");
-	
-	private static boolean isInherit(Object o) {
-		if (o instanceof CharSequence) {
-			String s = o.toString();
-			return "INHERIT".equals(s);
-		}
-		return false;
-	}
-}

http://git-wip-us.apache.org/repos/asf/juneau/blob/ea8b3398/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
----------------------------------------------------------------------
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 e4b5a6c..7bb2e50 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
@@ -12,8 +12,12 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.internal;
 
+import java.lang.reflect.*;
 import java.util.*;
 
+import org.apache.juneau.*;
+import org.apache.juneau.json.*;
+
 /**
  * Utility methods for collections.
  */
@@ -133,4 +137,70 @@ public final class CollectionUtils {
 		Collections.reverse(l2);
 		return l2;
 	}
+	
+	/**
+	 * Collapses a collection of individual objects, arrays, and collections into a single list
of objects.
+	 * 
+	 * @param o The collection of objects to collapse.
+	 * @return A new linked-list of objects.
+	 */
+	public static List<Object> collapse(Object...o) {
+		return collapse(new LinkedList<>(), o);
+	}
+
+	/**
+	 * Same as {@link #collapse(Object...)} but allows you to supply your own list to append
to.
+	 * 
+	 * @param l The list to append to.
+	 * @param o The collection of objects to collapse.
+	 * @return The same list passed in.
+	 */
+	@SuppressWarnings("unchecked")
+	public static List<Object> collapse(List<Object> l, Object...o) {
+		for (Object o2 : o) {
+			if (o2 != null) {
+				if (o2.getClass().isArray()) {
+					for (int i = 0; i < Array.getLength(o2); i++)
+						collapse(l, Array.get(o2, i));
+				} else if (o2 instanceof Collection) {
+					for (Object o3 : (Collection<Object>)o2) 
+						collapse(l, o3);
+				} else {
+					l.add(o2);
+				}
+			}
+		}
+		return l;
+	}
+	
+	/**
+	 * Asserts that all entries in the list are either instances or subclasses of at least one
of the specified classes.
+	 * 
+	 * @param l The list to check.
+	 * @param c The valid classes.
+	 */
+	public static void assertTypes(List<Object> l, Class<?>...c) {
+		for (Object o : l) {
+			boolean matches = false;
+			if (o.getClass() == Class.class) {
+				Class<?> o2 = (Class<?>)o;
+				for (int i = 0; i < c.length && ! matches; i++)
+					matches = c[i].isAssignableFrom(o2);
+			} else {
+				for (int i = 0; i < c.length && ! matches; i++)
+					matches = c[i].isInstance(o);
+			}
+			if (! matches)
+				throw new FormattedRuntimeException("Invalid list entry ''{0}'' ({1}).  Not one of the
following types: {2}", string(o), className(o), c);
+		}
+	}
+	
+	static String string(Object value) {
+		return JsonSerializer.DEFAULT_LAX.toString(value);
+	}
+
+	static String className(Object value) {
+		return value.getClass().getSimpleName();
+	}
+	
 }


Mime
View raw message