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 2016/08/01 00:07:58 UTC

[09/51] [partial] incubator-juneau git commit: Initial Juno contents from IBM JazzHub repo

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/UrlEncodingSerializer.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/UrlEncodingSerializer.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/UrlEncodingSerializer.java
new file mode 100755
index 0000000..e4894df
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/UrlEncodingSerializer.java
@@ -0,0 +1,515 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2011, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.urlencoding;
+
+import static com.ibm.juno.core.urlencoding.UonSerializerProperties.*;
+import static com.ibm.juno.core.urlencoding.UrlEncodingProperties.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.annotation.*;
+import com.ibm.juno.core.filter.*;
+import com.ibm.juno.core.serializer.*;
+import com.ibm.juno.core.utils.*;
+
+/**
+ * Serializes POJO models to URL-encoded notation with UON-encoded values (a notation for URL-encoded query paramter values).
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ * 	Handles <code>Accept</code> types: <code>application/x-www-form-urlencoded</code>
+ * <p>
+ * 	Produces <code>Content-Type</code> types: <code>application/x-www-form-urlencoded</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ * 	This serializer provides several serialization options.  Typically, one of the predefined DEFAULT serializers will be sufficient.
+ * 	However, custom serializers can be constructed to fine-tune behavior.
+ *
+ *
+ * <h6 class='topic'>Configurable properties</h6>
+ * <p>
+ * 	This class has the following properties associated with it:
+ * <ul>
+ * 	<li>{@link UonSerializerProperties}
+ * 	<li>{@link SerializerProperties}
+ * 	<li>{@link BeanContextProperties}
+ * </ul>
+ * <p>
+ * 	The following shows a sample object defined in Javascript:
+ * </p>
+ * <p class='bcode'>
+ * 	{
+ * 		id: 1,
+ * 		name: <js>'John Smith'</js>,
+ * 		uri: <js>'http://sample/addressBook/person/1'</js>,
+ * 		addressBookUri: <js>'http://sample/addressBook'</js>,
+ * 		birthDate: <js>'1946-08-12T00:00:00Z'</js>,
+ * 		otherIds: <jk>null</jk>,
+ * 		addresses: [
+ * 			{
+ * 				uri: <js>'http://sample/addressBook/address/1'</js>,
+ * 				personUri: <js>'http://sample/addressBook/person/1'</js>,
+ * 				id: 1,
+ * 				street: <js>'100 Main Street'</js>,
+ * 				city: <js>'Anywhereville'</js>,
+ * 				state: <js>'NY'</js>,
+ * 				zip: 12345,
+ * 				isCurrent: <jk>true</jk>,
+ * 			}
+ * 		]
+ * 	}
+ * </p>
+ * <p>
+ * 	Using the "strict" syntax defined in this document, the equivalent
+ * 		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>=(
+ * 		(
+ * 			<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>
+ * 		)
+ * 	)
+ * </p>
+ *
+ *
+ * <h6 class='topic'>Examples</h6>
+ * <p class='bcode'>
+ * 	<jc>// Serialize a Map</jc>
+ * 	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>
+ * 	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);
+ * 		<jk>public</jk> String getName();
+ * 		<jk>public int</jk> getAge();
+ * 		<jk>public</jk> Address getAddress();
+ * 		<jk>public boolean</jk> deceased;
+ * 	}
+ *
+ * 	<jk>public class</jk> Address {
+ * 		<jk>public</jk> String getStreet();
+ * 		<jk>public</jk> String getCity();
+ * 		<jk>public</jk> String getState();
+ * 		<jk>public int</jk> getZip();
+ * 	}
+ *
+ * 	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>
+ * 	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>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+@Produces("application/x-www-form-urlencoded")
+@SuppressWarnings("hiding")
+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.Readable}. */
+	public static final UrlEncodingSerializer DEFAULT_READABLE = new Readable().lock();
+
+	/**
+	 * Constructor.
+	 */
+	public UrlEncodingSerializer() {
+		setProperty(UON_encodeChars, true);
+	}
+
+	/**
+	 * Equivalent to <code><jk>new</jk> UrlEncodingSerializer().setProperty(UonSerializerProperties.<jsf>UON_simpleMode</jsf>,<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() {
+			setProperty(UON_simpleMode, true);
+		}
+	}
+
+	/**
+	 * Equivalent to <code><jk>new</jk> UrlEncodingSerializer().setProperty(UonSerializerProperties.<jsf>UON_simpleMode</jsf>,<jk>true</jk>).setProperty(UonSerializerProperties.<jsf>URLENC_expandedParams</jsf>,<jk>true</jk>);</code>.
+	 */
+	@Produces(value={"application/x-www-form-urlencoded-simple"},contentType="application/x-www-form-urlencoded")
+	public static class SimpleExpanded extends Simple {
+		/** Constructor */
+		public SimpleExpanded() {
+			setProperty(URLENC_expandedParams, true);
+		}
+	}
+
+	/**
+	 * Equivalent to <code><jk>new</jk> UrlEncodingSerializer().setProperty(UonSerializerProperties.<jsf>UON_useWhitespace</jsf>,<jk>true</jk>);</code>.
+	 */
+	public static class Readable extends UrlEncodingSerializer {
+		/** Constructor */
+		public Readable() {
+			setProperty(UON_useWhitespace, true);
+		}
+	}
+
+	/**
+	 * Workhorse method. Determines the type of object, and then calls the
+	 * appropriate type-specific serialization method.
+	 */
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	private SerializerWriter serializeAnything(UonSerializerWriter out, Object o, UonSerializerContext ctx) throws SerializeException {
+		try {
+
+			BeanContext bc = ctx.getBeanContext();
+
+			boolean addClassAttr;		// Add "_class" attribute to element?
+			ClassMeta<?> aType;			// The actual type
+			ClassMeta<?> gType;			// The generic type
+
+			aType = ctx.push("root", o, object());
+			ctx.indent--;
+			if (aType == null)
+				aType = object();
+
+			gType = aType.getFilteredClassMeta();
+			addClassAttr = (ctx.isAddClassAttrs());
+
+			// Filter if necessary
+			PojoFilter filter = aType.getPojoFilter();				// The filter
+			if (filter != null) {
+				o = filter.filter(o);
+
+				// If the filter's getFilteredClass() method returns Object, we need to figure out
+				// the actual type now.
+				if (gType.isObject())
+					gType = bc.getClassMetaForObject(o);
+			}
+
+			if (gType.isMap()) {
+				if (o instanceof BeanMap)
+					serializeBeanMap(out, (BeanMap)o, addClassAttr, ctx);
+				else
+					serializeMap(out, (Map)o, gType, ctx);
+			} else if (gType.hasToObjectMapMethod()) {
+				serializeMap(out, gType.toObjectMap(o), gType, ctx);
+			} else if (gType.isBean()) {
+				serializeBeanMap(out, bc.forBean(o), addClassAttr, ctx);
+			} else if (gType.isCollection()) {
+				serializeMap(out, getCollectionMap((Collection)o), bc.getMapClassMeta(Map.class, Integer.class, gType.getElementType()), ctx);
+			} 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(out, o, null, ctx, null, null, false, true);
+			}
+
+			ctx.pop();
+			return out;
+		} catch (SerializeException e) {
+			throw e;
+		} catch (StackOverflowError e) {
+			throw e;
+		} catch (Throwable e) {
+			throw new SerializeException("Exception occurred trying to process object of type ''{0}''", (o == null ? null : o.getClass().getName())).initCause(e);
+		}
+	}
+
+	private Map<Integer,Object> getCollectionMap(Collection<?> c) {
+		Map<Integer,Object> m = new TreeMap<Integer,Object>();
+		int i = 0;
+		for (Object o : c)
+			m.put(i++, o);
+		return m;
+	}
+
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	private SerializerWriter serializeMap(UonSerializerWriter out, Map m, ClassMeta<?> type, UonSerializerContext ctx) throws IOException, SerializeException {
+
+		m = sort(ctx, m);
+
+		ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType();
+
+		int depth = ctx.getIndent();
+		boolean addAmp = false;
+
+		Iterator mapEntries = m.entrySet().iterator();
+
+		while (mapEntries.hasNext()) {
+			Map.Entry e = (Map.Entry) mapEntries.next();
+			Object value = e.getValue();
+			Object key = generalize(ctx, e.getKey(), keyType);
+
+
+			if (shouldUseExpandedParams(value, ctx)) {
+				Iterator i = value instanceof Collection ? ((Collection)value).iterator() : ArrayUtils.iterator(value);
+				while (i.hasNext()) {
+					if (addAmp)
+						out.cr(depth).append('&');
+					out.appendObject(key, false, true, true).append('=');
+					super.serializeAnything(out, i.next(), null, ctx, (key == null ? null : key.toString()), null, false, true);
+					addAmp = true;
+				}
+			} else {
+				if (addAmp)
+					out.cr(depth).append('&');
+			out.appendObject(key, false, true, true).append('=');
+			super.serializeAnything(out, value, valueType, ctx, (key == null ? null : key.toString()), null, false, true);
+				addAmp = true;
+			}
+		}
+
+		return out;
+	}
+
+	@SuppressWarnings({ "rawtypes" })
+	private SerializerWriter serializeBeanMap(UonSerializerWriter out, BeanMap m, boolean addClassAttr, UonSerializerContext ctx) throws IOException, SerializeException {
+		int depth = ctx.getIndent();
+
+		Iterator mapEntries = m.entrySet().iterator();
+
+		// Print out "_class" attribute on this bean if required.
+		if (addClassAttr) {
+			String attr = "_class";
+			out.appendObject(attr, false, false, true).append('=').append(m.getClassMeta().getInnerClass().getName());
+			if (mapEntries.hasNext())
+				out.cr(depth).append('&');
+		}
+
+		boolean addAmp = false;
+
+		while (mapEntries.hasNext()) {
+			BeanMapEntry p = (BeanMapEntry)mapEntries.next();
+			BeanPropertyMeta pMeta = p.getMeta();
+
+			String key = p.getKey();
+			Object value = null;
+			try {
+				value = p.getValue();
+			} catch (StackOverflowError e) {
+				throw e;
+			} catch (Throwable t) {
+				ctx.addBeanGetterWarning(pMeta, t);
+			}
+
+			if (canIgnoreValue(ctx, pMeta.getClassMeta(), key, value))
+				continue;
+
+			if (value != null && shouldUseExpandedParams(pMeta, ctx)) {
+				ClassMeta cm = pMeta.getClassMeta();
+				// Filtered object array bean properties may be filtered resulting in ArrayLists,
+				// so we need to check type if we think it's an array.
+				Iterator i = (cm.isCollection() || value instanceof Collection) ? ((Collection)value).iterator() : ArrayUtils.iterator(value);
+				while (i.hasNext()) {
+					if (addAmp)
+						out.cr(depth).append('&');
+
+					out.appendObject(key, false, true, true).append('=');
+
+					super.serializeAnything(out, i.next(), pMeta.getClassMeta().getElementType(), ctx, key, pMeta, false, true);
+
+					addAmp = true;
+				}
+			} else {
+				if (addAmp)
+					out.cr(depth).append('&');
+
+				out.appendObject(key, false, true, true).append('=');
+
+				super.serializeAnything(out, value, pMeta.getClassMeta(), ctx, key, pMeta, false, true);
+
+				addAmp = true;
+			}
+
+		}
+		return out;
+	}
+
+	/**
+	 * Returns true if the specified bean property should be expanded as multiple key-value pairs.
+	 */
+	private final boolean shouldUseExpandedParams(BeanPropertyMeta<?> pMeta, UonSerializerContext ctx) {
+		ClassMeta<?> cm = pMeta.getClassMeta();
+		if (cm.isArray() || cm.isCollection()) {
+			if (ctx.isExpandedParams())
+				return true;
+			if (pMeta.getBeanMeta().getClassMeta().getUrlEncodingMeta().isExpandedParams())
+				return true;
+		}
+		return false;
+	}
+
+	private final boolean shouldUseExpandedParams(Object value, UonSerializerContext ctx) {
+		if (value == null)
+			return false;
+		ClassMeta<?> cm = ctx.getBeanContext().getClassMetaForObject(value).getFilteredClassMeta();
+		if (cm.isArray() || cm.isCollection()) {
+			if (ctx.isExpandedParams())
+				return true;
+		}
+		return false;
+	}
+
+	//--------------------------------------------------------------------------------
+	// Methods for constructing individual parameter values.
+	//--------------------------------------------------------------------------------
+
+	/**
+	 * Converts the specified object to a string using this serializers {@link BeanContext#convertToType(Object, Class)} method
+	 * 	and runs {@link URLEncoder#encode(String,String)} against the results.
+	 * Useful for constructing URL parts.
+	 *
+	 * @param o The object to serialize.
+	 * @return The serialized object.
+	 */
+	public String serializeUrlPart(Object o) {
+		try {
+			// Shortcut for simple types.
+			ClassMeta<?> cm = getBeanContext().getClassMetaForObject(o);
+			if (cm != null)
+				if (cm.isCharSequence() || cm.isNumber() || cm.isBoolean())
+					return o.toString();
+
+			UonSerializerContext uctx = createContext(null, null);
+			StringWriter w = new StringWriter();
+			super.doSerialize(o, w, uctx);
+			return w.toString();
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+
+	//--------------------------------------------------------------------------------
+	// Overridden methods
+	//--------------------------------------------------------------------------------
+
+	@Override /* Serializer */
+	public UonSerializerContext createContext(ObjectMap properties, Method javaMethod) {
+		return new UonSerializerContext(getBeanContext(), sp, usp, uep, properties, javaMethod);
+	}
+
+	@Override /* Serializer */
+	protected void doSerialize(Object o, Writer out, SerializerContext ctx) throws IOException, SerializeException {
+		UonSerializerContext uctx = (UonSerializerContext)ctx;
+		serializeAnything(uctx.getWriter(out), o, uctx);
+	}
+
+	@Override /* CoreApi */
+	public UrlEncodingSerializer setProperty(String property, Object value) throws LockedException {
+		checkLock();
+		if (! usp.setProperty(property, value))
+			if (! uep.setProperty(property, value))
+				super.setProperty(property, value);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public UrlEncodingSerializer setProperties(ObjectMap properties) throws LockedException {
+		for (Map.Entry<String,Object> e : properties.entrySet())
+			setProperty(e.getKey(), e.getValue());
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public UrlEncodingSerializer addNotBeanClasses(Class<?>...classes) throws LockedException {
+		super.addNotBeanClasses(classes);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public UrlEncodingSerializer addFilters(Class<?>...classes) throws LockedException {
+		super.addFilters(classes);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public <T> UrlEncodingSerializer addImplClass(Class<T> interfaceClass, Class<? extends T> implClass) throws LockedException {
+		super.addImplClass(interfaceClass, implClass);
+		return this;
+	}
+
+	@Override /* CoreApi */
+	public UrlEncodingSerializer setClassLoader(ClassLoader classLoader) throws LockedException {
+		super.setClassLoader(classLoader);
+		return this;
+	}
+
+	@Override /* Lockable */
+	public UrlEncodingSerializer lock() {
+		super.lock();
+		return this;
+	}
+
+	@Override /* Lockable */
+	public UrlEncodingSerializer clone() {
+		UrlEncodingSerializer c = (UrlEncodingSerializer)super.clone();
+		c.usp = usp.clone();
+		c.uep = uep.clone();
+		return c;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.class
new file mode 100755
index 0000000..84e2638
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.java
new file mode 100755
index 0000000..d0870ad
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/UrlEncoding.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core.urlencoding.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import com.ibm.juno.core.urlencoding.*;
+
+/**
+ * Annotation that can be applied to classes, fields, and methods to tweak how
+ * they are handled by {@link UrlEncodingSerializer} and {@link UrlEncodingParser}.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+@Documented
+@Target({TYPE})
+@Retention(RUNTIME)
+@Inherited
+public @interface UrlEncoding {
+
+	/**
+	 * When true, bean properties of type array or Collection will be expanded into multiple key=value pairings.
+	 * <p>
+	 * This annotation is identical in behavior to using the {@link UrlEncodingProperties#URLENC_expandedParams} 
+	 * property, but applies to only instances of this bean.  
+	 */
+	boolean expandedParams() default false;
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/package.html
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/package.html b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/package.html
new file mode 100755
index 0000000..806eadb
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/annotation/package.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<!--
+    Licensed Materials - Property of IBM
+    (c) Copyright IBM Corporation 2015 All Rights Reserved.
+   
+    Note to U.S. Government Users Restricted Rights:  
+    Use, duplication or disclosure restricted by GSA ADP Schedule 
+    Contract with IBM Corp. 
+ -->
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<style type="text/css">
+		/* For viewing in Page Designer */
+		@IMPORT url("../../../../../../../javadoc.css");
+
+		/* For viewing in REST interface */
+		@IMPORT url("../htdocs/javadoc.css");
+		body { 
+			margin: 20px; 
+		}	
+	</style>
+	<script>
+		/* Replace all @code and @link tags. */	
+		window.onload = function() {
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>');
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>');
+		}
+	</script>
+</head>
+<body>
+<p>URL-Encoding annotations</p>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_HTML.png
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_HTML.png b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_HTML.png
new file mode 100755
index 0000000..ab74763
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_HTML.png differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_UrlEncoding.png
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_UrlEncoding.png b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_UrlEncoding.png
new file mode 100755
index 0000000..34de8a7
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/Example_UrlEncoding.png differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/rfc_uon.txt
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/rfc_uon.txt b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/rfc_uon.txt
new file mode 100755
index 0000000..c79c9c5
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/urlencoding/doc-files/rfc_uon.txt
@@ -0,0 +1,352 @@
+Network Working Group                                          J. Bognar
+Request for Comments: 9999                                     C. Chaney  
+Category: Informational                                              IBM
+                                                                Jan 2014
+
+                            ***DRAFT***
+               URI Object Notation (UON): Generic Syntax
+
+
+About this document
+
+   This memo provides information for the Internet community.  It does
+   not specify an Internet standard of any kind.  Distribution of this
+   memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) IBM Corp. 2014.  All Rights Reserved.
+
+Abstract
+
+   This document describes a grammar that builds upon RFC2396
+   (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 
+   defined in an equivalent URI-based grammar, yet be fully compliant 
+   with the RFC2396 specification. 
+
+   This grammar provides the ability to construct the following data 
+   structures in URL parameter values: 
+	
+      OBJECT
+      ARRAY
+      NUMBER
+      BOOLEAN
+      STRING
+      NULL
+
+   Example:
+
+      The following shows a sample object defined in Javascript:
+
+         var x = { 
+            id: 1, 
+            name: 'John Smith', 
+            uri: 'http://sample/addressBook/person/1', 
+            addressBookUri: 'http://sample/addressBook', 
+            birthDate: '1946-08-12T00:00:00Z', 
+            otherIds: null,
+            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,
+               } 
+            ] 
+         } 
+
+      Using the "strict" 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/
+         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 
+      URI notation:
+
+      uric       = reserved | unreserved | escaped
+      reserved   = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+                   "$" | ","
+      unreserved = alphanum | mark
+      mark       = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+
+   In particular, the URI specification disallows the following 
+   characters in unencoded form:
+
+      unwise     = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
+      delims     = "<" | ">" | "#" | "%" | <">
+
+   The exclusion of {} and [] characters eliminates the possibility of 
+   using JSON as parameter values.
+
+
+2. Grammar constructs
+
+   The grammar consists of the following language constructs:
+   
+      Objects - Values consisting of one or more child name/value pairs.
+      Arrays - Values consisting of zero or more child values.
+      Booleans - Values consisting of true/false values.
+      Numbers - Decimal and floating point values.
+      Strings - Everything else.
+
+2.1. Objects 
+
+   Objects are values consisting of one or more child name/value pairs.
+   The $o() construct is used to define an object.
+
+   Example:  A simple map with two key/value pairs:
+
+      a1=$o(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))
+
+2.2. Arrays
+
+   Arrays are values consisting of zero or more child values.
+   The $a() construct is used to define an array.
+
+   Example:  An array of two string values:
+
+      a1=$a(x1,x2)
+
+   Example:  A 2-dimensional array:
+
+      a1=$a($a(x1,x2),$a(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))
+
+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.
+   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
+   
+   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:  
+
+      $ , ( ) ~ =
+   
+   For example, the string literal "$o(b1=x)" should be 
+   represented as follows:
+
+      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)
+      
+   Using parentheses, the following construct can be used to represent
+   an empty string:
+   
+      a1=()
+   
+   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 
+   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()
+
+   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: 
+
+      a1=$a(,)
+
+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:
+
+      a1=(%00)
+
+2.8. Top-level attribute names
+
+   Top-level attribute names (e.g. "a1" in "&a1=foobar") are treated
+   as strings but for one exception.  The '=' character must be
+   encoded so as not to be confused as a key/value separator.
+   Note that the '=' character must also be escaped per the UON
+   notation.
+   
+   For example, the UON equivalent of {"a=b":"a=b"} constructed as
+   a top-level query parameter string would be as follows:
+   
+      a~%3Db=a~=b
+      
+   Note that the '=' character is encoded in the attribute name,
+   but it is not necessary to have it encoded in the attribute value.
+
+2.9. URL-encoded characters
+
+   UON notation allows for any character, even UON grammar
+   characters, to be URL-encoded.
+   
+   The following query strings are fully equivalent in structure:
+   
+     a1=$o(b1=x1,b2=x2)
+     %61%31=%24%6F%28%62%31%3D%78%31%2C%62%32%3D%78%32%29
+
+
+3. BNF
+
+   The following BNF describes the syntax for top-level URI query 
+   parameter values (e.g. ?<attrname>=<value>).
+
+   attrname    = (string | null)
+   value       = (var | string | null)
+
+   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
+
+   pairs       = pair ["," pairs]
+   pair        = key "=" value	
+   values      = value ["," values]
+   key         = (string | null)
+   boolean     = "true" | "false"
+
+   escape_seq  = "~" escaped
+   encode_seq  = "%" digithex digithex
+
+   number      = [-] (decimal | float) [exp]
+   decimal     = "0" | (digit19 digit*)
+   float       = decimal "." digit+
+   exp         = "e" [("+" | "-")] digit+
+
+   litchar     = unencoded | encode_seq | escape_seq
+   escaped     = "$" | "," | "(" | ")" | "~" | "=" 
+   unencoded   = alpha | digit | 
+                 ";" | "/" | "?" | ":" | "@" |
+                 "-" | "_" | "." | "!" | "*" | "'" 
+   alpha       = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+                 "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+                 "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" |
+                 "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |             
+                 "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+                 "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+   digit       = "0" | digit19
+   digit19     = "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+                 "8" | "9"
+   digithex    = digit | 
+                 "A" | "B" | "C" | "D" | "E" | "F" |
+                 "a" | "b" | "c" | "d" | "e" | "f"
+
+
+
+