http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeOutputStream.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeOutputStream.java
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeOutputStream.java
new file mode 100755
index 0000000..70807a8
--- /dev/null
+++ 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeOutputStream.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Output stream that can send output to multiple output streams.
+ *
+ * @author James Bognar ([email protected])
+ */
+public class TeeOutputStream extends OutputStream {
+       private OutputStream[] outputStreams = new OutputStream[0];
+       private Map<String,OutputStream> outputStreamMap;
+
+       /**
+        * Constructor.
+        *
+        * @param outputStreams The list of output streams.
+        */
+       public TeeOutputStream(OutputStream...outputStreams) {
+               this.outputStreams = outputStreams;
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param outputStreams The list of output streams.
+        */
+       public TeeOutputStream(Collection<OutputStream> outputStreams) {
+               this.outputStreams = outputStreams.toArray(new 
OutputStream[outputStreams.size()]);
+       }
+
+       /**
+        * Adds an output stream to this tee output stream.
+        *
+        * @param os The output stream to add to this tee output stream.
+        * @param close If <jk>false</jk>, then calling {@link #close()} on 
this stream
+        *      will not filter to the specified output stream.
+        * @return This object (for method chaining).
+        */
+       public TeeOutputStream add(OutputStream os, boolean close) {
+               if (os == null)
+                       return this;
+               if (! close)
+                       os = new NoCloseOutputStream(os);
+               if (os == this)
+                       throw new RuntimeException("Cannot add this output 
stream to itself.");
+               for (OutputStream os2 : outputStreams)
+                       if (os2 == os)
+                               throw new RuntimeException("Cannot add this 
output stream again.");
+               if (os instanceof TeeOutputStream) {
+                       for (OutputStream os2 : 
((TeeOutputStream)os).outputStreams)
+                               add(os2, true);
+               } else {
+                       outputStreams = ArrayUtils.append(outputStreams, os);
+               }
+               return this;
+       }
+
+       /**
+        * Returns the output stream identified through the <code>id</code> 
parameter
+        * passed in through the {@link #add(String, OutputStream, boolean)} 
method.
+        *
+        * @param id The ID associated with the output stream.
+        * @return The output stream, or <jk>null</jk> if no identifier was 
specified when the output stream was added.
+        */
+       public OutputStream getOutputStream(String id) {
+               if (outputStreamMap != null)
+                       return outputStreamMap.get(id);
+               return null;
+       }
+
+       /**
+        * Same as {@link #add(OutputStream, boolean)} but associates the 
stream with an identifier
+        * so the stream can be retrieved through {@link 
#getOutputStream(String)}.
+        *
+        * @param id The ID to associate the output stream with.
+        * @param os The output stream to add.
+        * @param close Close the specified stream afterwards.
+        * @return This object (for method chaining).
+        */
+       public TeeOutputStream add(String id, OutputStream os, boolean close) {
+               if (id != null) {
+                       if (outputStreamMap == null)
+                               outputStreamMap = new 
TreeMap<String,OutputStream>();
+                       outputStreamMap.put(id, os);
+               }
+               return add(os, close);
+       }
+
+       /**
+        * Returns the number of inner streams in this tee stream.
+        *
+        * @return The number of streams in this tee stream.
+        */
+       public int size() {
+               return outputStreams.length;
+       }
+
+       @Override /* OutputStream */
+       public void write(int b) throws IOException {
+               for (OutputStream os : outputStreams)
+                       os.write(b);
+       }
+
+       @Override /* OutputStream */
+       public void write(byte b[], int off, int len) throws IOException {
+               for (OutputStream os : outputStreams)
+                       os.write(b, off, len);
+       }
+
+       @Override /* OutputStream */
+       public void flush() throws IOException {
+               for (OutputStream os : outputStreams)
+                       os.flush();
+       }
+
+       @Override /* OutputStream */
+       public void close() throws IOException {
+               for (OutputStream os : outputStreams)
+                       os.close();
+       }
+
+       private static class NoCloseOutputStream extends OutputStream {
+               private OutputStream os;
+
+               private NoCloseOutputStream(OutputStream os) {
+                       this.os = os;
+               }
+
+               @Override /* OutputStream */
+               public void write(int b) throws IOException {
+                       os.write(b);
+               }
+
+               @Override /* OutputStream */
+               public void write(byte b[], int off, int len) throws 
IOException {
+                       os.write(b, off, len);
+               }
+
+               @Override /* OutputStream */
+               public void flush() throws IOException {
+                       os.flush();
+               }
+
+               @Override /* OutputStream */
+               public void close() throws IOException {
+                       // Do nothing.
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter$1.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter$1.class 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter$1.class
new file mode 100755
index 0000000..caa1961
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter$1.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/utils/TeeWriter$NoCloseWriter.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter$NoCloseWriter.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter$NoCloseWriter.class
new file mode 100755
index 0000000..fc76e14
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter$NoCloseWriter.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/utils/TeeWriter.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter.class 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter.class
new file mode 100755
index 0000000..b5702ac
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter.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/utils/TeeWriter.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter.java
new file mode 100755
index 0000000..f01c3cd
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/TeeWriter.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * Writer that can send output to multiple writers.
+ *
+ * @author James Bognar ([email protected])
+ */
+public class TeeWriter extends Writer {
+       private Writer[] writers = new Writer[0];
+       private Map<String,Writer> writerMap;
+
+       /**
+        * Constructor.
+        *
+        * @param writers The list of writers.
+        */
+       public TeeWriter(Writer...writers) {
+               this.writers = writers;
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param writers The list of writers.
+        */
+       public TeeWriter(Collection<Writer> writers) {
+               this.writers = writers.toArray(new Writer[writers.size()]);
+       }
+
+       /**
+        * Adds a writer to this tee writer.
+        *
+        * @param w The writer to add to this tee writer.
+        * @param close If <jk>false</jk>, then calling {@link #close()} on 
this tee writer
+        *      will not filter to the specified writer.
+        * @return This object (for method chaining).
+        */
+       public TeeWriter add(Writer w, boolean close) {
+               if (w == null)
+                       return this;
+               if (! close)
+                       w = new NoCloseWriter(w);
+               if (w == this)
+                       throw new RuntimeException("Cannot add this writer to 
itself.");
+               for (Writer w2 : writers)
+                       if (w2 == w)
+                               throw new RuntimeException("Cannot add this 
writer again.");
+               if (w instanceof TeeWriter) {
+                       for (Writer w2 : ((TeeWriter)w).writers)
+                               add(w2, true);
+               } else {
+                       writers = ArrayUtils.append(writers, w);
+               }
+               return this;
+       }
+
+       /**
+        * Same as {@link #add(Writer, boolean)} but associates the writer with 
an identifier
+        * so the writer can be retrieved through {@link #getWriter(String)}.
+        *
+        * @param id The ID to associate the writer with.
+        * @param w The writer to add.
+        * @param close Close the specified writer afterwards.
+        * @return This object (for method chaining).
+        */
+       public TeeWriter add(String id, Writer w, boolean close) {
+               if (id != null) {
+                       if (writerMap == null)
+                               writerMap = new TreeMap<String,Writer>();
+                       writerMap.put(id, w);
+               }
+               return add(w, close);
+       }
+
+       /**
+        * Returns the number of inner writers in this tee writer.
+        *
+        * @return The number of writers.
+        */
+       public int size() {
+               return writers.length;
+       }
+
+       /**
+        * Returns the writer identified through the <code>id</code> parameter
+        * passed in through the {@link #add(String, Writer, boolean)} method.
+        *
+        * @param id The ID associated with the writer.
+        * @return The writer, or <jk>null</jk> if no identifier was specified 
when the writer was added.
+        */
+       public Writer getWriter(String id) {
+               if (writerMap != null)
+                       return writerMap.get(id);
+               return null;
+       }
+
+       @Override /* Writer */
+       public void write(char[] cbuf, int off, int len) throws IOException {
+               for (Writer w : writers)
+                       if (w != null)
+                       w.write(cbuf, off, len);
+       }
+
+       @Override /* Writer */
+       public void flush() throws IOException {
+               for (Writer w : writers)
+                       if (w != null)
+                       w.flush();
+       }
+
+       @Override /* Writer */
+       public void close() throws IOException {
+               IOException e = null;
+               for (Writer w : writers) {
+                       if (w != null) {
+                               try {
+                       w.close();
+                               } catch (IOException e2) {
+                                       e = e2;
+                               }
+                       }
+               }
+               if (e != null)
+                       throw e;
+       }
+
+       private static class NoCloseWriter extends Writer {
+               private Writer writer;
+
+               private NoCloseWriter(Writer writer) {
+                       this.writer = writer;
+               }
+
+               @Override /* Writer */
+               public void write(char[] cbuf, int off, int len) throws 
IOException {
+                       writer.write(cbuf, off, len);
+               }
+
+               @Override /* Writer */
+               public void flush() throws IOException {
+                       writer.flush();
+               }
+
+               @Override /* Writer */
+               public void close() throws IOException {
+                       // Do nothing.
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ThrowableUtils.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ThrowableUtils.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ThrowableUtils.class
new file mode 100755
index 0000000..55805dd
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ThrowableUtils.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/utils/ThrowableUtils.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ThrowableUtils.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ThrowableUtils.java
new file mode 100755
index 0000000..d2b25ae
--- /dev/null
+++ 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ThrowableUtils.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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.utils;
+
+import java.text.*;
+
+/**
+ * Various utility methods for creating and working with throwables.
+ *
+ * @author James Bognar ([email protected])
+ */
+public class ThrowableUtils {
+
+       /**
+        * Throws an {@link IllegalArgumentException} if the specified object 
is <jk>null</jk>.
+        *
+        * @param o The object to check.
+        * @param msg The message of the IllegalArgumentException.
+        * @param args {@link MessageFormat}-style arguments in the message.
+        * @throws IllegalArgumentException
+        */
+       public static void assertNotNull(Object o, String msg, Object...args) 
throws IllegalArgumentException {
+               if (o == null)
+                       throw new 
IllegalArgumentException(MessageFormat.format(msg, args));
+       }
+
+       /**
+        * Throws an {@link IllegalArgumentException} if the specified field is 
<jk>null</jk>.
+        *
+        * @param fieldValue The object to check.
+        * @param fieldName The name of the field.
+        * @throws IllegalArgumentException
+        */
+       public static void assertFieldNotNull(Object fieldValue, String 
fieldName) throws IllegalArgumentException {
+               if (fieldValue == null)
+                       throw new IllegalArgumentException("Field '" + 
fieldName + "' cannot be null.");
+       }
+
+       /**
+        * Throws an {@link IllegalArgumentException} if the specified field is 
<code>&lt;=0</code>.
+        *
+        * @param fieldValue The object to check.
+        * @param fieldName The name of the field.
+        * @throws IllegalArgumentException
+        */
+       public static void assertFieldPositive(int fieldValue, String 
fieldName) throws IllegalArgumentException {
+               if (fieldValue <= 0)
+                       throw new IllegalArgumentException("Field '" + 
fieldName + "' must be a positive integer.");
+       }
+
+       /**
+        * Shortcut for calling <code><jk>new</jk> 
IllegalArgumentException(MessageFormat.<jsm>format</jsm>(msg, args));</code>
+        *
+        * @param msg The message of the IllegalArgumentException.
+        * @param args {@link MessageFormat}-style arguments in the message.
+        * @throws IllegalArgumentException
+        */
+       public static void illegalArg(String msg, Object...args) throws 
IllegalArgumentException {
+               throw new IllegalArgumentException(MessageFormat.format(msg, 
args));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList$FileEntry.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList$FileEntry.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList$FileEntry.class
new file mode 100755
index 0000000..4b11004
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList$FileEntry.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/utils/ZipFileList$ZipFileEntry.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList$ZipFileEntry.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList$ZipFileEntry.class
new file mode 100755
index 0000000..bad51b4
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList$ZipFileEntry.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/utils/ZipFileList.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList.class 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList.class
new file mode 100755
index 0000000..77ab270
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList.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/utils/ZipFileList.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList.java
new file mode 100755
index 0000000..1aebf3c
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/ZipFileList.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 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.
+ 
*******************************************************************************/
+package com.ibm.juno.core.utils;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * Utility class for representing the contents of a zip file as a list of 
entries
+ * whose contents don't resolve until serialize time.
+ * <p>
+ * Generally associated with <code>RestServlets</code> using the 
<code>responseHandlers</code>
+ *     annotation so that REST methods can easily create ZIP file responses by 
simply returning instances
+ *     of this class.
+ */
+@SuppressWarnings("serial")
+public class ZipFileList extends LinkedList<ZipFileList.ZipFileEntry> {
+
+       /**
+        * The name of the zip file.
+        */
+       public final String fileName;
+
+       /**
+        * Constructor.
+        *
+        * @param fileName The file name of the zip file to create.
+        */
+       public ZipFileList(String fileName) {
+               this.fileName = fileName;
+       }
+
+       /**
+        * Add an entry to this list.
+        *
+        * @param e The zip file entry.
+        * @return This object (for method chaining).
+        */
+       public ZipFileList append(ZipFileEntry e) {
+               add(e);
+               return this;
+       }
+
+       /**
+        * Interface for ZipFileList entries.
+        */
+       public static interface ZipFileEntry {
+               /**
+                * Write this entry to the specified output stream.
+                *
+                * @param zos The output stream to write to.
+                * @throws IOException
+                */
+               void write(ZipOutputStream zos) throws IOException;
+       }
+
+       /**
+        * ZipFileList entry for File entry types.
+        */
+       public static class FileEntry implements ZipFileEntry {
+
+               /** The root file to base the entry paths on. */
+               protected File root;
+
+               /** The file being zipped. */
+               protected File file;
+
+               /**
+                * Constructor.
+                *
+                * @param root The root file that represents the base path.
+                * @param file The file to add to the zip file.
+                */
+               public FileEntry(File root, File file) {
+                       this.root = root;
+                       this.file = file;
+               }
+
+               /**
+                * Constructor.
+                *
+                * @param file The file to add to the zip file.
+                */
+               public FileEntry(File file) {
+                       this.file = file;
+                       this.root = (file.isDirectory() ? file : 
file.getParentFile());
+               }
+
+               @Override /* ZipFileEntry */
+               public void write(ZipOutputStream zos) throws IOException {
+                       addFile(zos, file);
+               }
+
+               /**
+                * Subclasses can override this method to customize which files 
get added to a zip file.
+                *
+                * @param f The file being added to the zip file.
+                * @return Always returns <jk>true</jk>.
+                */
+               public boolean doAdd(File f) {
+                       return true;
+               }
+
+               /**
+                * Adds the specified file to the specified output stream.
+                *
+                * @param zos The output stream.
+                * @param f The file to add.
+                * @throws IOException
+                */
+               protected void addFile(ZipOutputStream zos, File f) throws 
IOException {
+                       if (doAdd(f)) {
+                               if (f.isDirectory()) {
+                                       File[] fileList = f.listFiles();
+                                       if (fileList == null)
+                                               throw new 
IOException(f.toString());
+                                       for (File fc : fileList)
+                                               addFile(zos, fc);
+                               } else if (f.canRead()) {
+                                       String path = 
f.getAbsolutePath().substring(root.getAbsolutePath().length() + 
1).replace('\\', '/');
+                                       ZipEntry e = new ZipEntry(path);
+                                       e.setSize(f.length());
+                                       zos.putNextEntry(e);
+                                       IOPipe.create(new FileInputStream(f), 
zos).run();
+                               }
+                       }
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/package.html
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/package.html 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/package.html
new file mode 100755
index 0000000..97bdc68
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/utils/package.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<!--
+    Licensed Materials - Property of IBM
+    (c) Copyright IBM Corporation 2014. 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>Utility classes</p>
+
+<script>
+       function toggle(x) {
+               var div = x.nextSibling;
+               while (div != null && div.nodeType != 1)
+                       div = div.nextSibling;
+               if (div != null) {
+                       var d = div.style.display;
+                       if (d == 'block' || d == '') {
+                               div.style.display = 'none';
+                               x.className += " closed";
+                       } else {
+                               div.style.display = 'block';
+                               x.className = 
x.className.replace(/(?:^|\s)closed(?!\S)/g , '' );
+                       }
+               }
+       }
+</script>
+
+</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/xml/Namespace.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/Namespace.class 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/Namespace.class
new file mode 100755
index 0000000..281438e
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/Namespace.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/xml/Namespace.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/Namespace.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/Namespace.java
new file mode 100755
index 0000000..7cb3b54
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/Namespace.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 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.xml;
+
+/**
+ * Represents a simple namespace mapping between a simple name and URI.
+ * <p>
+ *     In general, the simple name will be used as the XML prefix mapping 
unless
+ *     there are conflicts or prefix remappings in the serializer.
+ *
+ * @author James Bognar ([email protected])
+ */
+public final class Namespace implements Comparable<Namespace> {
+       final String name, uri;
+       private final int hashCode;
+
+       /**
+        * Constructor.
+        * <p>
+        *      Use this constructor when the long name and short name are the 
same value.
+        *
+        * @param name The long and short name of this schema.
+        * @param uri The URI of this schema.
+        */
+       protected Namespace(String name, String uri) {
+               this.name = name;
+               this.uri = uri;
+               this.hashCode = (name == null ? 0 : name.hashCode()) + 
uri.hashCode();
+       }
+
+       /**
+        * Returns the namespace name.
+        *
+        * @return The namespace name.
+        */
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Returns the namespace URI.
+        *
+        * @return The namespace URI.
+        */
+       public String getUri() {
+               return uri;
+       }
+
+       @Override /* Comparable */
+       public int compareTo(Namespace o) {
+               int i = name.compareTo(o.name);
+               if (i == 0)
+                       i = uri.compareTo(o.uri);
+               return i;
+       }
+
+       /**
+        * For performance reasons, equality is always based on identity, since
+        * the {@link NamespaceFactory} class ensures no duplicate name+uri 
pairs.
+        */
+       @Override /* Object */
+       public boolean equals(Object o) {
+               return this == o;
+       }
+
+       @Override /* Object */
+       public int hashCode() {
+               return hashCode;
+       }
+
+       @Override /* Object */
+       public String toString() {
+               return "{name='"+name+"',uri:'"+uri+"'}";
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/NamespaceFactory.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/NamespaceFactory.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/NamespaceFactory.class
new file mode 100755
index 0000000..27b3171
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/NamespaceFactory.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/xml/NamespaceFactory.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/NamespaceFactory.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/NamespaceFactory.java
new file mode 100755
index 0000000..20faa03
--- /dev/null
+++ 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/NamespaceFactory.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 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.xml;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.parser.*;
+import com.ibm.juno.core.utils.*;
+
+/**
+ * Factory class for getting unique instances of {@link Namespace} objects.
+ * <p>
+ *     For performance reasons, {@link Namespace} objects are stored in {@link 
IdentityList IdentityLists}.
+ *     For this to work property, namespaces with the same name and URI must 
only be represented by a single
+ *     {@link Namespace} instance.
+ *     This factory class ensures this identity uniqueness.
+ *
+ * @author James Bognar ([email protected])
+ */
+public final class NamespaceFactory {
+
+       private static ConcurrentHashMap<String,Namespace> cache = new 
ConcurrentHashMap<String,Namespace>();
+
+       /**
+        * Get the {@link Namespace} with the specified name and URI, and 
create a new one
+        *      if this is the first time it's been encountered.
+        *
+        * @param name The namespace name.  See {@link Namespace#getName()}.
+        * @param uri The namespace URI.  See {@link Namespace#getUri()}.
+        * @return The namespace object.
+        */
+       public static Namespace get(String name, String uri) {
+               String key = name + "+" + uri;
+               Namespace n = cache.get(key);
+               if (n == null) {
+                       n = new Namespace(name, uri);
+                       Namespace n2 = cache.putIfAbsent(key, n);
+                       return (n2 == null ? n : n2);
+               }
+               return n;
+       }
+
+       /**
+        * Converts the specified object into a {@link Namespace} object.
+        * <p>
+        *      Can be any of following types:
+        * <ul>
+        *      <li>A {@link Namespace} object
+        *      <li>A JSON string containing a single key/value pair indicating 
the name/URI mapping.
+        *      <li>A <code>Map</code> containing a single key/value pair 
indicating the name/URI mapping.
+        * </ul>
+        *
+        * @param o The input.
+        * @return The namespace object, or <jk>null</jk> if the input was 
<jk>null</jk> or an empty JSON object.
+        */
+       @SuppressWarnings("rawtypes")
+       public static Namespace parseNamespace(Object o) {
+               if (o == null)
+                       return null;
+               if (o instanceof Namespace)
+                       return (Namespace)o;
+               try {
+                       Map<?,?> m = (o instanceof Map ? (Map)o : new 
ObjectMap(o.toString()));
+                       if (m.size() == 0)
+                               return null;
+                       if (m.size() > 1)
+                               throw new RuntimeException("Too many namespaces 
specified.  Only one allowed. '"+o+"'");
+                       Map.Entry<?,?> e = m.entrySet().iterator().next();
+                       return get(e.getKey().toString(), 
e.getValue().toString());
+               } catch (ParseException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       /**
+        * Converts the specified object into an array of {@link Namespace} 
object.
+        * <p>
+        *      Can be any of following types:
+        * <ul>
+        *      <li>A {@link Namespace} array
+        *      <li>A JSON string with key/value pairs indicating name/URI 
pairs.
+        *      <li>A <code>Map</code> with key/value pairs indicating name/URI 
pairs.
+        *      <li>A <code>Collection</code> containing any of object that can 
be passed to {@link #parseNamespace(Object)}.
+        * </ul>
+        *
+        * @param o The input.
+        * @return The namespace objects, or <jk>null</jk> if the input was 
<jk>null</jk> or an empty JSON object.
+        */
+       @SuppressWarnings("rawtypes")
+       public static Namespace[] parseNamespaces(Object o) {
+               try {
+                       if (o instanceof Namespace[])
+                               return (Namespace[])o;
+
+                       if (o instanceof CharSequence)
+                               o = new ObjectMap(o.toString());
+
+                       Namespace[] n;
+                       int i = 0;
+                       if (o instanceof Collection) {
+                               Collection c = (Collection)o;
+                               n = new Namespace[c.size()];
+                               for (Object o2 : c)
+                                       n[i++] = parseNamespace(o2);
+                       } else if (o instanceof Map) {
+                               Map<?,?> m = (Map<?,?>)o;
+                               n = new Namespace[m.size()];
+                               for (Map.Entry e : m.entrySet())
+                                       n[i++] = get(e.getKey().toString(), 
e.getValue().toString());
+                       } else {
+                               throw new RuntimeException("Invalid type passed 
to NamespaceFactory.listFromObject: '"+o+"'");
+                       }
+                       return n;
+               } catch (ParseException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanMeta.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanMeta.class 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanMeta.class
new file mode 100755
index 0000000..507530b
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanMeta.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/xml/XmlBeanMeta.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanMeta.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanMeta.java
new file mode 100755
index 0000000..3ffbe5c
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanMeta.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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.xml;
+
+import java.util.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.xml.annotation.*;
+
+/**
+ * Metadata on beans specific to the XML serializers and parsers pulled from 
the {@link Xml @Xml} annotation on the class.
+ *
+ * @author James Bognar ([email protected])
+ * @param <T> The bean class type.
+ */
+public class XmlBeanMeta<T> {
+
+       // XML related fields
+       private final Map<String,BeanPropertyMeta<T>> xmlAttrs;                 
       // Map of bean properties that are represented as XML attributes.
+       private final BeanPropertyMeta<T> xmlContent;                           
       // Bean property that is represented as XML content within the bean 
element.
+       private final XmlContentHandler<T> xmlContentHandler;                   
       // Class used to convert bean to XML content.
+       private final Map<String,BeanPropertyMeta<T>> childElementProperties;   
       // Properties defined with @Xml.childName annotation.
+       private final BeanMeta<T> beanMeta;
+
+       /**
+        * Constructor.
+        *
+        * @param beanMeta The metadata on the bean that this metadata applies 
to.
+        * @param pNames Only look at these property names.  If <jk>null</jk>, 
apply to all bean properties.
+        */
+       public XmlBeanMeta(BeanMeta<T> beanMeta, String[] pNames) {
+               this.beanMeta = beanMeta;
+               Class<T> c = beanMeta.getClassMeta().getInnerClass();
+
+               Map<String,BeanPropertyMeta<T>> tXmlAttrs = new 
LinkedHashMap<String,BeanPropertyMeta<T>>();
+               BeanPropertyMeta<T> tXmlContent = null;
+               XmlContentHandler<T> tXmlContentHandler = null;
+               Map<String,BeanPropertyMeta<T>> tChildElementProperties = new 
LinkedHashMap<String,BeanPropertyMeta<T>>();
+
+               for (BeanPropertyMeta<T> p : beanMeta.getPropertyMetas(pNames)) 
{
+                       XmlFormat xf = p.getXmlMeta().getXmlFormat();
+                       if (xf == XmlFormat.ATTR)
+                               tXmlAttrs.put(p.getName(), p);
+                       else if (xf == XmlFormat.CONTENT) {
+                               if (tXmlContent != null)
+                                       throw new BeanRuntimeException(c, 
"Multiple instances of CONTENT properties defined on class.  Only one property 
can be designated as such.");
+                               tXmlContent = p;
+                               tXmlContentHandler = 
p.getXmlMeta().getXmlContentHandler();
+                       }
+                       // Look for any properties that are collections with 
@Xml.childName specified.
+                       String n = p.getXmlMeta().getChildName();
+                       if (n != null) {
+                               if (tChildElementProperties.containsKey(n))
+                                       throw new BeanRuntimeException(c, 
"Multiple properties found with the name ''{0}''.", n);
+                               tChildElementProperties.put(n, p);
+                       }
+               }
+
+               xmlAttrs = Collections.unmodifiableMap(tXmlAttrs);
+               xmlContent = tXmlContent;
+               xmlContentHandler = tXmlContentHandler;
+               childElementProperties = (tChildElementProperties.isEmpty() ? 
null : Collections.unmodifiableMap(tChildElementProperties));
+       }
+
+       /**
+        * Returns the list of properties annotated with an {@link 
Xml#format()} of {@link XmlFormat#ATTR}.
+        * In other words, the list of properties that should be rendered as 
XML attributes instead of child elements.
+        *
+        * @return Metadata on the XML attribute properties of the bean.
+        */
+       protected Map<String,BeanPropertyMeta<T>> getXmlAttrProperties() {
+               return xmlAttrs;
+       }
+
+       /**
+        * Returns the bean property annotated with an {@link Xml#format()} 
value of {@link XmlFormat#CONTENT}
+        *
+        * @return The bean property, or <jk>null</jk> if annotation is not 
specified.
+        */
+       protected BeanPropertyMeta<T> getXmlContentProperty() {
+               return xmlContent;
+       }
+
+       /**
+        * Return the XML content handler for this bean.
+        *
+        * @return The XML content handler for this bean, or <jk>null</jk> if 
no content handler is defined.
+        */
+       protected XmlContentHandler<T> getXmlContentHandler() {
+               return xmlContentHandler;
+       }
+
+       /**
+        * Returns the child element properties for this bean.
+        * See {@link Xml#childName()}
+        *
+        * @return The child element properties for this bean, or <jk>null</jk> 
if no child element properties are defined.
+        */
+       protected Map<String,BeanPropertyMeta<T>> getChildElementProperties() {
+               return childElementProperties;
+       }
+
+       /**
+        * Returns bean property meta with the specified name.
+        * This is identical to calling {@link 
BeanMeta#getPropertyMeta(String)} except it first retrieves
+        *      the bean property meta based on the child name (e.g. a property 
whose name is "people", but whose child name is "person").
+        *
+        * @param fieldName The bean property name.
+        * @return The property metadata.
+        */
+       protected BeanPropertyMeta<T> getPropertyMeta(String fieldName) {
+               if (childElementProperties != null) {
+                       BeanPropertyMeta<T> bpm = 
childElementProperties.get(fieldName);
+                       if (bpm != null)
+                               return bpm;
+               }
+               return beanMeta.getPropertyMeta(fieldName);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanPropertyMeta.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanPropertyMeta.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanPropertyMeta.class
new file mode 100755
index 0000000..f3e5a97
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanPropertyMeta.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/xml/XmlBeanPropertyMeta.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanPropertyMeta.java
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanPropertyMeta.java
new file mode 100755
index 0000000..210ae0b
--- /dev/null
+++ 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlBeanPropertyMeta.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * 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.xml;
+
+import java.util.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.xml.annotation.*;
+
+/**
+ * Metadata on bean properties specific to the XML serializers and parsers 
pulled from the {@link Xml @Xml} annotation on the bean property.
+ *
+ * @author James Bognar ([email protected])
+ * @param <T> The bean class.
+ */
+public class XmlBeanPropertyMeta<T> {
+
+       private Namespace namespace = null;
+       private XmlFormat xmlFormat = XmlFormat.NORMAL;
+       private XmlContentHandler<T> xmlContentHandler = null;
+       private String childName;
+       private final BeanPropertyMeta<T> beanPropertyMeta;
+
+       /**
+        * Constructor.
+        *
+        * @param beanPropertyMeta The metadata of the bean property of this 
additional metadata.
+        */
+       public XmlBeanPropertyMeta(BeanPropertyMeta<T> beanPropertyMeta) {
+               this.beanPropertyMeta = beanPropertyMeta;
+
+               if (beanPropertyMeta.getField() != null)
+                       
findXmlInfo(beanPropertyMeta.getField().getAnnotation(Xml.class));
+               if (beanPropertyMeta.getGetter() != null)
+                       
findXmlInfo(beanPropertyMeta.getGetter().getAnnotation(Xml.class));
+               if (beanPropertyMeta.getSetter() != null)
+                       
findXmlInfo(beanPropertyMeta.getSetter().getAnnotation(Xml.class));
+
+               if (namespace == null)
+                       namespace = 
beanPropertyMeta.getBeanMeta().getClassMeta().getXmlMeta().getNamespace();
+
+               if (beanPropertyMeta.isBeanUri() && xmlFormat != 
XmlFormat.ELEMENT)
+                       xmlFormat = XmlFormat.ATTR;
+       }
+
+       /**
+        * Returns the XML namespace associated with this bean property.
+        * <p>
+        *      Namespace is determined in the following order:
+        * <ol>
+        *      <li>{@link Xml#prefix()} annotation defined on bean property 
field.
+        *      <li>{@link Xml#prefix()} annotation defined on bean getter.
+        *      <li>{@link Xml#prefix()} annotation defined on bean setter.
+        *      <li>{@link Xml#prefix()} annotation defined on bean.
+        *      <li>{@link Xml#prefix()} annotation defined on bean package.
+        *      <li>{@link Xml#prefix()} annotation defined on bean 
superclasses.
+        *      <li>{@link Xml#prefix()} annotation defined on bean superclass 
packages.
+        *      <li>{@link Xml#prefix()} annotation defined on bean interfaces.
+        *      <li>{@link Xml#prefix()} annotation defined on bean interface 
packages.
+        * </ol>
+        *
+        * @return The namespace associated with this bean property, or 
<jk>null</jk> if no namespace is
+        *      associated with it.
+        */
+       public Namespace getNamespace() {
+               return namespace;
+       }
+
+       /**
+        * Returns the XML format of this property from the {@link Xml#format} 
annotation on this bean property.
+        *
+        * @return The XML format, or {@link XmlFormat#NORMAL} if annotation 
not specified.
+        */
+       protected XmlFormat getXmlFormat() {
+               return xmlFormat;
+       }
+
+       /**
+        * Returns the XML content handler of this property from the {@link 
Xml#contentHandler} annotation on this bean property.
+        *
+        * @return The XML content handler, or <jk>null</jk> if annotation not 
specified.
+        */
+       protected XmlContentHandler<T> getXmlContentHandler() {
+               return xmlContentHandler;
+       }
+
+       /**
+        * Returns the child element of this property from the {@link 
Xml#childName} annotation on this bean property.
+        *
+        * @return The child element, or <jk>null</jk> if annotation not 
specified.
+        */
+       protected String getChildName() {
+               return childName;
+       }
+
+       /**
+        * Returns the bean property metadata that this metadata belongs to.
+        *
+        * @return The bean property metadata.  Never <jk>null</jk>.
+        */
+       protected BeanPropertyMeta<T> getBeanPropertyMeta() {
+               return beanPropertyMeta;
+       }
+
+       @SuppressWarnings("unchecked")
+       private void findXmlInfo(Xml xml) {
+               if (xml == null)
+                       return;
+               ClassMeta<?> cmProperty = beanPropertyMeta.getClassMeta();
+               ClassMeta<?> cmBean = 
beanPropertyMeta.getBeanMeta().getClassMeta();
+               String name = beanPropertyMeta.getName();
+               if (! xml.name().isEmpty())
+                       throw new BeanRuntimeException(cmBean.getInnerClass(), 
"Annotation error on property ''{0}''.  Found @Xml.name annotation can only be 
specified on types.", name);
+
+               List<Xml> xmls = beanPropertyMeta.findAnnotations(Xml.class);
+               List<XmlSchema> schemas = 
beanPropertyMeta.findAnnotations(XmlSchema.class);
+               namespace = XmlUtils.findNamespace(xmls, schemas);
+
+               if (xmlFormat == XmlFormat.NORMAL)
+                       xmlFormat = xml.format();
+
+               boolean isCollection = cmProperty.isCollection() || 
cmProperty.isArray();
+
+               String cen = xml.childName();
+               if ((! cen.isEmpty()) && (! isCollection))
+                       throw new 
BeanRuntimeException(cmProperty.getInnerClass(), "Annotation error on property 
''{0}''.  @Xml.childName can only be specified on collections and arrays.", 
name);
+
+               if (xmlFormat == XmlFormat.COLLAPSED) {
+                       if (isCollection) {
+                               if (cen.isEmpty())
+                                       cen = 
cmProperty.getXmlMeta().getChildName();
+                               if (cen == null || cen.isEmpty())
+                                       cen = 
cmProperty.getElementType().getXmlMeta().getElementName();
+                               if (cen == null || cen.isEmpty())
+                                       cen = name;
+                       } else {
+                               throw new 
BeanRuntimeException(cmBean.getInnerClass(), "Annotation error on property 
''{0}''.  @Xml.format=COLLAPSED can only be specified on collections and 
arrays.", name);
+                       }
+                       if (cen.isEmpty() && isCollection)
+                               cen = cmProperty.getXmlMeta().getElementName();
+               }
+
+               try {
+                       if (xmlFormat == XmlFormat.CONTENT && 
xml.contentHandler() != XmlContentHandler.NULL.class)
+                               xmlContentHandler = (XmlContentHandler<T>) 
xml.contentHandler().newInstance();
+               } catch (Exception e) {
+                       throw new BeanRuntimeException(cmBean.getInnerClass(), 
"Could not instantiate content handler ''{0}''", 
xml.contentHandler().getName()).initCause(e);
+               }
+
+               if (! cen.isEmpty())
+                       childName = cen;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlClassMeta.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlClassMeta.class 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlClassMeta.class
new file mode 100755
index 0000000..f5ffbb0
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlClassMeta.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/xml/XmlClassMeta.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlClassMeta.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlClassMeta.java
new file mode 100755
index 0000000..4252bab
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlClassMeta.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * 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.xml;
+
+import java.util.*;
+
+import com.ibm.juno.core.utils.*;
+import com.ibm.juno.core.xml.annotation.*;
+
+
+/**
+ * Metadata on classes specific to the XML serializers and parsers pulled from 
the {@link Xml @Xml} annotation on the class.
+ *
+ * @author James Bognar ([email protected])
+ */
+public class XmlClassMeta {
+
+       private final Namespace namespace;
+       private final Xml xml;
+       private final XmlFormat format;
+       private final String elementName;
+       private final String childName;
+
+       /**
+        * Constructor.
+        *
+        * @param c The class that this annotation is defined on.
+        */
+       public XmlClassMeta(Class<?> c) {
+               this.namespace = findNamespace(c);
+               this.xml =  ReflectionUtils.getAnnotation(Xml.class, c);
+               if (xml != null) {
+                       this.format = xml.format();
+                       this.elementName = StringUtils.nullIfEmpty(xml.name());
+                       this.childName = 
StringUtils.nullIfEmpty(xml.childName());
+
+               } else {
+                       this.format = XmlFormat.NORMAL;
+                       this.elementName = null;
+                       this.childName = null;
+               }
+       }
+
+       /**
+        * Returns the {@link Xml} annotation defined on the class.
+        *
+        * @return The value of the {@link Xml} annotation defined on the 
class, or <jk>null</jk> if annotation is not specified.
+        */
+       protected Xml getAnnotation() {
+               return xml;
+       }
+
+       /**
+        * Returns the {@link Xml#format()} annotation defined on the class.
+        *
+        * @return The value of the {@link Xml#format()} annotation, or {@link 
XmlFormat#NORMAL} if not specified.
+        */
+       protected XmlFormat getFormat() {
+               return format;
+       }
+
+       /**
+        * Returns the {@link Xml#name()} annotation defined on the class.
+        *
+        * @return The value of the {@link Xml#name()} annotation, or 
<jk>null</jk> if not specified.
+        */
+       protected String getElementName() {
+               return elementName;
+       }
+
+       /**
+        * Returns the {@link Xml#childName()} annotation defined on the class.
+        *
+        * @return The value of the {@link Xml#childName()} annotation, or 
<jk>null</jk> if not specified.
+        */
+       protected String getChildName() {
+               return childName;
+       }
+
+       /**
+        * Returns the XML namespace associated with this class.
+        * <p>
+        *      Namespace is determined in the following order:
+        * <ol>
+        *      <li>{@link Xml#prefix()} annotation defined on class.
+        *      <li>{@link Xml#prefix()} annotation defined on package.
+        *      <li>{@link Xml#prefix()} annotation defined on superclasses.
+        *      <li>{@link Xml#prefix()} annotation defined on superclass 
packages.
+        *      <li>{@link Xml#prefix()} annotation defined on interfaces.
+        *      <li>{@link Xml#prefix()} annotation defined on interface 
packages.
+        * </ol>
+        *
+        * @return The namespace associated with this class, or <jk>null</jk> 
if no namespace is
+        *      associated with it.
+        */
+       protected Namespace getNamespace() {
+               return namespace;
+       }
+
+       private Namespace findNamespace(Class<?> c) {
+               if (c == null)
+                       return null;
+
+               List<Xml> xmls = ReflectionUtils.findAnnotations(Xml.class, c);
+               List<XmlSchema> schemas = 
ReflectionUtils.findAnnotations(XmlSchema.class, c);
+               return XmlUtils.findNamespace(xmls, schemas);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler$NULL.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler$NULL.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler$NULL.class
new file mode 100755
index 0000000..cd9f86e
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler$NULL.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/xml/XmlContentHandler.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler.class
new file mode 100755
index 0000000..b0f1b7a
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler.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/xml/XmlContentHandler.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler.java
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler.java
new file mode 100755
index 0000000..3ebfef3
--- /dev/null
+++ 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlContentHandler.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014. 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.xml;
+
+import javax.xml.stream.*;
+
+import com.ibm.juno.core.dto.atom.*;
+import com.ibm.juno.core.xml.annotation.*;
+
+/**
+ * Customization class that allows a bean (or parts of a bean) to be 
serialized as XML text or mixed content.
+ * <p>
+ *     For example, the ATOM specification allows text elements (e.g. title, 
subtitle...)
+ *             to be either plain text or XML depending on the value of a 
<xa>type</xa> attribute.
+ *     The behavior of text escaping thus depends on that attribute.
+ *
+ * <p class='bcode'>
+ *     <xt>&lt;feed</xt> 
<xa>xmlns</xa>=<xs>"http://www.w3.org/2005/Atom";</xs><xt>&gt;</xt>
+ *             <xt>&lt;title</xt> <xa>type</xa>=<xs>"html"</xs><xt>&gt;</xt>
+ *                     &amp;lt;p&amp;gt;&amp;lt;i&amp;gt;This is the 
title&amp;lt;/i&amp;gt;&amp;lt;/p&amp;gt;
+ *             <xt>&lt;/title&gt;</xt>
+ *             <xt>&lt;title</xt> <xa>type</xa>=<xs>"xhtml"</xs><xt>&gt;</xt>
+ *                     <xt>&lt;div</xt> 
<xa>xmlns</xa>=<xs>"http://www.w3.org/1999/xhtml";</xs><xt>&gt;</xt>
+ *                             <xt>&lt;p&gt;&lt;i&gt;</xt>This is the 
subtitle<xt>&lt;/i&gt;&lt;/p&gt;</xt>
+ *                     <xt>&lt;/div&gt;</xt>
+ *             <xt>&lt;/title&gt;</xt>
+ *     <xt>&lt;/feed&gt;</xt>
+ * </p>
+ *
+ * <p>
+ *     The ATOM {@link Text} class (the implementation for both the 
<xt>&lt;title&gt;</xt> and <xt>&lt;subtitle&gt;</xt>
+ *             tags shown above) then associates a content handler through the 
{@link Xml#contentHandler()} annotation
+ *             on the bean property containing the text, like so...
+ *
+ * <p class='bcode'>
+ *     <ja>@Xml</ja>(format=<jsf>ATTR</jsf>)
+ *     <jk>public</jk> String getType() {
+ *             <jk>return</jk> <jf>type</jf>;
+ *     }
+ *
+ *     <ja>@Xml</ja>(format=<jsf>CONTENT</jsf>, 
contentHandler=TextContentHandler.<jk>class</jk>)
+ *     <jk>public</jk> String getText() {
+ *             <jk>return</jk> <jf>text</jf>;
+ *     }
+ *
+ *     <jk>public void</jk> setText(String text) {
+ *             <jk>this</jk>.<jf>text</jf> = text;
+ *     }
+ * </p>
+ *
+ * <p>
+ *     The content handler that transforms the output is shown below...
+ *
+ * <p class='bcode'>
+ *     <jk>public static class</jk> TextContentHandler <jk>implements</jk> 
XmlContentHandler&lt;Text&gt; {
+ *
+ *             <ja>@Override</ja>
+ *             <jk>public void</jk> parse(XMLStreamReader r, Text text) 
<jk>throws</jk> Exception {
+ *                     String type = text.<jf>type</jf>;
+ *                     <jk>if</jk> (type != <jk>null</jk> && 
type.equals(<js>"xhtml"</js>))
+ *                             text.<jf>text</jf> = 
<jsm>decode</jsm>(readXmlContents(r).trim());
+ *                     <jk>else</jk>
+ *                             text.<jf>text</jf> = 
<jsm>decode</jsm>(r.getElementText().trim());
+ *             }
+ *
+ *             <ja>@Override</ja>
+ *             <jk>public void</jk> serialize(XmlSerializerWriter w, Text 
text) <jk>throws</jk> Exception {
+ *                     String type = text.<jf>type</jf>;
+ *                     String content = text.<jf>text</jf>;
+ *                     <jk>if</jk> (type != <jk>null</jk> && 
type.equals(<js>"xhtml"</js>))
+ *                             w.encodeTextInvalidChars(content);
+ *                     <jk>else</jk>
+ *                             w.encodeText(content);
+ *             }
+ *     }
+ * </p>
+ *
+ * <h6 class='topic'>Notes</h6>
+ * <ul>
+ *     <li>The {@link Xml#contentHandler()} annotation can only be specified 
on a bean class, or a bean property
+ *             of format {@link XmlFormat#CONTENT}.
+ * </ul>
+ *
+ *
+ * @author James Bognar ([email protected])
+ * @param <T> The class type of the bean
+ */
+public interface XmlContentHandler<T> {
+
+       /**
+        * Represents <jk>null</jk> on the {@link Xml#contentHandler()} 
annotation.
+        */
+       public static interface NULL extends XmlContentHandler<Object> {}
+
+       /**
+        * Reads XML element content the specified reader and sets the 
appropriate value on the specified bean.
+        * <p>
+        *      When this method is called, the attributes have already been 
parsed and set on the bean.
+        *      Therefore, if the content handling is different based on some 
XML attribute (e.g.
+        *              <code><xa>type</xa>=<xs>"text/xml"</xs></code> vs 
<code><xa>type</xa>=<xs>"text/plain"</xs></code>)
+        *              then that attribute value can be obtained via the set 
bean property.
+        *
+        * @param r The XML stream reader.
+        *      When called, the reader is positioned on the element containing 
the text to read.
+        *      For example, calling <code>r.getElementText()</code> can be 
called immediately
+        *      to return the element text if the element contains only 
characters and whitespace.
+        *      However typically, the stream is going to contain XML elements 
that need to
+        *      be handled special (otherwise you wouldn't need to use an 
<code>XmlContentHandler</code>
+        *      to begin with).
+        * @param bean The bean where the parsed contents are going to be 
placed.
+        *      Subclasses determine how the content maps to values in the bean.
+        *      However, typically the contents map to a single property on the 
bean.
+        * @throws Exception If any problem occurs.  Causes parse to fail.
+        */
+       public void parse(XMLStreamReader r, T bean) throws Exception;
+
+       /**
+        * Writes XML element content from values in the specified bean.
+        *
+        * @param w The XML output writer.
+        *      When called, the XML element/attributes and
+        *              whitespace/indentation (if enabled) have already been 
written to the stream.
+        *      Subclasses must simply write the contents of the element.
+        * @param bean The bean whose values will be converted to XML content.
+        * @throws Exception If any problems occur.  Causes serialize to fail.
+        */
+       public void serialize(XmlSerializerWriter w, T bean) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer$Simple.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer$Simple.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer$Simple.class
new file mode 100755
index 0000000..876d0e7
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer$Simple.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/xml/XmlDocSerializer.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer.class
 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer.class
new file mode 100755
index 0000000..7eef3a8
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer.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/xml/XmlDocSerializer.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer.java
new file mode 100755
index 0000000..a2d7da0
--- /dev/null
+++ 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlDocSerializer.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.xml;
+
+import static com.ibm.juno.core.xml.XmlSerializerProperties.*;
+
+import java.io.*;
+
+import com.ibm.juno.core.annotation.*;
+import com.ibm.juno.core.serializer.*;
+
+/**
+ * Serializes POJOs to HTTP responses as XML.
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ *     Handles <code>Accept</code> types: <code>text/xml</code>
+ * <p>
+ *     Produces <code>Content-Type</code> types: <code>text/xml</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     Same as {@link XmlSerializer}, except prepends <code><xt>&lt;?xml</xt> 
<xa>version</xa>=<xs>'1.0'</xs> 
<xa>encoding</xa>=<xs>'UTF-8'</xs><xt>?&gt;</xt></code> to the response
+ *     to make it a valid XML document.
+ *
+ *
+ * @author James Bognar ([email protected])
+ */
+public class XmlDocSerializer extends XmlSerializer {
+
+       /** Default serializer without namespaces. */
+       @Produces(value="text/xml+simple",contentType="text/xml")
+       public static class Simple extends XmlDocSerializer {
+               /** Constructor */
+               public Simple() {
+                       setProperty(XML_enableNamespaces, false);
+               }
+       }
+
+       
//--------------------------------------------------------------------------------
+       // Overridden methods
+       
//--------------------------------------------------------------------------------
+
+       @Override /* Serializer */
+       protected void doSerialize(Object o, Writer out, SerializerContext ctx) 
throws IOException, SerializeException {
+               XmlSerializerContext xctx = (XmlSerializerContext)ctx;
+               XmlSerializerWriter w = xctx.getWriter(out);
+               w.append("<?xml")
+                       .attr("version", "1.0")
+                       .attr("encoding", "UTF-8")
+                       .appendln("?>");
+               super.doSerialize(o, w, ctx);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlParser.class
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlParser.class 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlParser.class
new file mode 100755
index 0000000..8ef1946
Binary files /dev/null and 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlParser.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/xml/XmlParser.java
----------------------------------------------------------------------
diff --git 
a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlParser.java 
b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlParser.java
new file mode 100755
index 0000000..9503b03
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/xml/XmlParser.java
@@ -0,0 +1,558 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 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.xml;
+
+import static com.ibm.juno.core.utils.StringUtils.*;
+import static com.ibm.juno.core.xml.XmlUtils.*;
+import static com.ibm.juno.core.xml.annotation.XmlFormat.*;
+import static javax.xml.stream.XMLStreamConstants.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import javax.xml.stream.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.annotation.*;
+import com.ibm.juno.core.filter.*;
+import com.ibm.juno.core.parser.*;
+import com.ibm.juno.core.xml.annotation.*;
+
+/**
+ * Parses text generated by the {@link XmlSerializer} class back into a POJO 
model.
+ *
+ *
+ * <h6 class='topic'>Media types</h6>
+ * <p>
+ *     Handles <code>Content-Type</code> types: <code>text/xml</code>
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     See the {@link XmlSerializer} class for a description of Juno-generated 
XML.
+ *
+ *
+ * <h6 class='topic'>Configurable properties</h6>
+ * <p>
+ *     This class has the following properties associated with it:
+ * <ul>
+ *     <li>{@link XmlParserProperties}
+ *     <li>{@link ParserProperties}
+ *     <li>{@link BeanContextProperties}
+ * </ul>
+ *
+ *
+ * @author James Bognar ([email protected])
+ */
+@SuppressWarnings({ "rawtypes", "unchecked" })
+@Consumes({"text/xml","application/xml"})
+public class XmlParser extends ReaderParser {
+
+       /** Default parser, all default settings.*/
+       public static final XmlParser DEFAULT = new XmlParser().lock();
+
+       private static final int UNKNOWN=0, OBJECT=1, ARRAY=2, STRING=3, 
NUMBER=4, BOOLEAN=5, NULL=6;
+
+
+       /** XML specific properties currently defined on this class */
+       protected transient XmlParserProperties xpp = new XmlParserProperties();
+
+
+       private <T> T parseAnything(ClassMeta<T> nt, XmlParserContext ctx, 
String currAttr, XMLStreamReader r, BeanPropertyMeta p, Object outer, boolean 
isRoot) throws ParseException, IOException {
+
+               try {
+                       BeanContext bc = ctx.getBeanContext();
+                       if (nt == null)
+                               nt = (ClassMeta<T>)object();
+                       PojoFilter<T,Object> filter = 
(PojoFilter<T,Object>)nt.getPojoFilter();
+                       ClassMeta<?> ft = nt.getFilteredClassMeta();
+
+                       String wrapperAttr = (isRoot && 
ctx.isPreserveRootElement()) ? r.getName().getLocalPart() : null;
+                       String typeAttr = r.getAttributeValue(null, "type");
+                       int jsonType = getJsonType(typeAttr);
+                       String b = r.getAttributeValue(ctx.getXsiNs(), "nil");
+                       if (b == null)
+                               b = r.getAttributeValue(null, "nil");
+                       boolean isNull = b != null && b.equals("true");
+                       if (jsonType == 0) {
+                               try {
+                                       String elementName = 
decode(r.getLocalName());
+                                       if (elementName == null || 
elementName.equals(currAttr))
+                                               jsonType = UNKNOWN;
+                                       else
+                                               jsonType = 
getJsonType(elementName);
+                               } catch (Exception e) {
+                                       throw e;
+                               }
+                       }
+                       if (! ft.canCreateNewInstance(outer)) {
+                               String c = r.getAttributeValue(null, "_class");
+                               if (c != null) {
+                                       ft = nt = 
(ClassMeta<T>)bc.getClassMetaFromString(c);
+                               }
+                       }
+                       Object o = null;
+
+                       if (jsonType == NULL) {
+                               r.nextTag();    // Discard end tag
+                               return null;
+                       }
+                       if (isNull) {
+                               while (true) {
+                                       int e = r.next();
+                                       if (e == END_ELEMENT)
+                                               return null;
+                               }
+                       }
+
+                       if (ft.isObject()) {
+                               if (jsonType == OBJECT) {
+                                       ObjectMap m = new ObjectMap(bc);
+                                       parseIntoMap(ctx, r, m, string(), 
object());
+                                       if (wrapperAttr != null)
+                                               m = new 
ObjectMap(bc).append(wrapperAttr, m);
+                                       o = m.cast();
+                               } else if (jsonType == ARRAY)
+                                       o = parseIntoCollection(ctx, r, new 
ObjectList(bc), object());
+                               else if (jsonType == STRING) {
+                                       o = getText(ctx, r);
+                                       if (ft.isChar())
+                                               o = o.toString().charAt(0);
+                               }
+                               else if (jsonType == NUMBER)
+                                       o = parseNumber(getText(ctx, r), null);
+                               else if (jsonType == BOOLEAN)
+                                       o = Boolean.parseBoolean(getText(ctx, 
r));
+                               else if (jsonType == UNKNOWN)
+                                       o = getUnknown(ctx, r);
+                       } else if (ft.isBoolean()) {
+                               o = Boolean.parseBoolean(getText(ctx, r));
+                       } else if (ft.isCharSequence()) {
+                               o = getText(ctx, r);
+                       } else if (ft.isChar()) {
+                               o = getText(ctx, r).charAt(0);
+                       } else if (ft.isMap()) {
+                               Map m = (ft.canCreateNewInstance(outer) ? 
(Map)ft.newInstance(outer) : new ObjectMap(bc));
+                               o = parseIntoMap(ctx, r, m, ft.getKeyType(), 
ft.getValueType());
+                               if (wrapperAttr != null)
+                                       o = new 
ObjectMap(bc).append(wrapperAttr, m);
+                       } else if (ft.isCollection()) {
+                               Collection l = (ft.canCreateNewInstance(outer) 
? (Collection)ft.newInstance(outer) : new ObjectList(bc));
+                               o = parseIntoCollection(ctx, r, l, 
ft.getElementType());
+                       } else if (ft.isNumber()) {
+                               o = parseNumber(getText(ctx, r), (Class<? 
extends Number>)ft.getInnerClass());
+                       } else if (ft.canCreateNewInstanceFromObjectMap(outer)) 
{
+                               ObjectMap m = new ObjectMap(bc);
+                               parseIntoMap(ctx, r, m, string(), object());
+                               o = ft.newInstanceFromObjectMap(outer, m);
+                       } else if (ft.canCreateNewBean(outer)) {
+                               if (ft.getXmlMeta().getFormat() == 
XmlFormat.COLLAPSED) {
+                                       String fieldName = r.getLocalName();
+                                       BeanMap m = bc.newBeanMap(outer, 
ft.getInnerClass());
+                                       BeanPropertyMeta bpm = 
m.getMeta().getXmlMeta().getPropertyMeta(fieldName);
+                                       bpm.set(m, 
parseAnything(m.getMeta().getClassMeta(), ctx, currAttr, r, p, 
m.getBean(false), false));
+                                       o = m.getBean();
+                               } else {
+                                       BeanMap m = bc.newBeanMap(outer, 
ft.getInnerClass());
+                                       o = parseIntoBean(ctx, r, m).getBean();
+                               }
+                       } else if (ft.isArray()) {
+                               ArrayList l = 
(ArrayList)parseIntoCollection(ctx, r, new ArrayList(), ft.getElementType());
+                               o = bc.toArray(ft, l);
+                       } else if (ft.canCreateNewInstanceFromString(outer)) {
+                               o = ft.newInstanceFromString(outer, 
getText(ctx, r));
+                       } else {
+                               throw new ParseException("Class ''{0}'' could 
not be instantiated.  Reason: ''{1}''", ft.getInnerClass().getName(), 
ft.getNotABeanReason());
+                       }
+
+                       if (filter != null && o != null)
+                               o = filter.unfilter(o, nt);
+
+                       if (outer != null)
+                               setParent(nt, o, outer);
+
+                       if (currAttr != null)
+                               setName(nt, o, currAttr);
+
+                       return (T)o;
+               } catch (ParseException e) {
+                       throw e;
+               } catch (IOException e) {
+                       throw e;
+               } catch (RuntimeException e) {
+                       throw e;
+               } catch (Exception e) {
+                       throw new ParseException("Error occurred while trying 
to parse class type ''{0}''", nt).initCause(e);
+               }
+       }
+
+       private <K,V> Map<K,V> parseIntoMap(XmlParserContext ctx, 
XMLStreamReader r, Map<K,V> m, ClassMeta<K> keyType, ClassMeta<V> valueType) 
throws ParseException, IOException {
+               BeanContext bc = ctx.getBeanContext();
+               try {
+                       int depth = 0;
+                       for (int i = 0; i < r.getAttributeCount(); i++) {
+                               String a = r.getAttributeLocalName(i);
+                               // TODO - Need better handling of namespaces 
here.
+                               if (! (a.equals("type"))) {
+                                       K key = convertAttrToType(m, a, 
keyType);
+                                       V value = convertAttrToType(m, 
r.getAttributeValue(i), valueType);
+                                       m.put(key, value);
+                               }
+                       }
+                       do {
+                               int event = r.nextTag();
+                               String currAttr;
+                               if (event == START_ELEMENT) {
+                                       depth++;
+                                       currAttr = decode(r.getLocalName());
+                                       K key = convertAttrToType(m, currAttr, 
keyType);
+                                       V value = parseAnything(valueType, ctx, 
currAttr, r, null, m, false);
+                                       if (valueType.isObject() && 
m.containsKey(key)) {
+                                               Object o = m.get(key);
+                                               if (o instanceof List)
+                                                       ((List)o).add(value);
+                                               else
+                                                       m.put(key, (V)new 
ObjectList(o, value).setBeanContext(bc));
+                                       } else {
+                                               m.put(key, value);
+                                       }
+                               } else if (event == END_ELEMENT) {
+                                       depth--;
+                                       return m;
+                               }
+                       } while (depth > 0);
+                       return m;
+               } catch (XMLStreamException e) {
+                       throw new ParseException(e);
+               }
+       }
+
+       private <E> Collection<E> parseIntoCollection(XmlParserContext ctx, 
XMLStreamReader r, Collection<E> l, ClassMeta<E> elementType) throws 
ParseException, IOException {
+               try {
+                       int depth = 0;
+                       do {
+                               int event = r.nextTag();
+                               if (event == START_ELEMENT) {
+                                       depth++;
+                                       E value = parseAnything(elementType, 
ctx, null, r, null, l, false);
+                                       l.add(value);
+                               } else if (event == END_ELEMENT) {
+                                       depth--;
+                                       return l;
+                               }
+                       } while (depth > 0);
+                       return l;
+               } catch (XMLStreamException e) {
+                       throw new ParseException(e);
+               }
+       }
+
+       private Object[] parseArgs(XmlParserContext ctx, XMLStreamReader r, 
ClassMeta<?>[] argTypes) throws ParseException, IOException {
+               try {
+                       int depth = 0;
+                       Object[] o = new Object[argTypes.length];
+                       int i = 0;
+                       do {
+                               int event = r.nextTag();
+                               if (event == START_ELEMENT) {
+                                       depth++;
+                                       o[i] = parseAnything(argTypes[i], ctx, 
null, r, null, null, false);
+                                       i++;
+                               } else if (event == END_ELEMENT) {
+                                       depth--;
+                                       return o;
+                               }
+                       } while (depth > 0);
+                       return o;
+               } catch (XMLStreamException e) {
+                       throw new ParseException(e);
+               }
+       }
+
+       private int getJsonType(String s) {
+               if (s == null)
+                       return UNKNOWN;
+               char c = s.charAt(0);
+               switch(c) {
+                       case 'o': return (s.equals("object") ? OBJECT : 
UNKNOWN);
+                       case 'a': return (s.equals("array") ? ARRAY : UNKNOWN);
+                       case 's': return (s.equals("string") ? STRING : 
UNKNOWN);
+                       case 'b': return (s.equals("boolean") ? BOOLEAN : 
UNKNOWN);
+                       case 'n': {
+                               c = s.charAt(2);
+                               switch(c) {
+                                       case 'm': return (s.equals("number") ? 
NUMBER : UNKNOWN);
+                                       case 'l': return (s.equals("null") ? 
NULL : UNKNOWN);
+                               }
+                               //return NUMBER;
+                       }
+               }
+               return UNKNOWN;
+       }
+
+       private <T> BeanMap<T> parseIntoBean(XmlParserContext ctx, 
XMLStreamReader r, BeanMap<T> m) throws Exception {
+               BeanMeta bMeta = m.getMeta();
+               XmlBeanMeta xmlMeta = bMeta.getXmlMeta();
+
+               for (int i = 0; i < r.getAttributeCount(); i++) {
+                       String key = decode(r.getAttributeLocalName(i));
+                       String val = r.getAttributeValue(i);
+                       BeanPropertyMeta bpm = xmlMeta.getPropertyMeta(key);
+                       if (bpm == null) {
+                               if (m.getMeta().isSubTyped()) {
+                                       m.put(key, val);
+                               } else {
+                                       Location l = r.getLocation();
+                                       onUnknownProperty(ctx, key, m, 
l.getLineNumber(), l.getColumnNumber());
+                               }
+                       } else {
+                               bpm.set(m, val);
+                       }
+               }
+
+               BeanPropertyMeta cp = xmlMeta.getXmlContentProperty();
+               if (cp != null) {
+                       XmlContentHandler h = xmlMeta.getXmlContentHandler();
+                       if (h != null) {
+                               h.parse(r, m.getBean());
+                       } else {
+                               String text = r.getElementText();
+                               cp.set(m, decode(text.trim()));
+                       }
+                       return m;
+               }
+
+               int depth = 0;
+               do {
+                       int event = r.nextTag();
+                       String currAttr;
+                       if (event == START_ELEMENT) {
+                               depth++;
+                               currAttr = decode(r.getLocalName());
+                               BeanPropertyMeta pMeta = 
xmlMeta.getPropertyMeta(currAttr);
+                               if (pMeta == null) {
+                                       if (m.getMeta().isSubTyped()) {
+                                               m.put(currAttr, 
parseAnything(ctx.getBeanContext().string(), ctx, currAttr, r, null, 
m.getBean(false), false));
+                                       } else {
+                                               Location l = r.getLocation();
+                                               onUnknownProperty(ctx, 
currAttr, m, l.getLineNumber(), l.getColumnNumber());
+                                               skipCurrentTag(r);
+                                       }
+                               } else {
+                                       XmlFormat xf = 
pMeta.getXmlMeta().getXmlFormat();
+                                       if (xf == COLLAPSED) {
+                                               pMeta.add(m, 
parseAnything(pMeta.getClassMeta().getElementType(), ctx, currAttr, r, null, 
m.getBean(false), false));
+                                       } else if (xf == ATTR)  {
+                                               pMeta.set(m, 
decode(r.getAttributeValue(0)));
+                                               r.nextTag();
+                                       } else {
+                                               pMeta.set(m, 
parseAnything(pMeta.getClassMeta(), ctx, currAttr, r, pMeta, m.getBean(false), 
false));
+                                       }
+                               }
+                       } else if (event == END_ELEMENT) {
+                               depth--;
+                               return m;
+                       }
+               } while (depth > 0);
+               return m;
+       }
+
+       private void skipCurrentTag(XMLStreamReader r) throws 
XMLStreamException {
+               int depth = 1;
+               do {
+                       int event = r.next();
+                       if (event == START_ELEMENT)
+                               depth++;
+                       else if (event == END_ELEMENT)
+                               depth--;
+               } while (depth > 0);
+       }
+
+       private String getText(XmlParserContext ctx, XMLStreamReader r) throws 
Exception {
+               String s = r.getElementText();
+               if (s.length() == 0)
+                       return s;
+               if (ctx.isTrimWhitespace() && 
Character.isWhitespace(s.charAt(0)) || 
Character.isWhitespace(s.charAt(s.length()-1)))
+                       s = s.trim();
+               if (s.indexOf('_') == -1)
+                       return s;
+               return decode(s);
+       }
+
+       private Object getUnknown(XmlParserContext ctx, XMLStreamReader r) 
throws Exception {
+               BeanContext bc = ctx.getBeanContext();
+               if (r.getEventType() != XMLStreamConstants.START_ELEMENT) {
+                       throw new XMLStreamException("parser must be on 
START_ELEMENT to read next text", r.getLocation());
+               }
+               ObjectMap m = null;
+
+               // If this element has attributes, then it's always an 
ObjectMap.
+               if (r.getAttributeCount() > 0) {
+                       m = new ObjectMap(bc);
+                       for (int i = 0; i < r.getAttributeCount(); i++) {
+                               String key = decode(r.getAttributeLocalName(i));
+                               String val = r.getAttributeValue(i);
+                               if (! key.equals("type"))
+                                       m.put(key, val);
+                       }
+               }
+               int eventType = r.next();
+               StringBuilder sb = new StringBuilder();
+               while (eventType != XMLStreamConstants.END_ELEMENT) {
+                       if (eventType == XMLStreamConstants.CHARACTERS || 
eventType == XMLStreamConstants.CDATA || eventType == XMLStreamConstants.SPACE 
|| eventType == XMLStreamConstants.ENTITY_REFERENCE) {
+                               sb.append(r.getText());
+                       } else if (eventType == 
XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == 
XMLStreamConstants.COMMENT) {
+                               // skipping
+                       } else if (eventType == 
XMLStreamConstants.END_DOCUMENT) {
+                               throw new XMLStreamException("Unexpected end of 
document when reading element text content", r.getLocation());
+                       } else if (eventType == 
XMLStreamConstants.START_ELEMENT) {
+                               // Oops...this has an element in it.
+                               // Parse it as a map.
+                               if (m == null)
+                                       m = new ObjectMap(bc);
+                               int depth = 0;
+                               do {
+                                       int event = (eventType == -1 ? 
r.nextTag() : eventType);
+                                       String currAttr;
+                                       if (event == START_ELEMENT) {
+                                               depth++;
+                                               currAttr = 
decode(r.getLocalName());
+                                               String key = 
convertAttrToType(null, currAttr, string());
+                                               Object value = 
parseAnything(object(), ctx, currAttr, r, null, null, false);
+                                               if (m.containsKey(key)) {
+                                                       Object o = m.get(key);
+                                                       if (o instanceof 
ObjectList)
+                                                               
((ObjectList)o).add(value);
+                                                       else
+                                                               m.put(key, new 
ObjectList(o, value).setBeanContext(bc));
+                                               } else {
+                                                       m.put(key, value);
+                                               }
+
+                                       } else if (event == END_ELEMENT) {
+                                               depth--;
+                                               break;
+                                       }
+                                       eventType = -1;
+                               } while (depth > 0);
+                               break;
+                       } else {
+                               throw new XMLStreamException("Unexpected event 
type " + eventType, r.getLocation());
+                       }
+                       eventType = r.next();
+               }
+               String s = sb.toString();
+               if (s.length() > 0) {
+                       if (ctx.isTrimWhitespace() && 
Character.isWhitespace(s.charAt(0)) || 
Character.isWhitespace(s.charAt(s.length()-1)))
+                               s = s.trim();
+                       if (s.indexOf('_') != -1)
+                               s = decode(s);
+               }
+               if (m != null) {
+                       if (! s.isEmpty())
+                               m.put("contents", s);
+                       return m;
+               }
+               return s;
+       }
+
+
+       
//--------------------------------------------------------------------------------
+       // Overridden methods
+       
//--------------------------------------------------------------------------------
+
+       @Override /* Parser */
+       public XmlParserContext createContext(ObjectMap properties, Method 
javaMethod, Object outer) {
+               return new XmlParserContext(getBeanContext(), pp, xpp, 
properties, javaMethod, outer);
+       }
+
+       @Override /* Parser */
+       protected <T> T doParse(Reader in, int estimatedSize, ClassMeta<T> 
type, ParserContext ctx) throws ParseException, IOException {
+               type = ctx.getBeanContext().normalizeClassMeta(type);
+               XmlParserContext xctx = (XmlParserContext)ctx;
+               return parseAnything(type, xctx, null, xctx.getReader(in, 
estimatedSize), null, ctx.getOuter(), true);
+       }
+
+       @Override /* ReaderParser */
+       protected <K,V> Map<K,V> doParseIntoMap(Reader in, int estimatedSize, 
Map<K,V> m, Type keyType, Type valueType, ParserContext ctx) throws 
ParseException, IOException {
+               ClassMeta cm = 
ctx.getBeanContext().getMapClassMeta(m.getClass(), keyType, valueType);
+               XmlParserContext xctx = (XmlParserContext)ctx;
+               return parseIntoMap(xctx, xctx.getReader(in, estimatedSize), m, 
cm.getKeyType(), cm.getValueType());
+       }
+
+       @Override /* ReaderParser */
+       protected <E> Collection<E> doParseIntoCollection(Reader in, int 
estimatedSize, Collection<E> c, Type elementType, ParserContext ctx) throws 
ParseException, IOException {
+               ClassMeta cm = 
ctx.getBeanContext().getCollectionClassMeta(c.getClass(), elementType);
+               XmlParserContext xctx = (XmlParserContext)ctx;
+               return parseIntoCollection(xctx, xctx.getReader(in, 
estimatedSize), c, cm.getElementType());
+       }
+
+       @Override /* ReaderParser */
+       protected Object[] doParseArgs(Reader in, int estimatedSize, 
ClassMeta<?>[] argTypes, ParserContext ctx) throws ParseException, IOException {
+               XmlParserContext xctx = (XmlParserContext)ctx;
+               return parseArgs(xctx, xctx.getReader(in, estimatedSize), 
argTypes);
+       }
+
+       @Override /* CoreApi */
+       public XmlParser setProperty(String property, Object value) throws 
LockedException {
+               checkLock();
+               if (! xpp.setProperty(property, value))
+                       super.setProperty(property, value);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser setProperties(ObjectMap properties) throws 
LockedException {
+               for (Map.Entry<String,Object> e : properties.entrySet())
+                       setProperty(e.getKey(), e.getValue());
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser addNotBeanClasses(Class<?>...classes) throws 
LockedException {
+               super.addNotBeanClasses(classes);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser addFilters(Class<?>...classes) throws LockedException {
+               super.addFilters(classes);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public <T> XmlParser addImplClass(Class<T> interfaceClass, Class<? 
extends T> implClass) throws LockedException {
+               super.addImplClass(interfaceClass, implClass);
+               return this;
+       }
+
+       @Override /* CoreApi */
+       public XmlParser setClassLoader(ClassLoader classLoader) throws 
LockedException {
+               super.setClassLoader(classLoader);
+               return this;
+       }
+
+       @Override /* Lockable */
+       public XmlParser lock() {
+               super.lock();
+               return this;
+       }
+
+       @Override /* Lockable */
+       public XmlParser clone() {
+               try {
+                       XmlParser c = (XmlParser)super.clone();
+                       c.xpp = xpp.clone();
+                       return c;
+               } catch (CloneNotSupportedException e) {
+                       throw new RuntimeException(e); // Shouldn't happen.
+               }
+       }
+}

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

Reply via email to