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 2017/02/15 20:50:42 UTC

[3/8] incubator-juneau git commit: Modification to UON spec. Remove bean subtype support.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParser.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParser.java
index 510078a..21227c7 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParser.java
@@ -53,13 +53,10 @@ public class UonParser extends ReaderParser {
 	/** Reusable instance of {@link UonParser.Decoding}. */
 	public static final UonParser DEFAULT_DECODING = new Decoding().lock();
 
-	/** Reusable instance of {@link UonParser}, all default settings, whitespace-aware. */
-	public static final UonParser DEFAULT_WS_AWARE = new UonParser().setWhitespaceAware(true).lock();
-
 	// Characters that need to be preceeded with an escape character.
-	private static final AsciiSet escapedChars = new AsciiSet(",()~=$\u0001\u0002");
+	private static final AsciiSet escapedChars = new AsciiSet("~'\u0001\u0002");
 
-	private static final char NUL='\u0000', AMP='\u0001', EQ='\u0002';  // Flags set in reader to denote & and = characters.
+	private static final char AMP='\u0001', EQ='\u0002';  // Flags set in reader to denote & and = characters.
 
 	/**
 	 * Equivalent to <code><jk>new</jk> UrlEncodingParser().setProperty(UonParserContext.<jsf>UON_decodeChars</jsf>,<jk>true</jk>);</code>.
@@ -89,14 +86,10 @@ public class UonParser extends ReaderParser {
 			eType = (ClassMeta<T>)object();
 		PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap();
 		ClassMeta<?> sType = eType.getSerializedClassMeta();
-		BeanRegistry breg = (pMeta == null ? session.getBeanRegistry() : pMeta.getBeanRegistry());
 
 		Object o = null;
 
-		// Parse type flag '$x'
-		char flag = readFlag(session, r, (char)0);
-
-		int c = r.peek();
+		int c = r.peekSkipWs();
 
 		if (c == -1 || c == AMP) {
 			// If parameter is blank and it's an array or collection, return an empty list.
@@ -108,21 +101,25 @@ public class UonParser extends ReaderParser {
 				o = sType.getPrimitiveDefault();
 			// Otherwise, leave null.
 		} else if (sType.isObject()) {
-			if (flag == 0 || flag == 's') {
-				o = parseString(session, r, isUrlParamValue);
-			} else if (flag == 'b') {
-				o = parseBoolean(session, r);
-			} else if (flag == 'n') {
-				o = parseNumber(session, r, null);
-			} else if (flag == 'o') {
+			if (c == '(') {
 				ObjectMap m = new ObjectMap(session);
 				parseIntoMap(session, r, m, string(), object(), pMeta);
-				o = breg.cast(m);
-			} else if (flag == 'a') {
+				o = session.cast(m, pMeta, eType);
+			} else if (c == '@') {
 				Collection l = new ObjectList(session);
 				o = parseIntoCollection(session, r, l, sType.getElementType(), isUrlParamValue, pMeta);
 			} else {
-				throw new ParseException(session, "Unexpected flag character ''{0}''.", flag);
+				String s = parseString(session, r, isUrlParamValue);
+				if (c != '\'') {
+					if ("true".equals(s) || "false".equals(s))
+						o = Boolean.valueOf(s);
+					else if (StringUtils.isNumeric(s))
+						o = StringUtils.parseNumber(s, Number.class);
+					else
+						o = s;
+				} else {
+					o = s;
+				}
 			}
 		} else if (sType.isBoolean()) {
 			o = parseBoolean(session, r);
@@ -137,12 +134,12 @@ public class UonParser extends ReaderParser {
 			Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(session));
 			o = parseIntoMap(session, r, m, sType.getKeyType(), sType.getValueType(), pMeta);
 		} else if (sType.isCollection()) {
-			if (flag == 'o') {
+			if (c == '(') {
 				ObjectMap m = new ObjectMap(session);
 				parseIntoMap(session, r, m, string(), object(), pMeta);
 				// Handle case where it's a collection, but serialized as a map with a _type or _value key.
 				if (m.containsKey(session.getBeanTypePropertyName()))
-					o = breg.cast(m);
+					o = session.cast(m, pMeta, eType);
 				// Handle case where it's a collection, but only a single value was specified.
 				else {
 					Collection l = (sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance(outer) : new ObjectList(session));
@@ -164,12 +161,12 @@ public class UonParser extends ReaderParser {
 		} else if (sType.canCreateNewInstanceFromNumber(outer)) {
 			o = sType.newInstanceFromNumber(session, outer, parseNumber(session, r, sType.getNewInstanceFromNumberClass()));
 		} else if (sType.isArray()) {
-			if (flag == 'o') {
+			if (c == '(') {
 				ObjectMap m = new ObjectMap(session);
 				parseIntoMap(session, r, m, string(), object(), pMeta);
 				// Handle case where it's an array, but serialized as a map with a _type or _value key.
 				if (m.containsKey(session.getBeanTypePropertyName()))
-					o = breg.cast(m);
+					o = session.cast(m, pMeta, eType);
 				// Handle case where it's an array, but only a single value was specified.
 				else {
 					ArrayList l = new ArrayList(1);
@@ -180,12 +177,12 @@ public class UonParser extends ReaderParser {
 				ArrayList l = (ArrayList)parseIntoCollection(session, r, new ArrayList(), sType.getElementType(), isUrlParamValue, pMeta);
 				o = session.toArray(sType, l);
 			}
-		} else if (flag == 'o') {
+		} else if (c == '(') {
 			// It could be a non-bean with _type attribute.
 			ObjectMap m = new ObjectMap(session);
 			parseIntoMap(session, r, m, string(), object(), pMeta);
 			if (m.containsKey(session.getBeanTypePropertyName()))
-				o = breg.cast(m);
+				o = session.cast(m, pMeta, eType);
 			else
 				throw new ParseException(session, "Class ''{0}'' could not be instantiated.  Reason: ''{1}''", sType.getInnerClass().getName(), sType.getNotABeanReason());
 		} else {
@@ -207,8 +204,10 @@ public class UonParser extends ReaderParser {
 			keyType = (ClassMeta<K>)string();
 
 		int c = r.read();
-		if (c == -1 || c == NUL || c == AMP)
+		if (c == -1 || c == AMP)
 			return null;
+		if (c == 'n')
+			return (Map<K,V>)parseNull(session, r);
 		if (c != '(')
 			throw new ParseException(session, "Expected '(' at beginning of object.");
 
@@ -226,12 +225,12 @@ public class UonParser extends ReaderParser {
 				if (state == S1) {
 					if (c == ')')
 						return m;
-					if ((c == '\n' || c == '\r') && session.isWhitespaceAware())
+					if (Character.isWhitespace(c))
 						skipSpace(r);
 					else {
 						r.unread();
 						Object attr = parseAttr(session, r, session.isDecodeChars());
-						currAttr = session.trim((attr == null ? null : session.convertToType(attr, keyType)));
+						currAttr = attr == null ? null : convertAttrToType(session, m, session.trim(attr.toString()), keyType);
 						state = S2;
 						c = 0; // Avoid isInEscape if c was '\'
 					}
@@ -287,18 +286,23 @@ public class UonParser extends ReaderParser {
 
 	private <E> Collection<E> parseIntoCollection(UonParserSession session, ParserReader r, Collection<E> l, ClassMeta<E> elementType, boolean isUrlParamValue, BeanPropertyMeta pMeta) throws Exception {
 
-		int c = r.read();
-		if (c == -1 || c == NUL || c == AMP)
+		int c = r.readSkipWs();
+		if (c == -1 || c == AMP)
 			return null;
+		if (c == 'n')
+			return (Collection<E>)parseNull(session, r);
 
 		// If we're parsing a top-level parameter, we're allowed to have comma-delimited lists outside parenthesis (e.g. "&foo=1,2,3&bar=a,b,c")
 		// This is not allowed at lower levels since we use comma's as end delimiters.
-		boolean isInParens = (c == '(');
-		if (! isInParens)
+		boolean isInParens = (c == '@');
+		if (! isInParens) {
 			if (isUrlParamValue)
 				r.unread();
 			else
 				throw new ParseException(session, "Could not find '(' marking beginning of collection.");
+		} else {
+			r.read();
+		}
 
 		if (isInParens) {
 			final int S1=1; // Looking for starting of first entry.
@@ -315,7 +319,7 @@ public class UonParser extends ReaderParser {
 							r.read();
 						}
 						return l;
-					} else if ((c == '\n' || c == '\r') && session.isWhitespaceAware()) {
+					} else if (Character.isWhitespace(c)) {
 						skipSpace(r);
 					} else {
 						l.add(parseAnything(session, elementType, r.unread(), l, false, pMeta));
@@ -342,7 +346,7 @@ public class UonParser extends ReaderParser {
 			while (c != -1 && c != AMP) {
 				c = r.read();
 				if (state == S1) {
-					if ((c == '\n' || c == '\r') && session.isWhitespaceAware()) {
+					if (Character.isWhitespace(c)) {
 						skipSpace(r);
 					} else {
 						l.add(parseAnything(session, elementType, r.unread(), l, false, pMeta));
@@ -351,7 +355,7 @@ public class UonParser extends ReaderParser {
 				} else if (state == S2) {
 					if (c == ',') {
 						state = S1;
-					} else if ((c == '\n' || c == '\r') && session.isWhitespaceAware()) {
+					} else if (Character.isWhitespace(c)) {
 						skipSpace(r);
 					} else if (c == AMP || c == -1) {
 						r.unread();
@@ -366,9 +370,11 @@ public class UonParser extends ReaderParser {
 
 	private <T> BeanMap<T> parseIntoBeanMap(UonParserSession session, ParserReader r, BeanMap<T> m) throws Exception {
 
-		int c = r.read();
-		if (c == -1 || c == NUL || c == AMP)
+		int c = r.readSkipWs();
+		if (c == -1 || c == AMP)
 			return null;
+		if (c == 'n')
+			return (BeanMap<T>)parseNull(session, r);
 		if (c != '(')
 			throw new ParseException(session, "Expected '(' at beginning of object.");
 
@@ -388,7 +394,7 @@ public class UonParser extends ReaderParser {
 					if (c == ')' || c == -1 || c == AMP) {
 						return m;
 					}
-					if ((c == '\n' || c == '\r') && session.isWhitespaceAware())
+					if (Character.isWhitespace(c))
 						skipSpace(r);
 					else {
 						r.unread();
@@ -413,11 +419,7 @@ public class UonParser extends ReaderParser {
 						if (! currAttr.equals(session.getBeanTypePropertyName())) {
 							BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 							if (pMeta == null) {
-								if (m.getMeta().isSubTyped()) {
-									m.put(currAttr, "");
-								} else {
-									onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
-								}
+								onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
 							} else {
 								Object value = session.convertToType("", pMeta.getClassMeta());
 								pMeta.set(m, value);
@@ -430,13 +432,8 @@ public class UonParser extends ReaderParser {
 						if (! currAttr.equals(session.getBeanTypePropertyName())) {
 							BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 							if (pMeta == null) {
-								if (m.getMeta().isSubTyped()) {
-									Object value = parseAnything(session, object(), r.unread(), m.getBean(false), false, null);
-									m.put(currAttr, value);
-								} else {
-									onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
-									parseAnything(session, object(), r.unread(), m.getBean(false), false, null); // Read content anyway to ignore it
-								}
+								onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
+								parseAnything(session, object(), r.unread(), m.getBean(false), false, null); // Read content anyway to ignore it
 							} else {
 								session.setCurrentProperty(pMeta);
 								ClassMeta<?> cm = pMeta.getClassMeta();
@@ -470,32 +467,26 @@ public class UonParser extends ReaderParser {
 		return null; // Unreachable.
 	}
 
+	Object parseNull(UonParserSession session, ParserReader r) throws Exception {
+		String s = parseString(session, r, false);
+		if ("ull".equals(s))
+			return null;
+		throw new ParseException(session, "Unexpected character sequence: ''{0}''", s);
+	}
+
 	Object parseAttr(UonParserSession session, ParserReader r, boolean encoded) throws Exception {
 		Object attr;
-		int c = r.peek();
-		if (c == '$') {
-			char f = readFlag(session, r, (char)0);
-			if (f == 'b')
-				attr = parseBoolean(session, r);
-			else if (f == 'n')
-				attr = parseNumber(session, r, null);
-			else
-				attr = parseAttrName(session, r, encoded);
-		} else {
-			attr = parseAttrName(session, r, encoded);
-		}
+		attr = parseAttrName(session, r, encoded);
 		return attr;
 	}
 
 	String parseAttrName(UonParserSession session, ParserReader r, boolean encoded) throws Exception {
 
-		// If string is of form '(xxx)', we're looking for ')' at the end.
-		// Otherwise, we're looking for '&' or '=' or -1 denoting the end of this string.
+		// If string is of form 'xxx', we're looking for ' at the end.
+		// Otherwise, we're looking for '&' or '=' or WS or -1 denoting the end of this string.
 
-		int c = r.peek();
-		if (c == '$')
-			readFlag(session, r, 's');
-		if (c == '(')
+		int c = r.peekSkipWs();
+		if (c == '\'')
 			return parsePString(session, r);
 
 		r.mark();
@@ -504,11 +495,11 @@ public class UonParser extends ReaderParser {
 			while (c != -1) {
 				c = r.read();
 				if (! isInEscape) {
-					if (c == AMP || c == EQ || c == -1) {
+					if (c == AMP || c == EQ || c == -1 || Character.isWhitespace(c)) {
 						if (c != -1)
 							r.unread();
 						String s = r.getMarked();
-						return (s.equals("\u0000") ? null : s);
+						return ("null".equals(s) ? null : s);
 					}
 				}
 				else if (c == AMP)
@@ -521,11 +512,11 @@ public class UonParser extends ReaderParser {
 			while (c != -1) {
 				c = r.read();
 				if (! isInEscape) {
-					if (c == '=' || c == -1) {
+					if (c == '=' || c == -1 || Character.isWhitespace(c)) {
 						if (c != -1)
 							r.unread();
 						String s = r.getMarked();
-						return (s.equals("\u0000") ? null : session.trim(s));
+						return ("null".equals(s) ? null : session.trim(s));
 					}
 				}
 				isInEscape = isInEscape(c, r, isInEscape);
@@ -556,11 +547,11 @@ public class UonParser extends ReaderParser {
 
 	String parseString(UonParserSession session, ParserReader r, boolean isUrlParamValue) throws Exception {
 
-		// If string is of form '(xxx)', we're looking for ')' at the end.
+		// If string is of form 'xxx', we're looking for ' at the end.
 		// Otherwise, we're looking for ',' or ')' or -1 denoting the end of this string.
 
-		int c = r.peek();
-		if (c == '(')
+		int c = r.peekSkipWs();
+		if (c == '\'')
 			return parsePString(session, r);
 
 		r.mark();
@@ -581,7 +572,7 @@ public class UonParser extends ReaderParser {
 				s = r.getMarked();
 			else if (c == EQ)
 				r.replace('=');
-			else if ((c == '\n' || c == '\r') && session.isWhitespaceAware()) {
+			else if (Character.isWhitespace(c)) {
 				s = r.getMarked(0, -1);
 				skipSpace(r);
 				c = -1;
@@ -589,19 +580,19 @@ public class UonParser extends ReaderParser {
 			isInEscape = isInEscape(c, r, isInEscape);
 		}
 
-		return (s == null || s.equals("\u0000") ? null : session.trim(s));
+		return ("null".equals(s) ? null : session.trim(s));
 	}
 
 	private static final AsciiSet endCharsParam = new AsciiSet(""+AMP), endCharsNormal = new AsciiSet(",)"+AMP);
 
 
 	/**
-	 * Parses a string of the form "(foo)"
+	 * Parses a string of the form "'foo'"
 	 * All whitespace within parenthesis are preserved.
 	 */
 	static String parsePString(UonParserSession session, ParserReader r) throws Exception {
 
-		r.read(); // Skip first parenthesis.
+		r.read(); // Skip first quote.
 		r.mark();
 		int c = 0;
 
@@ -609,7 +600,7 @@ public class UonParser extends ReaderParser {
 		while (c != -1) {
 			c = r.read();
 			if (! isInEscape) {
-				if (c == ')')
+				if (c == '\'')
 					return session.trim(r.getMarked(0, -1));
 			}
 			if (c == EQ)
@@ -620,9 +611,8 @@ public class UonParser extends ReaderParser {
 	}
 
 	private Boolean parseBoolean(UonParserSession session, ParserReader r) throws Exception {
-		readFlag(session, r, 'b');
 		String s = parseString(session, r, false);
-		if (s == null)
+		if (s == null || s.equals("null"))
 			return null;
 		if (s.equals("true"))
 			return true;
@@ -632,7 +622,6 @@ public class UonParser extends ReaderParser {
 	}
 
 	private Number parseNumber(UonParserSession session, ParserReader r, Class<? extends Number> c) throws Exception {
-		readFlag(session, r, 'n');
 		String s = parseString(session, r, false);
 		if (s == null)
 			return null;
@@ -644,29 +633,13 @@ public class UonParser extends ReaderParser {
 	 * remainder in the input, that it consists only of whitespace and comments.
 	 */
 	private void validateEnd(UonParserSession session, ParserReader r) throws Exception {
-		int c = r.read();
-		if (c != -1)
-			throw new ParseException(session, "Remainder after parse: ''{0}''.", (char)c);
-	}
-
-	/**
-	 * Reads flag character from "$x(" construct if flag is present.
-	 * Returns 0 if no flag is present.
-	 */
-	static char readFlag(UonParserSession session, ParserReader r, char expected) throws Exception {
-		char c = (char)r.peek();
-		if (c == '$') {
-			r.read();
-			char f = (char)r.read();
-			if (expected != 0 && f != expected)
-				throw new ParseException(session, "Unexpected flag character: ''{0}''.  Expected ''{1}''.", f, expected);
-			c = (char)r.peek();
-			// Type flag must be followed by '('
-			if (c != '(')
-				throw new ParseException(session, "Unexpected character following flag: ''{0}''.", c);
-			return f;
+		while (true) {
+			int c = r.read();
+			if (c == -1)
+				return;
+			if (! Character.isWhitespace(c))
+				throw new ParseException(session, "Remainder after parse: ''{0}''.", (char)c);
 		}
-		return 0;
 	}
 
 	private Object[] parseArgs(UonParserSession session, ParserReader r, ClassMeta<?>[] argTypes) throws Exception {
@@ -677,11 +650,12 @@ public class UonParser extends ReaderParser {
 		Object[] o = new Object[argTypes.length];
 		int i = 0;
 
-		int c = r.read();
+		int c = r.readSkipWs();
 		if (c == -1 || c == AMP)
 			return null;
-		if (c != '(')
-			throw new ParseException(session, "Expected '(' at beginning of args array.");
+		if (c != '@')
+			throw new ParseException(session, "Expected '@' at beginning of args array.");
+		c = r.read();
 
 		int state = S1;
 		while (c != -1 && c != AMP) {
@@ -707,7 +681,7 @@ public class UonParser extends ReaderParser {
 	private static void skipSpace(ParserReader r) throws Exception {
 		int c = 0;
 		while ((c = r.read()) != -1) {
-			if (c > ' ' || c <= 2) {
+			if (c <= 2 || ! Character.isWhitespace(c)) {
 				r.unread();
 				return;
 			}
@@ -741,7 +715,6 @@ public class UonParser extends ReaderParser {
 	protected <K,V> Map<K,V> doParseIntoMap(ParserSession session, Map<K,V> m, Type keyType, Type valueType) throws Exception {
 		UonParserSession s = (UonParserSession)session;
 		UonReader r = s.getReader();
-		readFlag(s, r, 'o');
 		m = parseIntoMap(s, r, m, (ClassMeta<K>)session.getClassMeta(keyType), (ClassMeta<V>)session.getClassMeta(valueType), null);
 		validateEnd(s, r);
 		return m;
@@ -751,7 +724,6 @@ public class UonParser extends ReaderParser {
 	protected <E> Collection<E> doParseIntoCollection(ParserSession session, Collection<E> c, Type elementType) throws Exception {
 		UonParserSession s = (UonParserSession)session;
 		UonReader r = s.getReader();
-		readFlag(s, r, 'a');
 		c = parseIntoCollection(s, r, c, (ClassMeta<E>)session.getClassMeta(elementType), false, null);
 		validateEnd(s, r);
 		return c;
@@ -761,7 +733,6 @@ public class UonParser extends ReaderParser {
 	protected Object[] doParseArgs(ParserSession session, ClassMeta<?>[] argTypes) throws Exception {
 		UonParserSession s = (UonParserSession)session;
 		UonReader r = s.getReader();
-		readFlag(s, r, 'a');
 		Object[] a = parseArgs(s, r, argTypes);
 		return a;
 	}
@@ -798,32 +769,6 @@ public class UonParser extends ReaderParser {
 		return setProperty(UON_decodeChars, value);
 	}
 
-	/**
-	 * <b>Configuration property:</b> Whitespace aware.
-	 * <p>
-	 * <ul>
-	 * 	<li><b>Name:</b> <js>"UonParser.whitespaceAware"</js>
-	 * 	<li><b>Data type:</b> <code>Boolean</code>
-	 * 	<li><b>Default:</b> <jk>false</jk>
-	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
-	 * </ul>
-	 * <p>
-	 * Expect input to contain readable whitespace characters from using the {@link UonSerializerContext#UON_useWhitespace} setting.
-	 * <p>
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul>
-	 * 	<li>This is equivalent to calling <code>setProperty(<jsf>UON_whitespaceAware</jsf>, value)</code>.
-	 * </ul>
-	 *
-	 * @param value The new value for this property.
-	 * @return This object (for method chaining).
-	 * @throws LockedException If {@link #lock()} was called on this class.
-	 * @see UonParserContext#UON_whitespaceAware
-	 */
-	public UonParser setWhitespaceAware(boolean value) throws LockedException {
-		return setProperty(UON_whitespaceAware, value);
-	}
-
 	@Override /* Parser */
 	public UonParser setTrimStrings(boolean value) throws LockedException {
 		super.setTrimStrings(value);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserContext.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserContext.java
index f1f65bb..2cc5745 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserContext.java
@@ -48,24 +48,8 @@ public class UonParserContext extends ParserContext {
 	 */
 	public static final String UON_decodeChars = "UonParser.decodeChars";
 
-	/**
-	 * <b>Configuration property:</b> Whitespace aware.
-	 * <p>
-	 * <ul>
-	 * 	<li><b>Name:</b> <js>"UonParser.whitespaceAware"</js>
-	 * 	<li><b>Data type:</b> <code>Boolean</code>
-	 * 	<li><b>Default:</b> <jk>false</jk>
-	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
-	 * </ul>
-	 * <p>
-	 * Expect input to contain readable whitespace characters from using the {@link UonSerializerContext#UON_useWhitespace} setting.
-	 */
-	public static final String UON_whitespaceAware = "UonParser.whitespaceAware";
-
-
 	final boolean
-		decodeChars,
-		whitespaceAware;
+		decodeChars;
 
 	/**
 	 * Constructor.
@@ -77,7 +61,6 @@ public class UonParserContext extends ParserContext {
 	public UonParserContext(ContextFactory cf) {
 		super(cf);
 		this.decodeChars = cf.getProperty(UON_decodeChars, boolean.class, false);
-		this.whitespaceAware = cf.getProperty(UON_whitespaceAware, boolean.class, false);
 	}
 
 	@Override /* Context */
@@ -85,7 +68,6 @@ public class UonParserContext extends ParserContext {
 		return super.asMap()
 			.append("UonParserContext", new ObjectMap()
 				.append("decodeChars", decodeChars)
-				.append("whitespaceAware", whitespaceAware)
 			);
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserSession.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserSession.java
index c2ea7da..54b8927 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonParserSession.java
@@ -28,7 +28,7 @@ import org.apache.juneau.parser.*;
  */
 public class UonParserSession extends ParserSession {
 
-	private final boolean decodeChars, whitespaceAware;
+	private final boolean decodeChars;
 	private UonReader reader;
 
 	/**
@@ -58,10 +58,8 @@ public class UonParserSession extends ParserSession {
 		super(ctx, op, input, javaMethod, outer, locale, timeZone, mediaType);
 		if (op == null || op.isEmpty()) {
 			decodeChars = ctx.decodeChars;
-			whitespaceAware = ctx.whitespaceAware;
 		} else {
 			decodeChars = op.getBoolean(UON_decodeChars, ctx.decodeChars);
-			whitespaceAware = op.getBoolean(UON_whitespaceAware, ctx.whitespaceAware);
 		}
 	}
 
@@ -83,7 +81,6 @@ public class UonParserSession extends ParserSession {
 	public UonParserSession(UonParserContext ctx, Object input) {
 		super(ctx, null, input, null, null, null, null, null);
 		decodeChars = false;
-		whitespaceAware = ctx.whitespaceAware;
 	}
 
 	/**
@@ -95,15 +92,6 @@ public class UonParserSession extends ParserSession {
 		return decodeChars;
 	}
 
-	/**
-	 * Returns the {@link UonParserContext#UON_whitespaceAware} setting value for this session.
-	 *
-	 * @return The {@link UonParserContext#UON_whitespaceAware} setting value for this session.
-	 */
-	public final boolean isWhitespaceAware() {
-		return whitespaceAware;
-	}
-
 	@Override /* ParserSession */
 	public UonReader getReader() throws Exception {
 		if (reader == null) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializer.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializer.java
index 8c7848f..9fae479 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializer.java
@@ -73,49 +73,23 @@ import org.apache.juneau.transform.*;
  * 		UON notation would be as follows:
  * </p>
  * <p class='bcode'>
- * 	$o(
- * 		<xa>id</xa>=$n(<xs>1</xs>),
- * 		<xa>name</xa>=<xs>John+Smith</xs>,
- * 		<xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 		<xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>,
- * 		<xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>,
- * 		<xa>otherIds</xa>=<xs>%00</xs>,
- * 		<xa>addresses</xa>=$a(
- * 			$o(
- * 				<xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>,
- * 				<xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 				<xa>id</xa>=$n(<xs>1</xs>),
- * 				<xa>street</xa>=<xs>100+Main+Street</xs>,
- * 				<xa>city</xa>=<xs>Anywhereville</xs>,
- * 				<xa>state</xa>=<xs>NY</xs>,
- * 				<xa>zip</xa>=$n(<xs>12345</xs>),
- * 				<xa>isCurrent</xa>=$b(<xs>true</xs>)
- * 			)
- * 		)
- * 	)
- * </p>
- * <p>
- * 	A secondary "lax" syntax is available when the data type of the
- * 		values are already known on the receiving end of the transmission:
- * </p>
- * <p class='bcode'>
  * 	(
- * 		<xa>id</xa>=<xs>1</xs>,
- * 		<xa>name</xa>=<xs>John+Smith</xs>,
- * 		<xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 		<xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>,
- * 		<xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>,
- * 		<xa>otherIds</xa>=<xs>%00</xs>,
- * 		<xa>addresses</xa>=(
+ * 		<ua>id</ua>=<un>1</un>,
+ * 		<ua>name</ua>=<us>'John+Smith'</us>,
+ * 		<ua>uri</ua>=<us>http://sample/addressBook/person/1</us>,
+ * 		<ua>addressBookUri</ua>=<us>http://sample/addressBook</us>,
+ * 		<ua>birthDate</ua>=<us>1946-08-12T00:00:00Z</us>,
+ * 		<ua>otherIds</ua>=<uk>null</uk>,
+ * 		<ua>addresses</ua>=@(
  * 			(
- * 				<xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>,
- * 				<xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 				<xa>id</xa>=<xs>1</xs>,
- * 				<xa>street</xa>=<xs>100+Main+Street</xs>,
- * 				<xa>city</xa>=<xs>Anywhereville</xs>,
- * 				<xa>state</xa>=<xs>NY</xs>,
- * 				<xa>zip</xa>=<xs>12345</xs>,
- * 				<xa>isCurrent</xa>=<xs>true</xs>
+ * 				<ua>uri</ua>=<us>http://sample/addressBook/address/1</us>,
+ * 				<ua>personUri</ua>=<us>http://sample/addressBook/person/1</us>,
+ * 				<ua>id</ua>=<un>1</un>,
+ * 				<ua>street</ua>=<us>'100+Main+Street'</us>,
+ * 				<ua>city</ua>=<us>Anywhereville</us>,
+ * 				<ua>state</ua>=<us>NY</us>,
+ * 				<ua>zip</ua>=<un>12345</un>,
+ * 				<ua>isCurrent</ua>=<uk>true</uk>
  * 			)
  * 		)
  * 	)
@@ -127,13 +101,9 @@ import org.apache.juneau.transform.*;
  * 	Map m = <jk>new</jk> ObjectMap(<js>"{a:'b',c:1,d:false,e:['f',1,false],g:{h:'i'}}"</js>);
  *
  * 	<jc>// Serialize to value equivalent to JSON.</jc>
- * 	<jc>// Produces "$o(a=b,c=$n(1),d=$b(false),e=$a(f,$n(1),$b(false)),g=$o(h=i))"</jc>
+ * 	<jc>// Produces "(a=b,c=1,d=false,e=@(f,1,false),g=(h=i))"</jc>
  * 	String s = UonSerializer.<jsf>DEFAULT</jsf>.serialize(s);
  *
- * 	<jc>// Serialize to simplified value (for when data type is already known by receiver).</jc>
- * 	<jc>// Produces "(a=b,c=1,d=false,e=(f,1,false),g=(h=i))"</jc>
- * 	String s = UonSerializer.<jsf>DEFAULT_SIMPLE</jsf>.serialize(s);
- *
  * 	<jc>// Serialize a bean</jc>
  * 	<jk>public class</jk> Person {
  * 		<jk>public</jk> Person(String s);
@@ -152,11 +122,8 @@ import org.apache.juneau.transform.*;
  *
  * 	Person p = <jk>new</jk> Person(<js>"John Doe"</js>, 23, <js>"123 Main St"</js>, <js>"Anywhere"</js>, <js>"NY"</js>, 12345, <jk>false</jk>);
  *
- * 	<jc>// Produces "$o(name=John Doe,age=23,address=$o(street=123 Main St,city=Anywhere,state=NY,zip=$n(12345)),deceased=$b(false))"</jc>
+ * 	<jc>// Produces "(name='John Doe',age=23,address=(street='123 Main St',city=Anywhere,state=NY,zip=12345),deceased=false)"</jc>
  * 	String s = UonSerializer.<jsf>DEFAULT</jsf>.serialize(s);
- *
- * 	<jc>// Produces "(name=John Doe,age=23,address=(street=123 Main St,city=Anywhere,state=NY,zip=12345),deceased=false)"</jc>
- * 	String s = UonSerializer.<jsf>DEFAULT_SIMPLE</jsf>.serialize(s);
  * </p>
  */
 @Produces("text/uon")
@@ -165,29 +132,12 @@ public class UonSerializer extends WriterSerializer {
 	/** Reusable instance of {@link UonSerializer}, all default settings. */
 	public static final UonSerializer DEFAULT = new UonSerializer().lock();
 
-	/** Reusable instance of {@link UonSerializer.Simple}. */
-	public static final UonSerializer DEFAULT_SIMPLE = new Simple().lock();
-
 	/** Reusable instance of {@link UonSerializer.Readable}. */
 	public static final UonSerializer DEFAULT_READABLE = new Readable().lock();
 
 	/** Reusable instance of {@link UonSerializer.Encoding}. */
 	public static final UonSerializer DEFAULT_ENCODING = new Encoding().lock();
 
-	/** Reusable instance of {@link UonSerializer.SimpleEncoding}. */
-	public static final UonSerializer DEFAULT_SIMPLE_ENCODING = new SimpleEncoding().lock();
-
-	/**
-	 * Equivalent to <code><jk>new</jk> UonSerializer().setSimpleMode(<jk>true</jk>);</code>.
-	 */
-	@Produces(value="text/uon-simple",contentType="text/uon")
-	public static class Simple extends UonSerializer {
-		/** Constructor */
-		public Simple() {
-			setSimpleMode(true);
-		}
-	}
-
 	/**
 	 * Equivalent to <code><jk>new</jk> UonSerializer().setUseWhitespace(<jk>true</jk>).setUseIndentation(<jk>true</jk>);</code>.
 	 */
@@ -195,7 +145,6 @@ public class UonSerializer extends WriterSerializer {
 		/** Constructor */
 		public Readable() {
 			setUseWhitespace(true);
-			setUseIndentation(true);
 		}
 	}
 
@@ -210,19 +159,6 @@ public class UonSerializer extends WriterSerializer {
 	}
 
 	/**
-	 * Equivalent to <code><jk>new</jk> UonSerializer().setSimpleMode(<jk>true</jk>).setEncodeChars(<jk>true</jk>);</code>.
-	 */
-	@Produces(value="text/uon-simple",contentType="text/uon")
-	public static class SimpleEncoding extends UonSerializer {
-		/** Constructor */
-		public SimpleEncoding() {
-			setSimpleMode(true);
-			setEncodeChars(true);
-		}
-	}
-
-
-	/**
 	 * Workhorse method. Determines the type of object, and then calls the
 	 * appropriate type-specific serialization method.
 	 * @param session The context that exist for the duration of a serialize.
@@ -231,25 +167,22 @@ public class UonSerializer extends WriterSerializer {
 	 * @param eType The expected type of the object if this is a bean property.
 	 * @param attrName The bean property name if this is a bean property.  <jk>null</jk> if this isn't a bean property being serialized.
 	 * @param pMeta The bean property metadata.
-	 * @param quoteEmptyStrings <jk>true</jk> if this is the first entry in an array.
-	 * @param isTop If we haven't recursively called this method.
 	 *
 	 * @return The same writer passed in.
 	 * @throws Exception
 	 */
 	@SuppressWarnings({ "rawtypes", "unchecked" })
 	protected SerializerWriter serializeAnything(UonSerializerSession session, UonWriter out, Object o, ClassMeta<?> eType,
-			String attrName, BeanPropertyMeta pMeta, boolean quoteEmptyStrings, boolean isTop) throws Exception {
+			String attrName, BeanPropertyMeta pMeta) throws Exception {
 
 		if (o == null) {
-			out.appendObject(null, false, false, isTop);
+			out.appendObject(null, false);
 			return out;
 		}
 
 		if (eType == null)
 			eType = object();
 
-		boolean addTypeProperty;		// Add "_type" attribute to element?
 		ClassMeta<?> aType;			// The actual type
 		ClassMeta<?> sType;			// The serialized type
 
@@ -263,7 +196,7 @@ public class UonSerializer extends WriterSerializer {
 		}
 
 		sType = aType.getSerializedClassMeta();
-		addTypeProperty = (session.isAddBeanTypeProperties() && ! eType.equals(aType));
+		String typeName = session.getBeanTypeName(eType, aType, pMeta);
 
 		// Swap if necessary
 		PojoSwap swap = aType.getPojoSwap();
@@ -278,14 +211,18 @@ public class UonSerializer extends WriterSerializer {
 
 		// '\0' characters are considered null.
 		if (o == null || (sType.isChar() && ((Character)o).charValue() == 0))
-			out.appendObject(null, false, false, isTop);
+			out.appendObject(null, false);
+		else if (sType.isBoolean())
+			out.appendBoolean(o);
+		else if (sType.isNumber())
+			out.appendNumber(o);
 		else if (sType.isBean())
-			serializeBeanMap(session, out, session.toBeanMap(o), addTypeProperty);
+			serializeBeanMap(session, out, session.toBeanMap(o), typeName);
 		else if (sType.isUri() || (pMeta != null && pMeta.isUri()))
-			out.appendUri(o, isTop);
+			out.appendUri(o);
 		else if (sType.isMap()) {
 			if (o instanceof BeanMap)
-				serializeBeanMap(session, out, (BeanMap)o, addTypeProperty);
+				serializeBeanMap(session, out, (BeanMap)o, typeName);
 			else
 				serializeMap(session, out, (Map)o, eType);
 		}
@@ -296,7 +233,7 @@ public class UonSerializer extends WriterSerializer {
 			serializeCollection(session, out, toList(sType.getInnerClass(), o), eType);
 		}
 		else {
-			out.appendObject(o, quoteEmptyStrings, false, isTop);
+			out.appendObject(o, false);
 		}
 
 		if (! isRecursion)
@@ -312,7 +249,7 @@ public class UonSerializer extends WriterSerializer {
 		ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType();
 
 		int depth = session.getIndent();
-		out.startFlag('o');
+		out.append('(');
 
 		Iterator mapEntries = m.entrySet().iterator();
 
@@ -320,8 +257,8 @@ public class UonSerializer extends WriterSerializer {
 			Map.Entry e = (Map.Entry) mapEntries.next();
 			Object value = e.getValue();
 			Object key = session.generalize(e.getKey(), keyType);
-			out.cr(depth).appendObject(key, session.isUseWhitespace(), false, false).append('=');
-			serializeAnything(session, out, value, valueType, (key == null ? null : session.toString(key)), null, session.isUseWhitespace(), false);
+			out.cr(depth).appendObject(key, false).append('=');
+			serializeAnything(session, out, value, valueType, (key == null ? null : session.toString(key)), null);
 			if (mapEntries.hasNext())
 				out.append(',');
 		}
@@ -333,14 +270,14 @@ public class UonSerializer extends WriterSerializer {
 		return out;
 	}
 
-	private SerializerWriter serializeBeanMap(UonSerializerSession session, UonWriter out, BeanMap<?> m, boolean addTypeProperty) throws Exception {
+	private SerializerWriter serializeBeanMap(UonSerializerSession session, UonWriter out, BeanMap<?> m, String typeName) throws Exception {
 		int depth = session.getIndent();
 
-		out.startFlag('o');
+		out.append('(');
 
 		boolean addComma = false;
 
-		for (BeanPropertyValue p : m.getValues(session.isTrimNulls(), addTypeProperty ? session.createBeanTypeNameProperty(m) : null)) {
+		for (BeanPropertyValue p : m.getValues(session.isTrimNulls(), typeName != null ? session.createBeanTypeNameProperty(m, typeName) : null)) {
 			BeanPropertyMeta pMeta = p.getMeta();
 			ClassMeta<?> cMeta = p.getClassMeta();
 
@@ -356,9 +293,9 @@ public class UonSerializer extends WriterSerializer {
 			if (addComma)
 				out.append(',');
 
-			out.cr(depth).appendObject(key, false, false, false).append('=');
+			out.cr(depth).appendObject(key, false).append('=');
 
-			serializeAnything(session, out, value, cMeta, key, pMeta, false, false);
+			serializeAnything(session, out, value, cMeta, key, pMeta);
 
 			addComma = true;
 		}
@@ -377,14 +314,13 @@ public class UonSerializer extends WriterSerializer {
 
 		c = session.sort(c);
 
-		out.startFlag('a');
+		out.append('@').append('(');
 
 		int depth = session.getIndent();
-		boolean quoteEmptyString = (c.size() == 1 || session.isUseWhitespace());
 
 		for (Iterator i = c.iterator(); i.hasNext();) {
 			out.cr(depth);
-			serializeAnything(session, out, i.next(), elementType, "<iterator>", null, quoteEmptyString, false);
+			serializeAnything(session, out, i.next(), elementType, "<iterator>", null);
 			if (i.hasNext())
 				out.append(',');
 		}
@@ -409,7 +345,7 @@ public class UonSerializer extends WriterSerializer {
 	@Override /* Serializer */
 	protected void doSerialize(SerializerSession session, Object o) throws Exception {
 		UonSerializerSession s = (UonSerializerSession)session;
-		serializeAnything(s, s.getWriter(), o, null, "root", null, false, true);
+		serializeAnything(s, s.getWriter(), o, null, "root", null);
 	}
 
 
@@ -418,106 +354,6 @@ public class UonSerializer extends WriterSerializer {
 	//--------------------------------------------------------------------------------
 
 	/**
-	 * <b>Configuration property:</b>  Use simplified output.
-	 * <p>
-	 * <ul>
-	 * 	<li><b>Name:</b> <js>"UonSerializer.simpleMode"</js>
-	 * 	<li><b>Data type:</b> <code>Boolean</code>
-	 * 	<li><b>Default:</b> <jk>false</jk>
-	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
-	 * </ul>
-	 * <p>
-	 * If <jk>true</jk>, type flags will not be prepended to values in most cases.
-	 * <p>
-	 * Use this setting if the data types of the values (e.g. object/array/boolean/number/string)
-	 * 	is known on the receiving end.
-	 * <p>
-	 * It should be noted that the default behavior produces a data structure that can
-	 * 	be losslessly converted into JSON, and any JSON can be losslessly represented
-	 * 	in a URL-encoded value.  However, this strict equivalency does not exist
-	 * 	when simple mode is used.
-	 * <p>
-	 * <table class='styled'>
-	 * 	<tr>
-	 * 		<th>Input (in JSON)</th>
-	 * 		<th>Normal mode output</th>
-	 * 		<th>Simple mode output</th>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>{foo:'bar',baz:'bing'}</td>
-	 * 		<td class='code'>$o(foo=bar,baz=bing)</td>
-	 * 		<td class='code'>(foo=bar,baz=bing)</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>{foo:{bar:'baz'}}</td>
-	 * 		<td class='code'>$o(foo=$o(bar=baz))</td>
-	 * 		<td class='code'>(foo=(bar=baz))</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>['foo','bar']</td>
-	 * 		<td class='code'>$a(foo,bar)</td>
-	 * 		<td class='code'>(foo,bar)</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>['foo',['bar','baz']]</td>
-	 * 		<td class='code'>$a(foo,$a(bar,baz))</td>
-	 * 		<td class='code'>(foo,(bar,baz))</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>true</td>
-	 * 		<td class='code'>$b(true)</td>
-	 * 		<td class='code'>true</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>123</td>
-	 * 		<td class='code'>$n(123)</td>
-	 * 		<td class='code'>123</td>
-	 * 	</tr>
-	 * </table>
-	 * <p>
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul>
-	 * 	<li>This is equivalent to calling <code>setProperty(<jsf>UON_simpleMode</jsf>, value)</code>.
-	 * 	<li>This introduces a slight performance penalty.
-	 * </ul>
-	 *
-	 * @param value The new value for this property.
-	 * @return This object (for method chaining).
-	 * @throws LockedException If {@link #lock()} was called on this class.
-	 * @see UonSerializerContext#UON_simpleMode
-	 */
-	public UonSerializer setSimpleMode(boolean value) throws LockedException {
-		return setProperty(UON_simpleMode, value);
-	}
-
-	/**
-	 * <b>Configuration property:</b>  Use whitespace.
-	 * <p>
-	 * <ul>
-	 * 	<li><b>Name:</b> <js>"UonSerializer.useWhitespace"</js>
-	 * 	<li><b>Data type:</b> <code>Boolean</code>
-	 * 	<li><b>Default:</b> <jk>false</jk>
-	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
-	 * </ul>
-	 * <p>
-	 * If <jk>true</jk>, whitespace is added to the output to improve readability.
-	 * <p>
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul>
-	 * 	<li>This is equivalent to calling <code>setProperty(<jsf>UON_useWhitespace</jsf>, value)</code>.
-	 * 	<li>This introduces a slight performance penalty.
-	 * </ul>
-	 *
-	 * @param value The new value for this property.
-	 * @return This object (for method chaining).
-	 * @throws LockedException If {@link #lock()} was called on this class.
-	 * @see UonSerializerContext#UON_useWhitespace
-	 */
-	public UonSerializer setUseWhitespace(boolean value) throws LockedException {
-		return setProperty(UON_useWhitespace, value);
-	}
-
-	/**
 	 * <b>Configuration property:</b>  Encode non-valid URI characters.
 	 * <p>
 	 * <ul>
@@ -573,8 +409,8 @@ public class UonSerializer extends WriterSerializer {
 	}
 
 	@Override /* Serializer */
-	public UonSerializer setUseIndentation(boolean value) throws LockedException {
-		super.setUseIndentation(value);
+	public UonSerializer setUseWhitespace(boolean value) throws LockedException {
+		super.setUseWhitespace(value);
 		return this;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerContext.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerContext.java
index db0cb2f..65867a5 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerContext.java
@@ -34,80 +34,6 @@ import org.apache.juneau.serializer.*;
 public class UonSerializerContext extends SerializerContext {
 
 	/**
-	 * <b>Configuration property:</b>  Use simplified output.
-	 * <p>
-	 * <ul>
-	 * 	<li><b>Name:</b> <js>"UonSerializer.simpleMode"</js>
-	 * 	<li><b>Data type:</b> <code>Boolean</code>
-	 * 	<li><b>Default:</b> <jk>false</jk>
-	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
-	 * </ul>
-	 * <p>
-	 * If <jk>true</jk>, type flags will not be prepended to values in most cases.
-	 * <p>
-	 * Use this setting if the data types of the values (e.g. object/array/boolean/number/string)
-	 * 	is known on the receiving end.
-	 * <p>
-	 * It should be noted that the default behavior produces a data structure that can
-	 * 	be losslessly converted into JSON, and any JSON can be losslessly represented
-	 * 	in a URL-encoded value.  However, this strict equivalency does not exist
-	 * 	when simple mode is used.
-	 * <p>
-	 * <table class='styled'>
-	 * 	<tr>
-	 * 		<th>Input (in JSON)</th>
-	 * 		<th>Normal mode output</th>
-	 * 		<th>Simple mode output</th>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>{foo:'bar',baz:'bing'}</td>
-	 * 		<td class='code'>$o(foo=bar,baz=bing)</td>
-	 * 		<td class='code'>(foo=bar,baz=bing)</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>{foo:{bar:'baz'}}</td>
-	 * 		<td class='code'>$o(foo=$o(bar=baz))</td>
-	 * 		<td class='code'>(foo=(bar=baz))</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>['foo','bar']</td>
-	 * 		<td class='code'>$a(foo,bar)</td>
-	 * 		<td class='code'>(foo,bar)</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>['foo',['bar','baz']]</td>
-	 * 		<td class='code'>$a(foo,$a(bar,baz))</td>
-	 * 		<td class='code'>(foo,(bar,baz))</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>true</td>
-	 * 		<td class='code'>$b(true)</td>
-	 * 		<td class='code'>true</td>
-	 * 	</tr>
-	 * 	<tr>
-	 * 		<td class='code'>123</td>
-	 * 		<td class='code'>$n(123)</td>
-	 * 		<td class='code'>123</td>
-	 * 	</tr>
-	 * </table>
-	 */
-	public static final String UON_simpleMode = "UonSerializer.simpleMode";
-
-	/**
-	 * <b>Configuration property:</b>  Use whitespace.
-	 * <p>
-	 * <ul>
-	 * 	<li><b>Name:</b> <js>"UonSerializer.useWhitespace"</js>
-	 * 	<li><b>Data type:</b> <code>Boolean</code>
-	 * 	<li><b>Default:</b> <jk>false</jk>
-	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
-	 * </ul>
-	 * <p>
-	 * If <jk>true</jk>, whitespace is added to the output to improve readability.
-	 */
-	public static final String UON_useWhitespace = "UonSerializer.useWhitespace";
-
-	/**
 	 * <b>Configuration property:</b>  Encode non-valid URI characters.
 	 * <p>
 	 * <ul>
@@ -127,8 +53,6 @@ public class UonSerializerContext extends SerializerContext {
 
 
 	final boolean
-		simpleMode,
-		useWhitespace,
 		encodeChars;
 
 	/**
@@ -140,8 +64,6 @@ public class UonSerializerContext extends SerializerContext {
 	 */
 	public UonSerializerContext(ContextFactory cf) {
 		super(cf);
-		simpleMode = cf.getProperty(UON_simpleMode, boolean.class, false);
-		useWhitespace = cf.getProperty(UON_useWhitespace, boolean.class, false);
 		encodeChars = cf.getProperty(UON_encodeChars, boolean.class, false);
 	}
 
@@ -149,8 +71,6 @@ public class UonSerializerContext extends SerializerContext {
 	public ObjectMap asMap() {
 		return super.asMap()
 			.append("UonSerializerContext", new ObjectMap()
-				.append("simpleMode", simpleMode)
-				.append("useWhitespace", useWhitespace)
 				.append("encodeChars", encodeChars)
 			);
 	}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerSession.java
index f758b99..b10f68e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonSerializerSession.java
@@ -28,7 +28,7 @@ import org.apache.juneau.serializer.*;
  */
 public class UonSerializerSession extends SerializerSession {
 
-	private final boolean simpleMode, useWhitespace, encodeChars;
+	private final boolean encodeChars;
 
 	/**
 	 * Create a new session using properties specified in the context.
@@ -48,12 +48,8 @@ public class UonSerializerSession extends SerializerSession {
 	protected UonSerializerSession(UonSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType) {
 		super(ctx, op, output, javaMethod, locale, timeZone, mediaType);
 		if (op == null || op.isEmpty()) {
-			simpleMode = ctx.simpleMode;
-			useWhitespace = ctx.useWhitespace;
 			encodeChars = ctx.encodeChars;
 		} else {
-			simpleMode = op.getBoolean(UON_simpleMode, ctx.simpleMode);
-			useWhitespace = op.getBoolean(UON_useWhitespace, ctx.useWhitespace);
 			encodeChars = op.getBoolean(UON_encodeChars, ctx.encodeChars);
 		}
 	}
@@ -63,25 +59,7 @@ public class UonSerializerSession extends SerializerSession {
 		Object output = getOutput();
 		if (output instanceof UonWriter)
 			return (UonWriter)output;
-		return new UonWriter(this, super.getWriter(), useWhitespace, isSimpleMode(), isEncodeChars(), isTrimStrings(), getRelativeUriBase(), getAbsolutePathUriBase());
-	}
-
-	/**
-	 * Returns the {@link UonSerializerContext#UON_useWhitespace} setting value for this session.
-	 *
-	 * @return The {@link UonSerializerContext#UON_useWhitespace} setting value for this session.
-	 */
-	public final boolean isUseWhitespace() {
-		return useWhitespace;
-	}
-
-	/**
-	 * Returns the {@link UonSerializerContext#UON_simpleMode} setting value for this session.
-	 *
-	 * @return The {@link UonSerializerContext#UON_simpleMode} setting value for this session.
-	 */
-	public final boolean isSimpleMode() {
-		return simpleMode;
+		return new UonWriter(this, super.getWriter(), isUseWhitespace(), isEncodeChars(), isTrimStrings(), getRelativeUriBase(), getAbsolutePathUriBase());
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonWriter.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonWriter.java
index 7025620..bfbe5e0 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UonWriter.java
@@ -28,7 +28,7 @@ import org.apache.juneau.serializer.*;
 public final class UonWriter extends SerializerWriter {
 
 	private final UonSerializerSession session;
-	private final boolean simpleMode, encodeChars;
+	private final boolean encodeChars;
 
 	// Characters that do not need to be URL-encoded in strings.
 	private static final AsciiSet unencodedChars = new AsciiSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;/?:@-_.!*'$(),~=");
@@ -38,10 +38,11 @@ public final class UonWriter extends SerializerWriter {
 	private static final AsciiSet unencodedCharsAttrName = new AsciiSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;/?:@-_.!*'$(),~");
 
 	// Characters that need to be preceeded with an escape character.
-	private static final AsciiSet escapedChars = new AsciiSet(",()~=");
+	private static final AsciiSet escapedChars = new AsciiSet("~'");
 
-	// AsciiSet that maps no characters.
-	private static final AsciiSet emptyCharSet = new AsciiSet("");
+	private static final AsciiSet needsQuoteChars = new AsciiSet("),=\n\t\r\b\f ");
+
+	private static final AsciiSet maybeNeedsQuotesFirstChar = new AsciiSet("),=\n\t\r\b\f tfn+-.#0123456789");
 
 	private static char[] hexArray = "0123456789ABCDEF".toCharArray();
 
@@ -50,17 +51,15 @@ public final class UonWriter extends SerializerWriter {
 	 *
 	 * @param session The session that created this writer.
 	 * @param out The writer being wrapped.
-	 * @param useIndentation If <jk>true</jk>, tabs will be used in output.
-	 * @param simpleMode If <jk>true</jk>, type flags will not be generated in output.
+	 * @param useWhitespace If <jk>true</jk>, tabs will be used in output.
 	 * @param encodeChars If <jk>true</jk>, special characters should be encoded.
 	 * @param trimStrings If <jk>true</jk>, strings should be trimmed before they're serialized.
 	 * @param relativeUriBase The base (e.g. <js>https://localhost:9443/contextPath"</js>) for relative URIs (e.g. <js>"my/path"</js>).
 	 * @param absolutePathUriBase The base (e.g. <js>https://localhost:9443"</js>) for relative URIs with absolute paths (e.g. <js>"/contextPath/my/path"</js>).
 	 */
-	protected UonWriter(UonSerializerSession session, Writer out, boolean useIndentation, boolean simpleMode, boolean encodeChars, boolean trimStrings, String relativeUriBase, String absolutePathUriBase) {
-		super(out, useIndentation, false, trimStrings, '\'', relativeUriBase, absolutePathUriBase);
+	protected UonWriter(UonSerializerSession session, Writer out, boolean useWhitespace, boolean encodeChars, boolean trimStrings, String relativeUriBase, String absolutePathUriBase) {
+		super(out, useWhitespace, trimStrings, '\'', relativeUriBase, absolutePathUriBase);
 		this.session = session;
-		this.simpleMode = simpleMode;
 		this.encodeChars = encodeChars;
 	}
 
@@ -68,46 +67,43 @@ public final class UonWriter extends SerializerWriter {
 	 * Serializes the specified simple object as a UON string value.
 	 *
 	 * @param o The object being serialized.
-	 * @param quoteEmptyStrings Special case where we're serializing an array containing an empty string.
 	 * @param isTopAttrName If this is a top-level attribute name we're serializing.
-	 * @param isTop If this is a top-level value we're serializing.
 	 * @return This object (for method chaining).
 	 * @throws IOException Should never happen.
 	 */
-	protected UonWriter appendObject(Object o, boolean quoteEmptyStrings, boolean isTopAttrName, boolean isTop) throws IOException {
-
-		char typeFlag = 0;
+	protected UonWriter appendObject(Object o, boolean isTopAttrName) throws IOException {
 
+		if (o instanceof Boolean)
+			return appendBoolean(o);
+		if (o instanceof Number)
+			return appendNumber(o);
 		if (o == null)
-			o = "\u0000";
-		else if (o.equals("\u0000"))
-			typeFlag = 's';
+			return append("null");
 
 		String s = session.toString(o);
-//		if (trimStrings)
-//			s = s.trim();
-		if (s.isEmpty()) {
-			if (quoteEmptyStrings)
-				typeFlag = 's';
-		} else if (s.charAt(0) == '(' || s.charAt(0) == '$') {
-			typeFlag = 's';
-		} else if (useIndentation && (s.indexOf('\n') != -1 || (s.charAt(0) <= ' ' && s.charAt(0) != 0))) {
-			// Strings containing newline characters must always be quoted so that they're not confused with whitespace.
-			// Also, strings starting with whitespace must be quoted so that the contents are not ignored when whitespace is ignored.
-			typeFlag = 's';
-		} else if (! simpleMode) {
-			if (o instanceof Boolean)
-				typeFlag = 'b';
-			else if (o instanceof Number)
-				typeFlag = 'n';
-		}
-
-		if (typeFlag != 0)
-			startFlag(typeFlag);
+		char c0 = s.isEmpty() ? 0 : s.charAt(0);
+
+		boolean needsQuotes =
+			s.isEmpty()
+			|| c0 == '@'
+			|| c0 == '('
+			|| needsQuoteChars.contains(s)
+			|| (
+				maybeNeedsQuotesFirstChar.contains(c0)
+				&& (
+					"true".equals(s)
+					|| "false".equals(s)
+					|| "null".equals(s)
+					|| StringUtils.isNumeric(s)
+				)
+			)
+		;
 
 		AsciiSet unenc = (isTopAttrName ? unencodedCharsAttrName : unencodedChars);
-		AsciiSet esc = (isTop && typeFlag == 0 ? emptyCharSet : escapedChars);
+		AsciiSet esc = escapedChars;
 
+		if (needsQuotes)
+			append('\'');
 		for (int i = 0; i < s.length(); i++) {
 			char c = s.charAt(i);
 			if (esc.contains(c))
@@ -135,24 +131,33 @@ public final class UonWriter extends SerializerWriter {
 				}
 			}
 		}
+		if (needsQuotes)
+			append('\'');
 
-		if (typeFlag != 0)
-			append(')');
+		return this;
+	}
 
+	/**
+	 * Appends a boolean value to the output.
+	 *
+	 * @param o The boolean value to append to the output.
+	 * @return This object (for method chaining).
+	 * @throws IOException
+	 */
+	protected UonWriter appendBoolean(Object o) throws IOException {
+		append(o.toString());
 		return this;
 	}
 
 	/**
-	 * Prints <code>$f(</code> in normal mode, and <code>(</code> in simple mode.
+	 * Appends a numeric value to the output.
 	 *
-	 * @param f The flag character.
+	 * @param o The numeric value to append to the output.
 	 * @return This object (for method chaining).
 	 * @throws IOException
 	 */
-	protected UonWriter startFlag(char f) throws IOException {
-		if (f != 's' && ! simpleMode)
-			append('$').append(f);
-		append('(');
+	protected UonWriter appendNumber(Object o) throws IOException {
+		append(o.toString());
 		return this;
 	}
 
@@ -170,11 +175,11 @@ public final class UonWriter extends SerializerWriter {
 	 * Appends a URI to the output.
 	 *
 	 * @param uri The URI to append to the output.
-	 * @param isTop If this is a top-level value we're serializing.
 	 * @return This object (for method chaining).
 	 * @throws IOException
 	 */
-	public SerializerWriter appendUri(Object uri, boolean isTop) throws IOException {
+	@Override
+	public SerializerWriter appendUri(Object uri) throws IOException {
 		String s = uri.toString();
 		if (s.indexOf("://") == -1) {
 			if (StringUtils.startsWith(s, '/')) {
@@ -185,11 +190,10 @@ public final class UonWriter extends SerializerWriter {
 					append(relativeUriBase);
 					if (! relativeUriBase.equals("/"))
 						append("/");
-
 				}
 			}
 		}
-		return appendObject(s, false, false, isTop);
+		return appendObject(s, false);
 	}
 
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
index 460e919..99e28d1 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
@@ -53,9 +53,6 @@ public class UrlEncodingParser extends UonParser {
 	/** Reusable instance of {@link UrlEncodingParser}. */
 	public static final UrlEncodingParser DEFAULT = new UrlEncodingParser().lock();
 
-	/** Reusable instance of {@link UrlEncodingParser}. */
-	public static final UrlEncodingParser DEFAULT_WS_AWARE = new UrlEncodingParser().setWhitespaceAware(true).lock();
-
 	/**
 	 * Constructor.
 	 */
@@ -69,9 +66,8 @@ public class UrlEncodingParser extends UonParser {
 			eType = (ClassMeta<T>)object();
 		PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap();
 		ClassMeta<?> sType = eType.getSerializedClassMeta();
-		BeanRegistry breg = session.getBeanRegistry();
 
-		int c = r.peek();
+		int c = r.peekSkipWs();
 		if (c == '?')
 			r.read();
 
@@ -83,7 +79,7 @@ public class UrlEncodingParser extends UonParser {
 			if (m.containsKey("_value"))
 				o = m.get("_value");
 			else
-				o = breg.cast(m);
+				o = session.cast(m, null, eType);
 		} else if (sType.isMap()) {
 			Map m = (sType.canCreateNewInstance() ? (Map)sType.newInstance() : new ObjectMap(session));
 			o = parseIntoMap(session, r, m, sType.getKeyType(), sType.getValueType());
@@ -97,7 +93,7 @@ public class UrlEncodingParser extends UonParser {
 			ClassMeta<Object> valueType = object();
 			parseIntoMap(session, r, m, string(), valueType);
 			if (m.containsKey(session.getBeanTypePropertyName()))
-				o = breg.cast(m);
+				o = session.cast(m, null, eType);
 			else if (m.containsKey("_value"))
 				o = session.convertToType(m.get("_value"), sType);
 			else if (sType.isCollection()) {
@@ -132,7 +128,7 @@ public class UrlEncodingParser extends UonParser {
 		if (keyType == null)
 			keyType = (ClassMeta<K>)string();
 
-		int c = r.peek();
+		int c = r.peekSkipWs();
 		if (c == -1)
 			return m;
 
@@ -152,7 +148,7 @@ public class UrlEncodingParser extends UonParser {
 						return m;
 					r.unread();
 					Object attr = parseAttr(session, r, true);
-					currAttr = session.trim(session.convertToType(attr, keyType));
+					currAttr = attr == null ? null : convertAttrToType(session, m, session.trim(attr.toString()), keyType);
 					state = S2;
 					c = 0; // Avoid isInEscape if c was '\'
 				} else if (state == S2) {
@@ -213,7 +209,7 @@ public class UrlEncodingParser extends UonParser {
 
 	private <T> BeanMap<T> parseIntoBeanMap(UrlEncodingParserSession session, ParserReader r, BeanMap<T> m) throws Exception {
 
-		int c = r.peek();
+		int c = r.peekSkipWs();
 		if (c == -1)
 			return m;
 
@@ -254,11 +250,7 @@ public class UrlEncodingParser extends UonParser {
 						if (! currAttr.equals(session.getBeanTypePropertyName())) {
 							BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 							if (pMeta == null) {
-								if (m.getMeta().isSubTyped()) {
-									m.put(currAttr, "");
-								} else {
-									onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
-								}
+								onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
 							} else {
 								session.setCurrentProperty(pMeta);
 								// In cases of "&foo=", create an empty instance of the value if createable.
@@ -276,13 +268,8 @@ public class UrlEncodingParser extends UonParser {
 						if (! currAttr.equals(session.getBeanTypePropertyName())) {
 							BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 							if (pMeta == null) {
-								if (m.getMeta().isSubTyped()) {
-									Object value = parseAnything(session, object(), r.unread(), m.getBean(false), true, null);
-									m.put(currAttr, value);
-								} else {
-									onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
-									parseAnything(session, object(), r.unread(), m.getBean(false), true, null); // Read content anyway to ignore it
-								}
+								onUnknownProperty(session, currAttr, m, currAttrLine, currAttrCol);
+								parseAnything(session, object(), r.unread(), m.getBean(false), true, null); // Read content anyway to ignore it
 							} else {
 								session.setCurrentProperty(pMeta);
 								if (session.shouldUseExpandedParams(pMeta)) {
@@ -345,7 +332,7 @@ public class UrlEncodingParser extends UonParser {
 		final int S4=4; // Found valStart, looking for & or end.
 
 		try {
-			int c = r.peek();
+			int c = r.peekSkipWs();
 			if (c == '?')
 				r.read();
 
@@ -531,7 +518,7 @@ public class UrlEncodingParser extends UonParser {
 	protected <K,V> Map<K,V> doParseIntoMap(ParserSession session, Map<K,V> m, Type keyType, Type valueType) throws Exception {
 		UrlEncodingParserSession s = (UrlEncodingParserSession)session;
 		UonReader r = s.getReader();
-		if (r.peek() == '?')
+		if (r.peekSkipWs() == '?')
 			r.read();
 		m = parseIntoMap(s, r, m, (ClassMeta<K>)session.getClassMeta(keyType), (ClassMeta<V>)session.getClassMeta(valueType));
 		return m;
@@ -598,12 +585,6 @@ public class UrlEncodingParser extends UonParser {
 		return this;
 	}
 
-	@Override /* UonParser */
-	public UrlEncodingParser setWhitespaceAware(boolean value) throws LockedException {
-		super.setWhitespaceAware(value);
-		return this;
-	}
-
 	@Override /* Parser */
 	public UrlEncodingParser setTrimStrings(boolean value) throws LockedException {
 		super.setTrimStrings(value);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index 232ce6b..04b64d6 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -76,46 +76,22 @@ import org.apache.juneau.transform.*;
  * 		URL-encoded notation would be as follows:
  * </p>
  * <p class='bcode'>
- * 	<xa>id</xa>=$n(<xs>1</xs>)
- * 	&amp;<xa>name</xa>=<xs>John+Smith</xs>,
- * 	&amp;<xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 	&amp;<xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>,
- * 	&amp;<xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>,
- * 	&amp;<xa>otherIds</xa>=<xs>%00</xs>,
- * 	&amp;<xa>addresses</xa>=$a(
- * 		$o(
- * 			<xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>,
- * 			<xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 			<xa>id</xa>=$n(<xs>1</xs>),
- * 			<xa>street</xa>=<xs>100+Main+Street</xs>,
- * 			<xa>city</xa>=<xs>Anywhereville</xs>,
- * 			<xa>state</xa>=<xs>NY</xs>,
- * 			<xa>zip</xa>=$n(<xs>12345</xs>),
- * 			<xa>isCurrent</xa>=$b(<xs>true</xs>)
- * 		)
- * 	)
- * </p>
- * <p>
- * 	A secondary "lax" syntax is available when the data type of the
- * 		values are already known on the receiving end of the transmission:
- * </p>
- * <p class='bcode'>
- * 	<xa>id</xa>=<xs>1</xs>,
- * 	&amp;<xa>name</xa>=<xs>John+Smith</xs>,
- * 	&amp;<xa>uri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 	&amp;<xa>addressBookUri</xa>=<xs>http://sample/addressBook</xs>,
- * 	&amp;<xa>birthDate</xa>=<xs>1946-08-12T00:00:00Z</xs>,
- * 	&amp;<xa>otherIds</xa>=<xs>%00</xs>,
- * 	&amp;<xa>addresses</xa>=(
+ * 	<ua>id</ua>=<un>1</un>
+ * 	&amp;<ua>name</ua>=<us>'John+Smith'</us>,
+ * 	&amp;<ua>uri</ua>=<us>http://sample/addressBook/person/1</us>,
+ * 	&amp;<ua>addressBookUri</ua>=<us>http://sample/addressBook</us>,
+ * 	&amp;<ua>birthDate</ua>=<us>1946-08-12T00:00:00Z</us>,
+ * 	&amp;<ua>otherIds</ua>=<uk>null</uk>,
+ * 	&amp;<ua>addresses</ua>=@(
  * 		(
- * 			<xa>uri</xa>=<xs>http://sample/addressBook/address/1</xs>,
- * 			<xa>personUri</xa>=<xs>http://sample/addressBook/person/1</xs>,
- * 			<xa>id</xa>=<xs>1</xs>,
- * 			<xa>street</xa>=<xs>100+Main+Street</xs>,
- * 			<xa>city</xa>=<xs>Anywhereville</xs>,
- * 			<xa>state</xa>=<xs>NY</xs>,
- * 			<xa>zip</xa>=<xs>12345</xs>,
- * 			<xa>isCurrent</xa>=<xs>true</xs>
+ * 			<ua>uri</ua>=<us>http://sample/addressBook/address/1</us>,
+ * 			<ua>personUri</ua>=<us>http://sample/addressBook/person/1</us>,
+ * 			<ua>id</ua>=<un>1</un>,
+ * 			<ua>street</ua>=<us>'100+Main+Street'</us>,
+ * 			<ua>city</ua>=<us>Anywhereville</us>,
+ * 			<ua>state</ua>=<us>NY</us>,
+ * 			<ua>zip</ua>=<un>12345</un>,
+ * 			<ua>isCurrent</ua>=<uk>true</uk>
  * 		)
  * 	)
  * </p>
@@ -126,13 +102,9 @@ import org.apache.juneau.transform.*;
  * 	Map m = <jk>new</jk> ObjectMap(<js>"{a:'b',c:1,d:false,e:['f',1,false],g:{h:'i'}}"</js>);
  *
  * 	<jc>// Serialize to value equivalent to JSON.</jc>
- * 	<jc>// Produces "a=b&amp;c=$n(1)&amp;d=$b(false)&amp;e=$a(f,$n(1),$b(false))&amp;g=$o(h=i)"</jc>
+ * 	<jc>// Produces "a=b&amp;c=1&amp;d=false&amp;e=@(f,1,false)&amp;g=(h=i)"</jc>
  * 	String s = UrlEncodingSerializer.<jsf>DEFAULT</jsf>.serialize(s);
  *
- * 	<jc>// Serialize to simplified value (for when data type is already known by receiver).</jc>
- * 	<jc>// Produces "a=b&amp;c=1&amp;d=false&amp;e=(f,1,false)&amp;g=(h=i))"</jc>
- * 	String s = UrlEncodingSerializer.<jsf>DEFAULT_SIMPLE</jsf>.serialize(s);
- *
  * 	<jc>// Serialize a bean</jc>
  * 	<jk>public class</jk> Person {
  * 		<jk>public</jk> Person(String s);
@@ -151,11 +123,8 @@ import org.apache.juneau.transform.*;
  *
  * 	Person p = <jk>new</jk> Person(<js>"John Doe"</js>, 23, <js>"123 Main St"</js>, <js>"Anywhere"</js>, <js>"NY"</js>, 12345, <jk>false</jk>);
  *
- * 	<jc>// Produces "name=John+Doe&amp;age=23&amp;address=$o(street=123+Main+St,city=Anywhere,state=NY,zip=$n(12345))&amp;deceased=$b(false)"</jc>
+ * 	<jc>// Produces "name=John+Doe&amp;age=23&amp;address=(street='123+Main+St',city=Anywhere,state=NY,zip=12345)&amp;deceased=false"</jc>
  * 	String s = UrlEncodingSerializer.<jsf>DEFAULT</jsf>.serialize(s);
- *
- * 	<jc>// Produces "name=John+Doe&amp;age=23&amp;address=(street=123+Main+St,city=Anywhere,state=NY,zip=12345)&amp;deceased=false)"</jc>
- * 	String s = UrlEncodingSerializer.<jsf>DEFAULT_SIMPLE</jsf>.serialize(s);
  * </p>
  */
 @Produces("application/x-www-form-urlencoded")
@@ -165,11 +134,8 @@ public class UrlEncodingSerializer extends UonSerializer {
 	/** Reusable instance of {@link UrlEncodingSerializer}, all default settings. */
 	public static final UrlEncodingSerializer DEFAULT = new UrlEncodingSerializer().lock();
 
-	/** Reusable instance of {@link UrlEncodingSerializer.Simple}. */
-	public static final UrlEncodingSerializer DEFAULT_SIMPLE = new Simple().lock();
-
-	/** Reusable instance of {@link UrlEncodingSerializer.SimpleExpanded}. */
-	public static final UrlEncodingSerializer DEFAULT_SIMPLE_EXPANDED = new SimpleExpanded().lock();
+	/** Reusable instance of {@link UrlEncodingSerializer.Expanded}. */
+	public static final UrlEncodingSerializer DEFAULT_EXPANDED = new Expanded().lock();
 
 	/** Reusable instance of {@link UrlEncodingSerializer.Readable}. */
 	public static final UrlEncodingSerializer DEFAULT_READABLE = new Readable().lock();
@@ -182,23 +148,12 @@ public class UrlEncodingSerializer extends UonSerializer {
 	}
 
 	/**
-	 * Equivalent to <code><jk>new</jk> UrlEncodingSerializer().setSimpleMode(<jk>true</jk>);</code>.
-	 */
-	@Produces(value="application/x-www-form-urlencoded-simple",contentType="application/x-www-form-urlencoded")
-	public static class Simple extends UrlEncodingSerializer {
-		/** Constructor */
-		public Simple() {
-			setSimpleMode(true);
-		}
-	}
-
-	/**
 	 * Equivalent to <code><jk>new</jk> UrlEncodingSerializer().setSimpleMode(<jk>true</jk>).setExpandedParams(<jk>true</jk>);</code>.
 	 */
-	@Produces(value="application/x-www-form-urlencoded-simple",contentType="application/x-www-form-urlencoded")
-	public static class SimpleExpanded extends Simple {
+	@Produces(value="application/x-www-form-urlencoded",contentType="application/x-www-form-urlencoded")
+	public static class Expanded extends UrlEncodingSerializer {
 		/** Constructor */
-		public SimpleExpanded() {
+		public Expanded() {
 			setExpandedParams(true);
 		}
 	}
@@ -220,7 +175,6 @@ public class UrlEncodingSerializer extends UonSerializer {
 	@SuppressWarnings({ "rawtypes", "unchecked" })
 	private SerializerWriter serializeAnything(UrlEncodingSerializerSession session, UonWriter out, Object o) throws Exception {
 
-		boolean addTypeProperty;		// Add "_type" attribute to element?
 		ClassMeta<?> aType;			// The actual type
 		ClassMeta<?> sType;			// The serialized type
 
@@ -230,7 +184,7 @@ public class UrlEncodingSerializer extends UonSerializer {
 			aType = object();
 
 		sType = aType.getSerializedClassMeta();
-		addTypeProperty = (session.isAddBeanTypeProperties());
+		String typeName = session.getBeanTypeName(session.object(), aType, null);
 
 		// Swap if necessary
 		PojoSwap swap = aType.getPojoSwap();
@@ -245,18 +199,18 @@ public class UrlEncodingSerializer extends UonSerializer {
 
 		if (sType.isMap()) {
 			if (o instanceof BeanMap)
-				serializeBeanMap(session, out, (BeanMap)o, addTypeProperty);
+				serializeBeanMap(session, out, (BeanMap)o, typeName);
 			else
 				serializeMap(session, out, (Map)o, sType);
 		} else if (sType.isBean()) {
-			serializeBeanMap(session, out, session.toBeanMap(o), addTypeProperty);
+			serializeBeanMap(session, out, session.toBeanMap(o), typeName);
 		} else if (sType.isCollection()) {
 			serializeMap(session, out, getCollectionMap((Collection)o), session.getClassMeta(Map.class, Integer.class, sType.getElementType()));
 		} else {
 			// All other types can't be serialized as key/value pairs, so we create a
 			// mock key/value pair with a "_value" key.
 			out.append("_value=");
-			super.serializeAnything(session, out, o, null, null, null, false, true);
+			super.serializeAnything(session, out, o, null, null, null);
 		}
 
 		session.pop();
@@ -294,15 +248,15 @@ public class UrlEncodingSerializer extends UonSerializer {
 				while (i.hasNext()) {
 					if (addAmp)
 						out.cr(depth).append('&');
-					out.appendObject(key, false, true, true).append('=');
-					super.serializeAnything(session, out, i.next(), null, (key == null ? null : key.toString()), null, false, true);
+					out.appendObject(key, true).append('=');
+					super.serializeAnything(session, out, i.next(), null, (key == null ? null : key.toString()), null);
 					addAmp = true;
 				}
 			} else {
 				if (addAmp)
 					out.cr(depth).append('&');
-				out.appendObject(key, false, true, true).append('=');
-				super.serializeAnything(session, out, value, valueType, (key == null ? null : key.toString()), null, false, true);
+				out.appendObject(key, true).append('=');
+				super.serializeAnything(session, out, value, valueType, (key == null ? null : key.toString()), null);
 				addAmp = true;
 			}
 		}
@@ -311,12 +265,12 @@ public class UrlEncodingSerializer extends UonSerializer {
 	}
 
 	@SuppressWarnings({ "rawtypes" })
-	private SerializerWriter serializeBeanMap(UrlEncodingSerializerSession session, UonWriter out, BeanMap<?> m, boolean addTypeProperty) throws Exception {
+	private SerializerWriter serializeBeanMap(UrlEncodingSerializerSession session, UonWriter out, BeanMap<?> m, String typeName) throws Exception {
 		int depth = session.getIndent();
 
 		boolean addAmp = false;
 
-		for (BeanPropertyValue p : m.getValues(session.isTrimNulls(), addTypeProperty ? session.createBeanTypeNameProperty(m) : null)) {
+		for (BeanPropertyValue p : m.getValues(session.isTrimNulls(), typeName != null ? session.createBeanTypeNameProperty(m, typeName) : null)) {
 			BeanPropertyMeta pMeta = p.getMeta();
 			ClassMeta<?> cMeta = p.getClassMeta();
 
@@ -337,9 +291,9 @@ public class UrlEncodingSerializer extends UonSerializer {
 					if (addAmp)
 						out.cr(depth).append('&');
 
-					out.appendObject(key, false, true, true).append('=');
+					out.appendObject(key, true).append('=');
 
-					super.serializeAnything(session, out, i.next(), cMeta.getElementType(), key, pMeta, false, true);
+					super.serializeAnything(session, out, i.next(), cMeta.getElementType(), key, pMeta);
 
 					addAmp = true;
 				}
@@ -347,9 +301,9 @@ public class UrlEncodingSerializer extends UonSerializer {
 				if (addAmp)
 					out.cr(depth).append('&');
 
-				out.appendObject(key, false, true, true).append('=');
+				out.appendObject(key, true).append('=');
 
-				super.serializeAnything(session, out, value, cMeta, key, pMeta, false, true);
+				super.serializeAnything(session, out, value, cMeta, key, pMeta);
 
 				addAmp = true;
 			}
@@ -461,18 +415,6 @@ public class UrlEncodingSerializer extends UonSerializer {
 	}
 
 	@Override /* UonSerializer */
-	public UrlEncodingSerializer setSimpleMode(boolean value) throws LockedException {
-		super.setSimpleMode(value);
-		return this;
-	}
-
-	@Override /* UonSerializer */
-	public UrlEncodingSerializer setUseWhitespace(boolean value) throws LockedException {
-		super.setUseWhitespace(value);
-		return this;
-	}
-
-	@Override /* UonSerializer */
 	public UrlEncodingSerializer setEncodeChars(boolean value) throws LockedException {
 		super.setEncodeChars(value);
 		return this;
@@ -503,8 +445,8 @@ public class UrlEncodingSerializer extends UonSerializer {
 	}
 
 	@Override /* Serializer */
-	public UrlEncodingSerializer setUseIndentation(boolean value) throws LockedException {
-		super.setUseIndentation(value);
+	public UrlEncodingSerializer setUseWhitespace(boolean value) throws LockedException {
+		super.setUseWhitespace(value);
 		return this;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_HTML.png
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_HTML.png b/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_HTML.png
index ab74763..04dcf41 100644
Binary files a/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_HTML.png and b/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_HTML.png differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_UrlEncoding.png
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_UrlEncoding.png b/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_UrlEncoding.png
deleted file mode 100644
index 34de8a7..0000000
Binary files a/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/Example_UrlEncoding.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/097b8103/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/rfc_uon.txt
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/rfc_uon.txt b/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/rfc_uon.txt
index 116a509..a78153f 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/rfc_uon.txt
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/doc-files/rfc_uon.txt
@@ -1,7 +1,7 @@
 Network Working Group                                          J. Bognar
-Request for Comments: 9999                                     C. Chaney  
-Category: Informational                                              IBM
-                                                                Jan 2014
+Request for Comments: 9999                                                
+Category: Informational                                       Salesforce
+                                                                Feb 2017
 
                             ***DRAFT***
                URI Object Notation (UON): Generic Syntax
@@ -38,7 +38,8 @@ Abstract
    (Uniform Resource Identifiers).  Its purpose is to define a 
    generalized object notation for URI query parameter values similar in 
    concept to Javascript Object Notation (RFC4627).  The goal is a 
-   syntax such that any data structure defined in JSON can be losslessly 
+   syntax that allows for array and map structures to be
+   such that any data structure defined in JSON can be losslessly 
    defined in an equivalent URI-based grammar, yet be fully compliant 
    with the RFC2396 specification. 
 
@@ -77,32 +78,17 @@ Abstract
             ] 
          } 
 
-      Using the "strict" syntax defined in this document, the equivalent 
+      Using the syntax defined in this document, the equivalent 
       UON notation would be as follows:
 
-         x=$o(id=$n(1),name=John+Smith,uri=http://sample/
-         addressBook/person/1,addressBookUri=http://sample/
-         addressBook,birthDate=1946-08-12T00:00:00Z,otherIds=%00,
-         addresses=$a($o(uri=http://sample/addressBook/
-         address/1,personUri=http://sample/addressBook/
-         person/1,id=$n(1),street=100+Main+Street,city=
-         Anywhereville,state=NY,zip=$n(12345),isCurrent=$b(true)))) 
-
-      A secondary "lax" syntax is available when the data type of the
-      values are already known on the receiving end of the transmission:
-
          x=(id=1,name=John+Smith,uri=http://sample/
          addressBook/person/1,addressBookUri=http://sample/
          addressBook,birthDate=1946-08-12T00:00:00Z,otherIds=%00,
-         addresses=((uri=http://sample/addressBook/
+         addresses=@((uri=http://sample/addressBook/
          address/1,personUri=http://sample/addressBook/
          person/1,id=1,street=100+Main+Street,city=
          Anywhereville,state=NY,zip=12345,isCurrent=true))) 
 
-      Values represented in strict mode can be losslessly converted
-      back and forth into a JSON model without any additional
-      information.  Values represented in lax mode cannot.
-
 1. Language constraints
 
    The grammar syntax is constrained to usage of characters allowed by 
@@ -137,146 +123,97 @@ Abstract
 2.1. Objects 
 
    Objects are values consisting of one or more child name/value pairs.
-   The $o() construct is used to define an object.
+   The (...) construct is used to define an object.
 
    Example:  A simple map with two key/value pairs:
 
-      a1=$o(b1=x1,b2=x2)
+      a1=(b1=x1,b2=x2)
 
    Example:  A nested map:
    
-      a1=$o(b1=$o(c1=x1,c2=x2))
-
-   When the data type is already known to be an object on the receiving 
-   end, then the type flag can be removed from the construct to produce
-   a simplified value. 
-
-   Example:  A nested map using "lax" syntax:
-
-     a1=(b1=(c1=x1,c2=x2))
+      a1=(b1=(c1=x1,c2=x2))
 
 2.2. Arrays
 
    Arrays are values consisting of zero or more child values.
-   The $a() construct is used to define an array.
+   The @(...) construct is used to define an array.
 
    Example:  An array of two string values:
 
-      a1=$a(x1,x2)
+      a1=@(x1,x2)
 
    Example:  A 2-dimensional array:
 
-      a1=$a($a(x1,x2),$a(x3,x4))
+      a1=@(@(x1,x2),@(x3,x4))
 
    Example:  An array of objects:
 
-      a1=$a($o(b1=x1,b2=x2),$o(c1=x1,c2=x2))
-
-   When the data type is already known to be an array on the receiving 
-   end, then the type flag can be removed from the construct to produce
-   a simplified value. 
-   
-   Example:  An array of objects using "lax" syntax:
-
-      a1=((b1=x1,b2=x2),(c1=x1,c2=x2))
+      a1=@((b1=x1,b2=x2),(c1=x1,c2=x2))
 
 2.3. Booleans
 
    Booleans are values that can only take on values "true" or "false".  
-   The $b() construct is used to define a boolean.
    
    Example:  Two boolean values:
 
-      a1=$b(true)&a2=$b(false)
-   
-   When the data type is already known to be a boolean on the receiving 
-   end, then the type flag and parentheses can be removed from the 
-   construct to produce a simplified value. 
-
-   Example:  Two boolean values using "lax" syntax:
-
       a1=true&a2=false
-
+   
 2.4. Numbers
 
-   The $n() construct is used to define a number.
+   Numbers are represented without constructs.
    Both decimal and float numbers are supported.
    
    Example:  Two numerical values, one decimal and one float:
 
-      a1=$n(123)&a2=$n(1.23e1)
-
-   When the data type is already known to be a number on the receiving 
-   end, then the type flag and parentheses can be removed from the 
-   construct to produce a simplified value. 
-   
-   Example:  Two numerical values using "lax" syntax:
-
       a1=123&a2=1.23e1
 
 2.5. Strings
 
-   Anything not conforming to one of the constructs described above 
-   are treated as simple strings.  
-   
-   Example:  A simple string value:
-
-      a1=foobar
+   Strings are encapsulated in single quote (') characters.
    
-   The tilde character (~) is used for escaping characters to prevent 
-   them from being confused with syntax characters.  
-
-   The following characters must be escaped in string literals:  
+   Example:  Simple string values:
 
-      $ , ( ) ~ =
+      a1='foobar'&a2='123'&a3='true'
+         
+   The quotes are optional when the string cannot be confused
+   with one of the constructs listed above (i.e. objects/arrays/
+   booleans/numbers/null). 
    
-   For example, the string literal "$o(b1=x)" should be 
-   represented as follows:
+   Example:  A simple string value, unquoted:
 
-      a1=~$o~(b1~=x~)
-   
-   In addition, strings can optionally be enclosed in parentheses
-   when needed to handle ambiguous cases.
-   
-   The following two values are equivalent:
-   
       a1=foobar
-      a1=(foobar)
+    
+   Strings must be quoted for the following cases:
       
-   Using parentheses, the following construct can be used to represent
-   an empty string:
-   
-      a1=()
+      - The string can be confused with a boolean or number.
+      - The string is empty.
+      - The string contains one or more whitespace characters.
+      - The string starts with one of the following characters:
+        @ (
+      - The string contains any of the following characters:
+        ) , =
    
-   The purpose for this is to handle a potential ambiguity in the 
-   representation of an empty array ([]) vs. an array containing one
-   empty string ([""]).  An array containing one empty string is 
+   For example, the string literal "(b1=x)" should be 
    represented as follows:
 
-      a1=$a(())
-
-   Without this construct, there would not be a way to tell the 
-   difference between an empty array and an array containing an empty    
-   string:
-
-      a1=$a()
+      a1='(b1=x)'
+   
+   The tilde character (~) is used for escaping characters to prevent 
+   them from being confused with syntax characters.  
 
-   Note that an array consisting of two empty strings does not suffer 
-   from this ambiguity, and the use of parenthesis is optional in 
-   this case: 
+   The following characters must be escaped in string literals:  
 
-      a1=$a(,)
+      ' ~
+   
+   Example:  The string "foo'bar~baz"
 
+      a1='foo~'bar~~baz'
+   
 2.7. Null values
 
-   Nulls are represented by ASCII '0' as an escaped hex sequence:
-
-      a1=%00
-
-   Note that a string consisting of a single null character can be 
-   represented with the following construct:
+   Nulls are represented by the keyword 'null':
 
-      a1=(%00)
+      a1=null
 
 2.8. Top-level attribute names
 
@@ -301,7 +238,7 @@ Abstract
    
    The following query strings are fully equivalent in structure:
    
-     a1=$o(b1=x1,b2=x2)
+     a1=(b1='x1',b2='x2')
      %61%31=%24%6F%28%62%31%3D%78%31%2C%62%32%3D%78%32%29
 
 
@@ -313,22 +250,12 @@ Abstract
    attrname    = (string | null)
    value       = (var | string | null)
 
-   string      = ("(" litchar* ")") | litchar*
+   string      = ("'" litchar* "'") | litchar*
    null        = "%00"
    
-   var         = ovar | avar | nvar | bvar
-   ovar        = ovar_strict | ovar_lax
-   avar        = avar_strict | avar_lax
-   nvar        = nvar_strict | nvar_lax
-   bvar        = bvar_strict | bvar_lax
-   ovar_strict = "$o(" [pairs] ")"
-   ovar_lax    =   "(" [pairs] ")"
-   avar_strict = "$a(" [values] ")"
-   avar_lax    =   "(" [values] ")"
-   nvar_strict = "$n(" number ")"
-   nvar_lax    =       number
-   bvar_strict = "$b(" boolean ")" 
-   bvar_lax    =       boolean
+   var         = ovar | avar | nvar | boolean | number
+   ovar        = "(" [pairs] ")"
+   avar        = "@(" [values] ")"
 
    pairs       = pair ["," pairs]
    pair        = key "=" value	
@@ -345,7 +272,7 @@ Abstract
    exp         = "e" [("+" | "-")] digit+
 
    litchar     = unencoded | encode_seq | escape_seq
-   escaped     = "$" | "," | "(" | ")" | "~" | "=" 
+   escaped     = "@" | "," | "(" | ")" | "~" | "=" 
    unencoded   = alpha | digit | 
                  ";" | "/" | "?" | ":" | "@" |
                  "-" | "_" | "." | "!" | "*" | "'"