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>) - * &<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> * ) * ) * </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&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 = 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&c=1&d=false&e=(f,1,false)&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&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 = UrlEncodingSerializer.<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 = 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 | ";" | "/" | "?" | ":" | "@" | "-" | "_" | "." | "!" | "*" | "'"