http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/svl/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/svl/package.html 
b/juneau-core/src/main/java/org/apache/juneau/svl/package.html
new file mode 100644
index 0000000..df73ef0
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/svl/package.html
@@ -0,0 +1,246 @@
+<!DOCTYPE HTML>
+<!--
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *  
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ 
***************************************************************************************************************************/
+ -->
+<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>Simple Variable Language</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>
+<a id='TOC'></a><h5 class='toc'>Table of Contents</h5>
+<ol class='toc'>
+       <li><p><a class='doclink' href='#SimpleVarLanguage'>Simple Variable 
Language</a></p>
+               <ol>
+                       <li><p><a class='doclink' href='#Vars'>Vars</a></p>
+                       <li><p><a class='doclink' 
href='#VarResolvers'>VarResolvers and VarResolverSessions</a></p>
+                       <li><p><a class='doclink' href='#OtherNotes'>Other 
Notes</a></p>
+               </ol>
+       </li>
+</ol>
+
+<!-- 
========================================================================================================
 -->
+<a id="SimpleVarLanguage"></a>
+<h2 class='topic' onclick='toggle(this)'>1 - Simple Variable Language</h2>
+<div class='topic'>
+       <p>
+               The <code>org.apache.juneau.svl</code> package defines an API 
for a language called "Simple Variable Language".
+               In a nutshell, Simple Variable Language (or SVL) is text that 
contains variables of the form <js>"$varName{varKey}"</js>.
+       </p>
+       <p>
+               Variables can be recursively nested within the varKey (e.g. 
<js>"$FOO{$BAR{xxx},$BAZ{xxx}}"</js>).
+               Variables can also return values that themselves contain more 
variables.
+       </p>
+       <p>
+               The {@link org.apache.juneau.svl.VarResolver} class is used to 
resolve variables.
+               The {@link org.apache.juneau.svl.VarResolver#DEFAULT} resolver 
will resolve <js>"$S{systemProperty}"</js> and <js>"$E{envVariable}"</js> 
+                       variables.
+       </p>
+       <p class='bcode'>
+       <jc>// Use the default variable resolver to resolve a string that 
contains $S (system property) variables</jc>
+       String myProperty = VarResolver.<jsf>DEFAULT</jsf>.resolve(<js>"The 
Java home directory is $S{java.home}"</js>);
+       </p>
+       <p>
+               The following shows how variables can be arbitrarily nested...
+       </p>
+       <p class='bcode'>
+       <jc>// Look up a property in the following order:
+       // 1) MYPROPERTY environment variable.
+       // 2) 'my.property' system property if environment variable not found.
+       // 3) 'not found' string if system property not found.</jc>
+       String myproperty = 
VarResolver.<jsf>DEFAULT</jsf>.resolve(<js>"$E{MYPROPERTY,$S{my.property,not 
found}}"</js>);
+       </p>
+
+       <!-- 
========================================================================================================
 -->
+       <a id="Vars"></a>
+       <h3 class='topic' onclick='toggle(this)'>1.1 - Vars</h3>
+       <div class='topic'>
+               <p>
+                       Variables are defined through the {@link 
org.apache.juneau.svl.Var} API.
+               </p>
+               <p class='bcode'>
+       <jc>// Create a var resolver that extends the default resolver and 
appends our own "$URLEncode{...}" variable</jc>
+       
+       <jc>// First create our var.</jc>
+       <jk>public class</jk> UrlEncodeVar <jk>extends</jk> SimpleVar {
+               
+               <jc>// Must have a no-arg constructor!</jc>
+               <jk>public</jk> UrlEncodeVar() {
+                       <jk>super</jk>(<js>"URLEncode"</js>);
+               }       
+               
+               <jc>// The method we must implement</jc>
+               <ja>@Override</ja>
+               <jk>public</jk> String resolve(VarResolverSession session, 
String varVal) {
+                       <jk>return</jk> URLEncoder.<jsm>encode</jsm>(varVal, 
<js>"UTF-8"</js>);
+               }
+       }
+       
+       <jc>// Next create a var resolver that extends the existing DEFAULT 
resolver
+       // that supports resolving system properties.</jc>
+       VarResolver r = 
VarResolver.<jsf>DEFAULT</jsf>.clone().addVars(UrlEncodeVar.<jk>class</jk>);
+       
+       <jc>// Retrieve a system property and URL-encode it if necessary.</jc>
+       String myProperty = r.resolve(<js>"$URLEncode{$S{my.property}}"</js>);
+               </p>
+               <p>
+                       The following shows the class hierarchy of the {@link 
org.apache.juneau.svl.Var} class and all current
+                               predefined implementations.
+               </p>  
+               <ul class='javahierarchy'>
+                       <li class='a'>{@link org.apache.juneau.svl.Var} - 
Superclass of all vars.
+                               <ul>
+                                       <li class='a'>{@link 
org.apache.juneau.svl.SimpleVar} - Superclass of all vars that return strings.
+                                               <ul>
+                                                       <li class='a'>{@link 
org.apache.juneau.svl.DefaultingVar} - Variables that define a default value if 
the resolve method returns null.
+                                                               <ul>
+                                                                       <li 
class='a'>{@link org.apache.juneau.svl.MapVar} - Variables that pull values 
from maps.
+                                                                               
<ul>
+                                                                               
        <li class='c'>{@link org.apache.juneau.svl.vars.SystemPropertiesVar} - 
Resolves system properties.
+                                                                               
</ul>
+                                                                       </li>
+                                                                       <li 
class='c'>{@link org.apache.juneau.svl.vars.ArgsVar} - Resolves variables from 
an {@link org.apache.juneau.utils.Args} object.
+                                                                       <li 
class='c'>{@link org.apache.juneau.svl.vars.ConfigFileVar} - Resolves variables 
from a {@link org.apache.juneau.ini.ConfigFile} object.
+                                                                       <li 
class='c'>{@link org.apache.juneau.svl.vars.EnvVariablesVar} - Resolves 
environment variables.
+                                                                       <li 
class='c'>{@link org.apache.juneau.svl.vars.ManifestFileVar} - Resolves 
variables from a {@link org.apache.juneau.utils.ManifestFile} object.
+                                                                       <li 
class='c'>{@link org.apache.juneau.server.vars.RequestAttrVar} - Resolves HTTP 
request attribute values.
+                                                                       <li 
class='c'>{@link org.apache.juneau.server.vars.RequestParamVar} - Resolves HTTP 
request URL parameter values.
+                                                                       <li 
class='c'>{@link org.apache.juneau.server.vars.ServletInitParamVar} - Resolves 
servlet initialization parameters.
+                                                               </ul>
+                                                       </li>
+                                                       <li class='a'>{@link 
org.apache.juneau.svl.MultipartVar} - Variables that consist of 2 or more 
comma-delimited arguments.
+                                                               <ul>
+                                                                       <li 
class='c'>{@link org.apache.juneau.server.vars.LocalizationVar} - Resolves 
localized strings for an HTTP request.
+                                                               </ul>
+                                                       </li>
+                                                       <li class='c'>{@link 
org.apache.juneau.server.vars.RequestVar} - Resolves specialized HTTP request 
values.
+                                                       <li class='c'>{@link 
org.apache.juneau.server.vars.UrlEncodeVar} - URL-encodes the value inside the 
variable.
+                                               </ul>
+                                       </li>
+                                       <li class='a'>{@link 
org.apache.juneau.svl.StreamedVar} - Superclass of all vars that stream their 
value to writers.
+                                               <ul>
+                                                       <li class='c'>{@link 
org.apache.juneau.server.vars.SerializedRequestAttrVar} - Resolves HTTP request 
attribute values passed through a {@link 
org.apache.juneau.serializer.Serializer}.
+                                                       <li class='c'>{@link 
org.apache.juneau.server.vars.SerializedRequestParamVar} - Resolves HTTP 
request URL parameter values passed through a {@link 
org.apache.juneau.serializer.Serializer}.
+                                               </ul>
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+       </div>
+       
+       <!-- 
========================================================================================================
 -->
+       <a id="VarResolvers"></a>
+       <h3 class='topic' onclick='toggle(this)'>1.2 - VarResolvers and 
VarResolverSessions</h3>
+       <div class='topic'>
+               <p>
+                       The main class for performing variable resolution is 
{@link org.apache.juneau.svl.VarResolver}.
+                       Two methods are provided for resolving variables:
+               </p>
+               <ul class='javahierarchy'>
+                       <li class='m'>{@link 
org.apache.juneau.svl.VarResolver#resolve(String)} - Resolves variables and 
returns the results as a simple string.
+                       <li class='m'>{@link 
org.apache.juneau.svl.VarResolver#resolveTo(String,Writer)} - Resolves 
variables and sends results to a writer.
+               </ul>
+               <p>
+                       Var resolvers can have zero or more context objects 
associated with them.
+                       Some {@link org.apache.juneau.svl.Var Vars} rely on the 
existence of some other object, such as an {@link org.apache.juneau.utils.Args} 
object
+                       for {@link org.apache.juneau.svl.vars.ArgsVar} or a 
{@link org.apache.juneau.ini.ConfigFile} for a {@link 
org.apache.juneau.svl.vars.ConfigFileVar}.
+                       These object dependencies are made by setting context 
objects on the var resolver.
+               </p>
+               <p>
+                       Context objects are set through the {@link 
org.apache.juneau.svl.VarResolver#setContextObject(String,Object)} method.
+                       They can be any class type.
+               </p>
+               <p>
+                       Context objects are used by {@link 
org.apache.juneau.svl.Var Vars} by calling the {@link 
org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String)} 
method.
+               </p>
+               <p>
+                       In addition to context objects, there are also session 
objects.
+                       Session objects are considered more ephemeral than 
context objects.
+                       While a context object is unlikely to ever change, a 
session object may change on every use of the var resolver.
+                       For example, the server API defines various 
<code>Var</code> objects that use the <code>RestRequest</code>
+                               object as a session object for the duration of 
a single HTTP request.
+               </p>
+               <p>
+                       Session objects are used by calling the {@link 
org.apache.juneau.svl.VarResolver#createSession()} or {@link 
org.apache.juneau.svl.VarResolver#createSession(Map)} methods to create an 
instance
+                               of a {@link 
org.apache.juneau.svl.VarResolverSession} object that contains {@link 
org.apache.juneau.svl.VarResolverSession#resolve(String)} and {@link 
org.apache.juneau.svl.VarResolverSession#resolveTo(String,Writer)} methods
+                               that are identical to {@link 
org.apache.juneau.svl.VarResolver#resolve(String)} and {@link 
org.apache.juneau.svl.VarResolver#resolveTo(String, Writer)} except that the 
<code>Var</code> objects
+                               have access to the session objects through the 
{@link org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, 
String)} method.
+                       Session objects are specified through either the {@link 
org.apache.juneau.svl.VarResolver#createSession(Map)} method or the {@link 
org.apache.juneau.svl.VarResolverSession#setSessionObject(String, Object)} 
methods.
+               </p>
+               <p>
+                       Like Context object, Session objects are used by {@link 
org.apache.juneau.svl.Var Vars} by calling the {@link 
org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String)} 
method.
+               </p>
+               <p>
+                       Var resolvers can be cloned and extended by using the 
{@link org.apache.juneau.svl.VarResolver#clone()} method.
+                       Cloning a resolver will copy it's {@link 
org.apache.juneau.svl.Var} class names and context objects.
+               </p>
+               <h6 class='topic'>Example:</h6>
+               <p class='bcode'>
+                       <jc>// Create a resolver that copies the default 
resolver and adds $C and $ARG vars.</jc>
+                       VarResolver myVarResolver = 
VarResolver.<jsf>DEFAULT</jsf>.clone().addVars(ConfigFileVar.<jk>class</jk>, 
ArgsVar.<jk>class</jk>);
+               </p>
+       </div>  
+       
+       <!-- 
========================================================================================================
 -->
+       <a id="OtherNotes"></a>
+       <h3 class='topic' onclick='toggle(this)'>1.3 - Other Notes</h3>
+       <div class='topic'>
+               <ul class='spaced-list'>
+                       <li>The escape character <js>'\'</js> can be used when 
necessary to escape the following characters: <code>$ , { }</code>
+                       <li><b>WARNING:</b>  It is possible to cause {@link 
java.lang.StackOverflowError StackOverflowErrors} if your nested variables 
result in
+                               a recursive loop (e.g. the environment variable 
<code>'MYPROPERTY'</code> has the value <code>'$E{MYPROPERTY}'</code>).
+                               So don't do that!
+                       <li>As a general rule, this class tries to be as 
efficient as possible by not creating new strings when not needed.<br>
+                               For example, calling the resolve method on a 
string that doesn't contain variables (e.g. 
<code>resolver.resolve(<js>"foobar"</js>)</code>)
+                               will simply be a no-op and return the same 
string.
+               </ul>
+       </div>  
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java 
b/juneau-core/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java
new file mode 100644
index 0000000..f1c9f38
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/svl/vars/ArgsVar.java
@@ -0,0 +1,64 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+
+package org.apache.juneau.svl.vars;
+
+import org.apache.juneau.svl.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * JVM args variable resolver.
+ * <p>
+ * The format for this var is <js>"$ARG{argNameOrNum}"</js> or 
<js>"$ARG{argNameOrNum,defaultValue}"</js>
+ * <p>
+ * This variable resolver requires that an {@link Args} object be set as a 
context object on the resolver or a
+ *     session object on the resolver session.
+ *
+ * <h6 class='topic'>Example:</h6>
+ * <p class='bcode'>
+ *     <jc>// Create an args object from the main(String[]) method.</jc>
+ *     Args args = new Args(argv);
+ *
+ *     <jc>// Create a variable resolver that resolves JVM arguments (e.g. 
"$ARG{1}")</jc>
+ *     VarResolver r = <jk>new</jk> 
VarResolver().addVars(ArgsVar.<js>class</js>).addContextObject(<jsf>SESSION_args</jsf>,
 args);
+ *
+ *     <jc>// Use it!</jc>
+ *     System.<jsf>out</jsf>.println(r.resolve(<js>"Arg #1 is set to 
$ARG{1}"</js>));
+ * </p>
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result 
will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved 
before they are passed to this var.
+ *
+ * @see org.apache.juneau.utils.Args
+ * @see org.apache.juneau.svl
+ * @author James Bognar ([email protected])
+ */
+public class ArgsVar extends DefaultingVar {
+
+       /**
+        * The name of the session or context object that identifies the {@link 
Args} object.
+        */
+       public static final String SESSION_args = "args";
+
+       /**
+        * Constructor.
+        */
+       public ArgsVar() {
+               super("ARG");
+       }
+
+       @Override /* Var */
+       public String resolve(VarResolverSession session, String key) {
+               return session.getSessionObject(Args.class, 
SESSION_args).getArg(key);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/svl/vars/ConfigFileVar.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/svl/vars/ConfigFileVar.java 
b/juneau-core/src/main/java/org/apache/juneau/svl/vars/ConfigFileVar.java
new file mode 100644
index 0000000..e69bda1
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/svl/vars/ConfigFileVar.java
@@ -0,0 +1,65 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+
+package org.apache.juneau.svl.vars;
+
+import org.apache.juneau.ini.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Config file variable resolver.
+ * <p>
+ * The format for this var is <js>"$C{key}"</js> or 
<js>"$C{key,defaultValue}"</js>.
+ * See {@link ConfigFile#getString(String)} for the format of the key.
+ * <p>
+ * This variable resolver requires that a {@link ConfigFile} object be set as 
a context object on the resolver or a
+ *     session object on the resolver session.
+ *
+ * <h6 class='topic'>Example:</h6>
+ * <p class='bcode'>
+ *     <jc>// Create a config file object.</jc>
+ *     ConfigFile configFile = 
ConfigMgr.<jsf>DEFAULT</jsf>.get(<js>"MyConfig.cfg"</js>);
+ *
+ *     <jc>// Create a variable resolver that resolves config file entries 
(e.g. "$C{MySection/myKey}")</jc>
+ *     VarResolver r = <jk>new</jk> 
VarResolver().addVars(ConfigVar.<js>class</js>).addContextObject(<jsf>SESSION_config</jsf>,
 configFile);
+ *
+ *     <jc>// Use it!</jc>
+ *     System.<jsf>out</jsf>.println(r.resolve(<js>"Value for myKey in section 
MySection is $C{MySection/myKey}"</js>));
+ * </p>
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result 
will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved 
before they are passed to this var.
+ *
+ * @see org.apache.juneau.ini.ConfigFile
+ * @see org.apache.juneau.svl
+ * @author James Bognar ([email protected])
+ */
+public class ConfigFileVar extends DefaultingVar {
+
+       /**
+        * The name of the session or context object that identifies the {@link 
ConfigFile} object.
+        */
+       public static final String SESSION_config = "config";
+
+       /**
+        * Constructor.
+        */
+       public ConfigFileVar() {
+               super("C");
+       }
+
+       @Override /* Var */
+       public String resolve(VarResolverSession session, String key) {
+               return session.getSessionObject(ConfigFile.class, 
SESSION_config).getString(key);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/svl/vars/EnvVariablesVar.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/svl/vars/EnvVariablesVar.java 
b/juneau-core/src/main/java/org/apache/juneau/svl/vars/EnvVariablesVar.java
new file mode 100644
index 0000000..e2f8024
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/svl/vars/EnvVariablesVar.java
@@ -0,0 +1,52 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+
+package org.apache.juneau.svl.vars;
+
+import org.apache.juneau.svl.*;
+
+/**
+ * Environment variable variable resolver.
+ * <p>
+ * The format for this var is <js>"$E{envVar}"</js> or 
<js>"$E{envVar,defaultValue}"</js>
+ *
+ * <h6 class='topic'>Example:</h6>
+ * <p class='bcode'>
+ *     <jc>// Create a variable resolver that resolves environment variables 
(e.g. "$E{PATH}")</jc>
+ *     VarResolver r = <jk>new</jk> 
VarResolver().addVars(EnvVariablesVar.<js>class</js>);
+ *
+ *     <jc>// Use it!</jc>
+ *     System.<jsf>out</jsf>.println(r.resolve(<js>"Environment variable PATH 
is set to $E{PATH}"</js>));
+ * </p>
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result 
will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved 
before they are passed to this var.
+ *
+ * @see org.apache.juneau.svl
+ * @author James Bognar ([email protected])
+ */
+public class EnvVariablesVar extends DefaultingVar {
+
+       /**
+        * Constructor.
+        */
+       public EnvVariablesVar() {
+               super("E");
+       }
+
+       @Override /* Var */
+       public String resolve(VarResolverSession session, String varVal) {
+               // Note that lookup is case-insensitive on windows.
+               return System.getenv(varVal);
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/svl/vars/ManifestFileVar.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/svl/vars/ManifestFileVar.java 
b/juneau-core/src/main/java/org/apache/juneau/svl/vars/ManifestFileVar.java
new file mode 100644
index 0000000..ccfbee7
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/svl/vars/ManifestFileVar.java
@@ -0,0 +1,64 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+
+package org.apache.juneau.svl.vars;
+
+import org.apache.juneau.svl.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Manifest file entries variable resolver.
+ * <p>
+ * The format for this var is <js>"$MF{key}"</js> or 
<js>"$MF{key,defaultValue}"</js>
+ * <p>
+ * This variable resolver requires that a {@link ManifestFile} object be set 
as a context object on the resolver or a
+ *     session object on the resolver session.
+ *
+ * <h6 class='topic'>Example:</h6>
+ * <p class='bcode'>
+ *     <jc>// Create a ManifestFile object that contains the manifest of the 
jar file containing this class.</jc>
+ *     ManifestFile mf = <jk>new</jk> ManifestFile(<jk>this</jk>.getClass());
+ *
+ *     <jc>// Create a variable resolver that resolves manifest file entries 
(e.g. "$MF{Main-Class}")</jc>
+ *     VarResolver r = <jk>new</jk> 
VarResolver().addVars(ManifestFile.<js>class</js>).addContextObject(<jsf>SESSION_manifest</jsf>,
 mf);
+ *
+ *     <jc>// Use it!</jc>
+ *     System.<jsf>out</jsf>.println(r.resolve(<js>"The main class is 
$MF{Main-Class}"</js>));
+ * </p>
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result 
will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved 
before they are passed to this var.
+ *
+ * @see org.apache.juneau.utils.ManifestFile
+ * @see org.apache.juneau.svl
+ * @author James Bognar ([email protected])
+ */
+public class ManifestFileVar extends DefaultingVar {
+
+       /**
+        * The name of the session or context object that identifies the {@link 
ManifestFile} object.
+        */
+       public static final String SESSION_manifest = "manifest";
+
+       /**
+        * Constructor.
+        */
+       public ManifestFileVar() {
+               super("MF");
+       }
+
+       @Override /* Var */
+       public String resolve(VarResolverSession session, String key) {
+               return session.getSessionObject(ManifestFile.class, 
SESSION_manifest).getString(key);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/svl/vars/SystemPropertiesVar.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/svl/vars/SystemPropertiesVar.java 
b/juneau-core/src/main/java/org/apache/juneau/svl/vars/SystemPropertiesVar.java
new file mode 100644
index 0000000..a2aa1f7
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/svl/vars/SystemPropertiesVar.java
@@ -0,0 +1,46 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+
+package org.apache.juneau.svl.vars;
+
+import org.apache.juneau.svl.*;
+
+/**
+ * System property variable resolver.
+ * <p>
+ * The format for this var is <js>"$S{systemProperty}"</js> or 
<js>"$S{systemProperty,defaultValue}"</js>
+ *
+ * <h6 class='topic'>Example:</h6>
+ * <p class='bcode'>
+ *     <jc>// Create a variable resolver that resolves system properties (e.g. 
"$S{java.home}")</jc>
+ *     VarResolver r = <jk>new</jk> 
VarResolver().addVars(SystemPropertiesVar.<js>class</js>);
+ *
+ *     <jc>// Use it!</jc>
+ *     System.<jsf>out</jsf>.println(r.resolve(<js>"java.home is set to 
$S{java.home}"</js>));
+ * </p>
+ * <p>
+ * Since this is a {@link SimpleVar}, any variables contained in the result 
will be recursively resolved.
+ * Likewise, if the arguments contain any variables, those will be resolved 
before they are passed to this var.
+ *
+ * @see org.apache.juneau.svl
+ * @author James Bognar ([email protected])
+ */
+public class SystemPropertiesVar extends MapVar {
+
+       /**
+        * Constructor.
+        */
+       public SystemPropertiesVar() {
+               super("S", System.getProperties());
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/transform/AnnotationBeanTransform.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/transform/AnnotationBeanTransform.java
 
b/juneau-core/src/main/java/org/apache/juneau/transform/AnnotationBeanTransform.java
new file mode 100644
index 0000000..a6bc86f
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/transform/AnnotationBeanTransform.java
@@ -0,0 +1,70 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+package org.apache.juneau.transform;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+
+/**
+ * Bean transform constructed from a {@link Bean @Bean} annotation found on a 
class.
+ * <p>
+ * <b>*** Internal class - Not intended for external use ***</b>
+ *
+ * @author James Bognar ([email protected])
+ * @param <T> The class type that this transform applies to.
+ */
+public final class AnnotationBeanTransform<T> extends BeanTransform<T> {
+
+       /**
+        * Constructor.
+        *
+        * @param annotatedClass The class found to have a {@link Bean @Bean} 
annotation.
+        * @param annotations The {@link Bean @Bean} annotations found on the 
class and all parent classes in child-to-parent order.
+        */
+       public AnnotationBeanTransform(Class<T> annotatedClass, List<Bean> 
annotations) {
+               super(annotatedClass);
+
+               ListIterator<Bean> li = 
annotations.listIterator(annotations.size());
+               while (li.hasPrevious()) {
+                       Bean b = li.previous();
+
+                       if (b.properties().length > 0 && getProperties() == 
null)
+                               setProperties(b.properties());
+
+                       if (b.sort())
+                               setSortProperties(true);
+
+                       if (b.excludeProperties().length > 0)
+                               setExcludeProperties(b.excludeProperties());
+
+                       setPropertyNamer(b.propertyNamer());
+
+                       if (b.interfaceClass() != Object.class)
+                               setInterfaceClass(b.interfaceClass());
+
+                       if (b.stopClass() != Object.class)
+                               setStopClass(b.stopClass());
+
+                       if (! b.subTypeProperty().isEmpty()) {
+                               setSubTypeProperty(b.subTypeProperty());
+
+                               LinkedHashMap<Class<?>,String> subTypes = new 
LinkedHashMap<Class<?>,String>();
+                               for (BeanSubType bst : b.subTypes())
+                                       subTypes.put(bst.type(), bst.id());
+
+                               setSubTypes(subTypes);
+                       }
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/transform/BeanTransform.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/transform/BeanTransform.java 
b/juneau-core/src/main/java/org/apache/juneau/transform/BeanTransform.java
new file mode 100644
index 0000000..f0b9f3c
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/transform/BeanTransform.java
@@ -0,0 +1,526 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+package org.apache.juneau.transform;
+
+import java.beans.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Parent class for all bean transforms.
+ * <p>
+ *     Bean transforms are used to control aspects of how beans are handled 
during serialization and parsing.
+ * <p>
+ *     This class can be considered a programmatic equivalent to using the 
{@link Bean @Bean} annotation on bean classes.
+ *     Thus, it can be used to perform the same function as the 
<code>@Bean</code> annotation when you don't have
+ *             the ability to annotate those classes (e.g. you don't have 
access to the source code).
+ * <p>
+ *     Note that value returned by the {@link Transform#forClass()} method is 
automatically determined through reflection
+ *             when the no-arg constructor is used.
+ *
+ * <p>
+ *     When defining bean transforms, you can either call the setters in the 
contructor, or override getters.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ *     <jc>// Create our serializer with a transform.</jc>
+ *     WriterSerializer s = <jk>new</jk> 
JsonSerializer().addTransforms(AddressTransform.<jk>class</jk>);
+ *
+ *     Address a = <jk>new</jk> Address();
+ *     String json = s.serialize(a); <jc>// Serializes only street, city, 
state.</jc>
+ *
+ *     <jc>// Transform class defined via setters</jc>
+ *     <jk>public class</jk> AddressTransform <jk>extends</jk> 
BeanTransform&lt;Address&gt; {
+ *             <jk>public</jk> AddressTransform() {
+ *                     
setProperties(<js>"street"</js>,<js>"city"</js>,<js>"state"</js>);
+ *             }
+ *     }
+ *
+ *     <jc>// Transform class defined by overriding getters</jc>
+ *     <jk>public class</jk> AddressTransform <jk>extends</jk> 
BeanTransform&lt;Address&gt; {
+ *             <jk>public</jk> String[] getProperties() {
+ *                     <jk>return new</jk> 
String[]{<js>"street"</js>,<js>"city"</js>,<js>"state"</js>};
+ *             }
+ *     }
+ * </p>
+ * <p>
+ *     The examples in this class use the setters approach.
+ *
+ * <h6 class='topic'>Additional information</h6>
+ *     See {@link org.apache.juneau.transform} for more information.
+ *
+ *
+ * @author James Bognar ([email protected])
+ * @param <T> The class type that this transform applies to.
+ */
+public abstract class BeanTransform<T> extends Transform {
+
+       private String[] properties, excludeProperties;
+       private LinkedHashMap<Class<?>, String> subTypes;
+       private String subTypeAttr;
+       private Class<? extends PropertyNamer> propertyNamer;
+       private Class<?> interfaceClass, stopClass;
+       private boolean sortProperties;
+
+       /**
+        * Constructor that determines the for-class value using reflection.
+        */
+       @SuppressWarnings("unchecked")
+       public BeanTransform() {
+               super();
+               this.type = TransformType.BEAN;
+
+               Class<?> c = this.getClass().getSuperclass();
+               Type t = this.getClass().getGenericSuperclass();
+               while (c != BeanTransform.class) {
+                       t = c.getGenericSuperclass();
+                       c = c.getSuperclass();
+               }
+
+               // Attempt to determine the T and G classes using reflection.
+               if (t instanceof ParameterizedType) {
+                       ParameterizedType pt = (ParameterizedType)t;
+                       Type[] pta = pt.getActualTypeArguments();
+                       if (pta.length > 0) {
+                               Type nType = pta[0];
+                               if (nType instanceof Class)
+                                       this.forClass = (Class<T>)nType;
+
+                               else
+                                       throw new RuntimeException("Unsupported 
parameter type: " + nType);
+                       }
+               }
+       }
+
+       /**
+        * Constructor that specifies the for-class explicitly.
+        * <p>
+        * This constructor only needs to be called when the class type cannot 
be inferred through reflection.
+        *
+        * <dl>
+        *      <dt>Example:</dt>
+        *      <dd>
+        *              <p class='bcode'>
+        *      <jk>public class</jk> SomeArbitraryTransform <jk>extends</jk> 
BeanTransform&lt?&gt; {
+        *              <jk>public</jk> SomeArbitraryTransform(Class&lt?&gt; 
forClass) {
+        *                      <jk>super</jk>(forClass);
+        *                      ...
+        *              }
+        *      }
+        *              </p>
+        *      </dd>
+        * </dl>
+        *
+        * @param forClass The class that this bean transform applies to.
+        */
+       public BeanTransform(Class<T> forClass) {
+               super(forClass);
+               this.type = TransformType.BEAN;
+       }
+
+       /**
+        * Returns the set and order of names of properties associated with a 
bean class.
+        *
+        * @see #setProperties(String...)
+        * @return The name of the properties associated with a bean class, or 
<jk>null</jk> if all bean properties should be used.
+        */
+       public String[] getProperties() {
+               return properties;
+       }
+
+       /**
+        * Specifies the set and order of names of properties associated with a 
bean class.
+        * <p>
+        *      The order specified is the same order that the entries will be 
returned by the {@link BeanMap#entrySet()} and related methods.
+        * <p>
+        *      This method is an alternative to using the {@link 
Bean#properties()} annotation on a class.
+        *
+        * <dl>
+        *      <dt>Example:</dt>
+        *      <dd>
+        *              <p class='bcode'>
+        *      <jc>// Create our serializer with a transform.</jc>
+        *      WriterSerializer s = <jk>new</jk> 
JsonSerializer().addTransforms(AddressTransform.<jk>class</jk>);
+        *
+        *      Address a = <jk>new</jk> Address();
+        *      String json = s.serialize(a); <jc>// Serializes only street, 
city, state.</jc>
+        *
+        *      <jc>// Transform class</jc>
+        *      <jk>public class</jk> AddressTransform <jk>extends</jk> 
BeanTransform&lt;Address&gt; {
+        *              <jk>public</jk> AddressTransform() {
+        *                      
setProperties(<js>"street"</js>,<js>"city"</js>,<js>"state"</js>);
+        *              }
+        *      }
+        *              </p>
+        *      </dd>
+        * </dl>
+        *
+        * @param properties The name of the properties associated with a bean 
class.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setProperties(String...properties) {
+               this.properties = properties;
+               return this;
+       }
+
+       /**
+        * Same as {@link #setProperties(String[])} but pass in a 
comma-delimited list of values.
+        *
+        * @param properties A comma-delimited list of properties.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setProperties(String properties) {
+               return setProperties(StringUtils.split(properties, ','));
+       }
+
+       /**
+        * Returns <jk>true</jk> if the properties defined on this bean class 
should be ordered alphabetically.
+        * <p>
+        *      This method is only used when the {@link #getProperties()} 
method returns <jk>null</jk>.
+        *      Otherwise, the ordering of the properties in the returned value 
is used.
+        *
+        * @see #setSortProperties(boolean)
+        * @return <jk>true</jk> if bean properties should be sorted.
+        */
+       public boolean isSortProperties() {
+               return sortProperties;
+       }
+
+       /**
+        * Specifies whether the properties on this bean should be ordered 
alphabetically.
+        * <p>
+        *      This method is ignored if the {@link #getProperties()} method 
does not return <jk>null</jk>.
+        * <p>
+        *      This method is an alternative to using the {@link Bean#sort()} 
annotation on a class.
+        *
+        * @param sortProperties The new value for the sort properties property.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setSortProperties(boolean sortProperties) {
+               this.sortProperties = sortProperties;
+               return this;
+       }
+
+       /**
+        * Returns the list of properties to ignore on a bean.
+        *
+        * @see #setExcludeProperties(String...)
+        * @return The name of the properties to ignore on a bean, or 
<jk>null</jk> to not ignore any properties.
+        */
+       public String[] getExcludeProperties() {
+               return excludeProperties;
+       }
+
+       /**
+        * Specifies a list of properties to ignore on a bean.
+        * <p>
+        *      This method is an alternative to using the {@link 
Bean#excludeProperties()} annotation on a class.
+        *
+        * <dl>
+        *      <dt>Example:</dt>
+        *      <dd>
+        *              <p class='bcode'>
+        *      <jc>// Create our serializer with a transform.</jc>
+        *      WriterSerializer s = <jk>new</jk> 
JsonSerializer().addTransforms(NoCityOrStateTransform.<jk>class</jk>);
+        *
+        *      Address a = <jk>new</jk> Address();
+        *      String json = s.serialize(a); <jc>// Excludes city and 
state.</jc>
+        *
+        *      <jc>// Transform class</jc>
+        *      <jk>public class</jk> NoCityOrStateTransform <jk>extends</jk> 
BeanTransform&lt;Address&gt; {
+        *              <jk>public</jk> AddressTransform() {
+        *                      
setExcludeProperties(<js>"city"</js>,<js>"state"</js>);
+        *              }
+        *      }
+        *              </p>
+        *      </dd>
+        * </dl>
+        *
+        * @param excludeProperties The name of the properties to ignore on a 
bean class.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> 
setExcludeProperties(String...excludeProperties) {
+               this.excludeProperties = excludeProperties;
+               return this;
+       }
+
+       /**
+        * Same as {@link #setExcludeProperties(String[])} but pass in a 
comma-delimited list of values.
+        *
+        * @param excludeProperties A comma-delimited list of properties to 
eclipse.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setExcludeProperties(String excludeProperties) {
+               return 
setExcludeProperties(StringUtils.split(excludeProperties, ','));
+       }
+
+       /**
+        * Returns the {@link PropertyNamer} associated with the bean to tailor 
the names of bean properties.
+        *
+        * @see #setPropertyNamer(Class)
+        * @return The property namer class, or <jk>null</jk> if no property 
namer is associated with this bean property.
+        */
+       public Class<? extends PropertyNamer> getPropertyNamer() {
+               return propertyNamer;
+       }
+
+       /**
+        * Associates a {@link PropertyNamer} with this bean to tailor the 
names of the bean properties.
+        * <p>
+        *      Property namers are used to transform bean property names from 
standard form to some other form.
+        *      For example, the {@link PropertyNamerDashedLC} will convert 
property names to dashed-lowercase, and
+        *              these will be used as attribute names in JSON, and 
element names in XML.
+        * <p>
+        *      This method is an alternative to using the {@link 
Bean#propertyNamer()} annotation on a class.
+        *
+        * @param propertyNamer The property namer class.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setPropertyNamer(Class<? extends PropertyNamer> 
propertyNamer) {
+               this.propertyNamer = propertyNamer;
+               return this;
+       }
+
+       /**
+        * Returns the name of the sub type property associated with the bean 
class.
+        *
+        * @see #setSubTypeProperty(String)
+        * @return The sub type property name, or <jk>null</jk> if bean has no 
subtypes defined.
+        */
+       public String getSubTypeProperty() {
+               return subTypeAttr;
+       }
+
+       /**
+        * Defines a virtual property on a superclass that identifies bean 
subtype classes.
+        * <p>
+        *      In the following example, the abstract class has two subclasses 
that are differentiated
+        *              by a property called <code>subType</code>
+        *
+        * <p class='bcode'>
+        *      <jc>// Abstract superclass</jc>
+        *      <jk>public abstract class</jk> A {
+        *              <jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
+        *      }
+        *
+        *      <jc>// Subclass 1</jc>
+        *      <jk>public class</jk> A1 <jk>extends</jk> A {
+        *              <jk>public</jk> String <jf>f1</jf>;
+        *      }
+        *
+        *      <jc>// Subclass 2</jc>
+        *      <jk>public class</jk> A2 <jk>extends</jk> A {
+        *              <jk>public</jk> String <jf>f2</jf>;
+        *      }
+        *
+        *      <jc>// Transform for defining subtypes</jc>
+        *      <jk>public class</jk> ATransform <jk>extends</jk> 
BeanTransform&lt;A&gt; {
+        *              <jk>public</jk> ATransform() {
+        *                      setSubTypeProperty(<js>"subType"</js>);
+        *                      addSubType(Al.<jk>class</jk>, <js>"A1"</js>);
+        *                      addSubType(A2.<jk>class</jk>, <js>"A2"</js>);
+        *              }
+        *      }
+        * </p>
+        * <p>
+        *      The following shows what happens when serializing a subclassed 
object to JSON:
+        * <p class='bcode'>
+        *      JsonSerializer s = <jk>new</jk> 
JsonSerializer().addTransforms(ATransform.<jk>class</jk>);
+        *      A1 a1 = <jk>new</jk> A1();
+        *      a1.<jf>f1</jf> = <js>"f1"</js>;
+        *      String r = s.serialize(a1);
+        *      
<jsm>assertEquals</jsm>(<js>"{subType:'A1',f1:'f1',f0:'f0'}"</js>, r);
+        * </p>
+        * <p>
+        *      The following shows what happens when parsing back into the 
original object.
+        * <p class='bcode'>
+        *      JsonParser p = <jk>new</jk> 
JsonParser().addTransforms(ATransform.<jk>class</jk>);
+        *      A a = p.parse(r, A.<jk>class</jk>);
+        *      <jsm>assertTrue</jsm>(a <jk>instanceof</jk> A1);
+        * </p>
+        * <p>
+        *      This method is an alternative to using the {@link 
Bean#subTypeProperty()} annotation on a class.
+        *
+        * @param subTypeAttr The name of the attribute representing the 
subtype.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setSubTypeProperty(String subTypeAttr) {
+               this.subTypeAttr = subTypeAttr;
+               return this;
+       }
+
+       /**
+        * Returns the subtypes associated with the bean class.
+        *
+        * @see #setSubTypeProperty(String)
+        * @return The set of sub types associated with this bean class, or 
<jk>null</jk> if bean has no subtypes defined.
+        */
+       public LinkedHashMap<Class<?>, String> getSubTypes() {
+               return subTypes;
+       }
+
+       /**
+        * Specifies the set of subclasses of this bean class in addition to a 
string identifier for that subclass.
+        *
+        * @see #setSubTypeProperty(String)
+        * @param subTypes the map of subtype classes to subtype identifier 
strings.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setSubTypes(LinkedHashMap<Class<?>, String> 
subTypes) {
+               this.subTypes = subTypes;
+               return this;
+       }
+
+       /**
+        * Convenience method for adding a single subtype in leu of using 
{@link #setSubTypes(LinkedHashMap)} in one call.
+        *
+        * @see #setSubTypeProperty(String)
+        * @param c The subtype class.
+        * @param id The subtype identifier string for the specified subtype 
class.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> addSubType(Class<?> c, String id) {
+               if (subTypes == null)
+                       subTypes = new LinkedHashMap<Class<?>, String>();
+               subTypes.put(c, id);
+               return this;
+       }
+
+       /**
+        * Returns the interface class associated with this class.
+        *
+        * @see #setInterfaceClass(Class)
+        * @return The interface class associated with this class, or 
<jk>null</jk> if no interface class is associated.
+        */
+       public Class<?> getInterfaceClass() {
+               return interfaceClass;
+       }
+
+       /**
+        * Identifies a class to be used as the interface class for this and 
all subclasses.
+        * <p>
+        *      Functionally equivalent to using the {@link 
Bean#interfaceClass()} annotation.
+        * <p>
+        *      When specified, only the list of properties defined on the 
interface class will be used during serialization.
+        *      Additional properties on subclasses will be ignored.
+        * <p class='bcode'>
+        *      <jc>// Parent class</jc>
+        *      <jk>public abstract class</jk> A {
+        *              <jk>public</jk> String <jf>f0</jf> = <js>"f0"</js>;
+        *      }
+        *
+        *      <jc>// Sub class</jc>
+        *      <jk>public class</jk> A1 <jk>extends</jk> A {
+        *              <jk>public</jk> String <jf>f1</jf> = <js>"f1"</js>;
+        *      }
+        *
+        *      <jc>// Transform class</jc>
+        *      <jk>public class</jk> ATransform <jk>extends</jk> 
BeanTransform&lt;A&gt; {
+        *              <jk>public</jk> ATransform() {
+        *                      setInterfaceClass(A.<jk>class</jk>);
+        *              }
+        *      }
+        *
+        *      JsonSerializer s = new 
JsonSerializer().addTransforms(ATransform.<jk>class</jk>);
+        *      A1 a1 = <jk>new</jk> A1();
+        *      String r = s.serialize(a1);
+        *      <jsm>assertEquals</jsm>(<js>"{f0:'f0'}"</js>, r);  <jc>// Note 
f1 is not serialized</jc>
+        * </p>
+        * <p>
+        *      Note that this transform can be used on the parent class so 
that it transforms to all child classes,
+        *              or can be set individually on the child classes.
+        * <p>
+        *      This method is an alternative to using the {@link 
Bean#interfaceClass()}} annotation.
+        *
+        * @param interfaceClass The interface class.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setInterfaceClass(Class<?> interfaceClass) {
+               this.interfaceClass = interfaceClass;
+               return this;
+       }
+
+       /**
+        * Returns the stop class associated with this class.
+        *
+        * @see #setStopClass(Class)
+        * @return The stop class associated with this class, or <jk>null</jk> 
if no stop class is associated.
+        */
+       public Class<?> getStopClass() {
+               return stopClass;
+       }
+
+       /**
+        * Identifies a stop class for this class and all subclasses.
+        * <p>
+        *      Functionally equivalent to using the {@link Bean#stopClass()} 
annotation.
+        * <p>
+        *      Identical in purpose to the stop class specified by {@link 
Introspector#getBeanInfo(Class, Class)}.
+        *      Any properties in the stop class or in its baseclasses will be 
ignored during analysis.
+        * <p>
+        *      For example, in the following class hierarchy, instances of 
<code>C3</code> will include property <code>p3</code>, but
+        *              not <code>p1</code> or <code>p2</code>.
+        * <p class='bcode'>
+        *      <jk>public class</jk> C1 {
+        *              <jk>public int</jk> getP1();
+        *      }
+        *
+        *      <jk>public class</jk> C2 <jk>extends</jk> C1 {
+        *              <jk>public int</jk> getP2();
+        *      }
+        *
+        *      <ja>@Bean</ja>(stopClass=C2.<jk>class</jk>)
+        *      <jk>public class</jk> C3 <jk>extends</jk> C2 {
+        *              <jk>public int</jk> getP3();
+        *      }
+        * </p>
+        *
+        * @param stopClass The stop class.
+        * @return This object (for method chaining).
+        */
+       public BeanTransform<T> setStopClass(Class<?> stopClass) {
+               this.stopClass = stopClass;
+               return this;
+       }
+
+       /**
+        * Subclasses can override this property to convert property values to 
some other
+        *      object just before serialization.
+        *
+        * @param bean The bean from which the property was read.
+        * @param name The property name.
+        * @param value The value just extracted from calling the bean getter.
+        * @return The value to serialize.  Default is just to return the 
existing value.
+        */
+       public Object readProperty(Object bean, String name, Object value) {
+               return value;
+       }
+
+       /**
+        * Subclasses can override this property to convert property values to 
some other
+        *      object just before calling the bean setter.
+        *
+        * @param bean The bean from which the property was read.
+        * @param name The property name.
+        * @param value The value just parsed.
+        * @return <jk>true</jk> if we set the property, <jk>false</jk> if we 
should allow the
+        *      framework to call the setter.
+        */
+       public boolean writeProperty(Object bean, String name, Object value) {
+               return false;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/transform/InterfaceBeanTransform.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/transform/InterfaceBeanTransform.java
 
b/juneau-core/src/main/java/org/apache/juneau/transform/InterfaceBeanTransform.java
new file mode 100644
index 0000000..5f281f3
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/transform/InterfaceBeanTransform.java
@@ -0,0 +1,39 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+package org.apache.juneau.transform;
+
+import org.apache.juneau.*;
+
+
+/**
+ * Simple bean transform that simply identifies a class to be used as an 
interface
+ *     class for all child classes.
+ * <p>
+ *     These objects are created when you pass in non-<code>Transform</code> 
classes to {@link ContextFactory#addToProperty(String,Object)},
+ *             and are equivalent to adding a 
<code><ja>@Bean</ja>(interfaceClass=Foo.<jk>class</jk>)</code> annotation on 
the <code>Foo</code> class.
+ *
+ * @author James Bognar ([email protected])
+ * @param <T> The class type that this transform applies to.
+ */
+public class InterfaceBeanTransform<T> extends BeanTransform<T> {
+
+       /**
+        * Constructor.
+        *
+        * @param interfaceClass The class to use as an interface on all child 
classes.
+        */
+       public InterfaceBeanTransform(Class<T> interfaceClass) {
+               super(interfaceClass);
+               setInterfaceClass(interfaceClass);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/transform/PojoTransform.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/transform/PojoTransform.java 
b/juneau-core/src/main/java/org/apache/juneau/transform/PojoTransform.java
new file mode 100644
index 0000000..4d41b3f
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/transform/PojoTransform.java
@@ -0,0 +1,265 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+package org.apache.juneau.transform;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Used to convert non-serializable objects to a serializable form.
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     <code>PojoTransforms</code> are used to extend the functionality of the 
serializers and parsers to be able to handle POJOs
+ *     that aren't automatically handled by the serializers or parsers.  For 
example, JSON does not have a standard
+ *     representation for rendering dates.  By defining a special {@code Date} 
transform and associating it with a serializer and
+ *     parser, you can convert a {@code Date} object to a {@code String} 
during serialization, and convert that {@code String} object back into
+ *     a {@code Date} object during parsing.
+ * <p>
+ *     Object transforms MUST declare a public no-arg constructor so that the 
bean context can instantiate them.
+ * <p>
+ *     <code>PojoTransforms</code> are associated with instances of {@link 
BeanContext BeanContexts} by passing the transform class to
+ *     the {@link CoreApi#addTransforms(Class...)} method.<br>
+ *     When associated with a bean context, fields of the specified type will 
automatically be converted when the
+ *     {@link BeanMap#get(Object)} or {@link BeanMap#put(String, Object)} 
methods are called.<br>
+ * <p>
+ *     <code>PojoTransforms</code> have two parameters:
+ *     <ol>
+ *             <li>{@code <F>} - The transformed representation of an object.
+ *             <li>{@code <T>} - The normal representation of an object.
+ *     </ol>
+ *     <br>
+ *     {@link Serializer Serializers} use object transforms to convert objects 
of type T into objects of type F, and on calls to {@link 
BeanMap#get(Object)}.<br>
+ *     {@link Parser Parsers} use object transforms to convert objects of type 
F into objects of type T, and on calls to {@link BeanMap#put(String,Object)}.
+ *
+ *
+ * <h6 class='topic'>Transformed Class Type {@code <T>}</h6>
+ * <p>
+ *     The transformed object representation of an object must be an object 
type that the serializers can
+ *     natively convert to JSON (or language-specific equivalent).  The list 
of valid transformed types are as follows...
+ *     <ul class='spaced-list'>
+ *             <li>{@link String}
+ *             <li>{@link Number}
+ *             <li>{@link Boolean}
+ *             <li>{@link Collection} containing anything on this list.
+ *             <li>{@link Map} containing anything on this list.
+ *             <li>A java bean with properties of anything on this list.
+ *             <li>An array of anything on this list.
+ *     </ul>
+ *
+ *
+ * <h6 class='topic'>Normal Class Type {@code <N>}</h6>
+ * <p>
+ *     The normal object representation of an object.<br>
+ *
+ *
+ * <h6 class='topic'>One-way vs. Two-way Serialization</h6>
+ * <p>
+ *     Note that while there is a unified interface for handling transforming 
during both serialization and parsing,
+ *     in many cases only one of the {@link #transform(Object)} or {@link 
#normalize(Object, ClassMeta)} methods will be defined
+ *     because the transform is one-way.  For example, a transform may be 
defined to convert an {@code Iterator} to a {@code ObjectList}, but
+ *     it's not possible to untransform an {@code Iterator}.  In that case, 
the {@code generalize(Object}} method would
+ *     be implemented, but the {@code narrow(ObjectMap)} object would not, and 
the transform would be associated on
+ *     the serializer, but not the parser.  Also, you may choose to serialize 
objects like {@code Dates} to readable {@code Strings},
+ *     in which case it's not possible to reparse it back into a {@code Date}, 
since there is no way for the {@code Parser} to
+ *     know it's a {@code Date} from just the JSON or XML text.
+ *
+ *
+ * <h6 class='topic'>Additional information</h6>
+ *     See {@link org.apache.juneau.transform} for more information.
+ *
+ *
+ * @author James Bognar ([email protected])
+ * @param <N> The normal form of the class.
+ * @param <T> The transformed form of the class.
+ */
+public abstract class PojoTransform<N,T> extends Transform {
+
+       /** Represents no transform. */
+       public static class NULL extends PojoTransform<Object,Object> {}
+
+       Class<N> normalClass;
+       Class<T> transformedClass;
+       ClassMeta<T> transformedClassMeta;
+
+       /**
+        * Constructor.
+        */
+       @SuppressWarnings("unchecked")
+       protected PojoTransform() {
+               super();
+
+               Class<?> c = this.getClass().getSuperclass();
+               Type t = this.getClass().getGenericSuperclass();
+               while (c != PojoTransform.class) {
+                       t = c.getGenericSuperclass();
+                       c = c.getSuperclass();
+               }
+
+               // Attempt to determine the T and G classes using reflection.
+               if (t instanceof ParameterizedType) {
+                       ParameterizedType pt = (ParameterizedType)t;
+                       Type[] pta = pt.getActualTypeArguments();
+                       if (pta.length == 2) {
+                               Type nType = pta[0];
+                               if (nType instanceof Class) {
+                                       this.normalClass = (Class<N>)nType;
+
+                               // <byte[],x> ends up containing a 
GenericArrayType, so it has to
+                               // be handled as a special case.
+                               } else if (nType instanceof GenericArrayType) {
+                                       Class<?> cmpntType = 
(Class<?>)((GenericArrayType)nType).getGenericComponentType();
+                                       this.normalClass = 
(Class<N>)Array.newInstance(cmpntType, 0).getClass();
+
+                               // <Class<?>,x> ends up containing a 
ParameterizedType, so just use the raw type.
+                               } else if (nType instanceof ParameterizedType) {
+                                       this.normalClass = 
(Class<N>)((ParameterizedType)nType).getRawType();
+
+                               } else
+                                       throw new RuntimeException("Unsupported 
parameter type: " + nType);
+                               if (pta[1] instanceof Class)
+                                       this.transformedClass = 
(Class<T>)pta[1];
+                               else if (pta[1] instanceof ParameterizedType)
+                                       this.transformedClass = 
(Class<T>)((ParameterizedType)pta[1]).getRawType();
+                               else
+                                       throw new RuntimeException("Unexpected 
transformed class type: " + pta[1].getClass().getName());
+                       }
+               }
+       }
+
+       /**
+        * Constructor for when the normal and transformed classes are already 
known.
+        *
+        * @param normalClass The normal class (cannot be serialized).
+        * @param transformedClass The transformed class (serializable).
+        */
+       protected PojoTransform(Class<N> normalClass, Class<T> 
transformedClass) {
+               this.normalClass = normalClass;
+               this.transformedClass = transformedClass;
+       }
+
+       /**
+        * If this transform is to be used to serialize non-serializable POJOs, 
it must implement this method.
+        * <p>
+        *      The object must be converted into one of the following 
serializable types:
+        *      <ul class='spaced-list'>
+        *              <li>{@link String}
+        *              <li>{@link Number}
+        *              <li>{@link Boolean}
+        *              <li>{@link Collection} containing anything on this list.
+        *              <li>{@link Map} containing anything on this list.
+        *              <li>A java bean with properties of anything on this 
list.
+        *              <li>An array of anything on this list.
+        *      </ul>
+        *
+        * @param o The object to be transformed.
+        * @return The transformed object.
+        * @throws SerializeException If a problem occurred trying to convert 
the output.
+        */
+       public T transform(N o) throws SerializeException {
+               throw new SerializeException("Generalize method not implemented 
on transform ''{0}''", this.getClass().getName());
+       }
+
+       /**
+        * If this transform is to be used to reconstitute POJOs that aren't 
true Java beans, it must implement this method.
+        *
+        * @param f The transformed object.
+        * @param hint If possible, the parser will try to tell you the object 
type being created.  For example,
+        *      on a serialized date, this may tell you that the object being 
created must be of type {@code GregorianCalendar}.<br>
+        *      This may be <jk>null</jk> if the parser cannot make this 
determination.
+        * @return The narrowed object.
+        * @throws ParseException If this method is not implemented.
+        */
+       public N normalize(T f, ClassMeta<?> hint) throws ParseException {
+               throw new ParseException("Narrow method not implemented on 
transform ''{0}''", this.getClass().getName());
+       }
+
+       /**
+        * Returns the T class, the normalized form of the class.
+        *
+        * @return The normal form of this class.
+        */
+       public Class<N> getNormalClass() {
+               return normalClass;
+       }
+
+       /**
+        * Returns the G class, the generialized form of the class.
+        * <p>
+        *      Subclasses must override this method if the generialized class 
is {@code Object},
+        *      meaning it can produce multiple generialized forms.
+        *
+        * @return The transformed form of this class.
+        */
+       public Class<T> getTransformedClass() {
+               return transformedClass;
+       }
+
+       /**
+        * Returns the {@link ClassMeta} of the transformed class type.
+        * This value is cached for quick lookup.
+        *
+        * @return The {@link ClassMeta} of the transformed class type.
+        */
+       public ClassMeta<T> getTransformedClassMeta() {
+               if (transformedClassMeta == null)
+                       transformedClassMeta = 
beanContext.getClassMeta(transformedClass);
+               return transformedClassMeta;
+       }
+
+       /**
+        * Checks if the specified object is an instance of the normal class 
defined on this transform.
+        *
+        * @param o The object to check.
+        * @return <jk>true</jk> if the specified object is a subclass of the 
normal class defined on this transform.
+        *      <jk>null</jk> always return <jk>false</jk>.
+        */
+       public boolean isNormalObject(Object o) {
+               if (o == null)
+                       return false;
+               return ClassUtils.isParentClass(normalClass, o.getClass());
+       }
+
+       /**
+        * Checks if the specified object is an instance of the transformed 
class defined on this transform.
+        *
+        * @param o The object to check.
+        * @return <jk>true</jk> if the specified object is a subclass of the 
transformed class defined on this transform.
+        *      <jk>null</jk> always return <jk>false</jk>.
+        */
+       public boolean isTransformedObject(Object o) {
+               if (o == null)
+                       return false;
+               return ClassUtils.isParentClass(transformedClass, o.getClass());
+       }
+
+       
//--------------------------------------------------------------------------------
+       // Overridden methods
+       
//--------------------------------------------------------------------------------
+
+       @Override /* Transform */
+       public Class<?> forClass() {
+               return normalClass;
+       }
+
+       @Override /* Object */
+       public String toString() {
+               return getClass().getSimpleName() + '<' + 
getNormalClass().getSimpleName() + "," + getTransformedClass().getSimpleName() 
+ '>';
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/transform/SurrogateTransform.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/transform/SurrogateTransform.java 
b/juneau-core/src/main/java/org/apache/juneau/transform/SurrogateTransform.java
new file mode 100644
index 0000000..2472f4f
--- /dev/null
+++ 
b/juneau-core/src/main/java/org/apache/juneau/transform/SurrogateTransform.java
@@ -0,0 +1,207 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+package org.apache.juneau.transform;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.serializer.*;
+
+
+/**
+ * Specialized {@link PojoTransform} for surrogate classes.
+ * <p>
+ * Surrogate classes are used in place of other classes during serialization.
+ * For example, you may want to use a surrogate class to change the names or 
order of bean
+ * properties on a bean.
+ * <p>
+ * The following is an example of a surrogate class change changes a property 
name:
+ * <p class='bcode'>
+ *     <jk>public class</jk> SurrogateClass {
+ *             <jk>public</jk> String surrogateField;  <jc>// New bean 
property</jc>
+ *
+ *             <jk>public</jk> SurrogateClass(NormalClass normalClass) {
+ *                     <jk>this</jk>.surrogateField = normalClass.normalField;
+ *             }
+ *     }
+ * </p>
+ * <p>
+ * Optionally, a public static method can be used to untransform a class 
during parsing:
+ * <p class='bcode'>
+ *     <jk>public class</jk> SurrogateClass {
+ *             ...
+ *             <jk>public static</jk> NormalClass 
<jsm>toNormalClass</jsm>(SurrogateClass surrogateClass) {
+ *                     <jk>return new</jk> 
NormalClass(surrogateClass.transformedField);
+ *             }
+ *     }
+ * </p>
+ * <p>
+ * Surrogate classes must conform to the following:
+ * <ul class='spaced-list'>
+ *     <li>It must have a one or more public constructors that take in a 
single parameter whose type is the normal types.
+ *             (It is possible to define a class as a surrogate for multiple 
class types by using multiple constructors with
+ *             different parameter types).
+ *     <li>It optionally can have a public static method that takes in a 
single parameter whose type is the transformed type
+ *             and returns an instance of the normal type.  This is called the 
untransform method.  The method can be called anything.
+ *     <li>If an untransform method is present, the class must also contain a 
no-arg constructor (so that the transformed class
+ *             can be instantiated by the parser before being converted into 
the normal class by the untransform method).
+ * </ul>
+ * <p>
+ * Surrogate classes are associated with serializers and parsers using the 
{@link CoreApi#addTransforms(Class...)} method.
+ * <p class='bcode'>
+ *     <ja>@Test</ja>
+ *     <jk>public void</jk> test() <jk>throws</jk> Exception {
+ *             JsonSerializer s = <jk>new</jk> 
JsonSerializer.Simple().addTransforms(Surrogate.<jk>class</jk>);
+ *             JsonParser p = <jk>new</jk> 
JsonParser().addTransforms(Surrogate.<jk>class</jk>);
+ *             String r;
+ *             Normal n = Normal.<jsm>create</jsm>();
+ *
+ *             r = s.serialize(n);
+ *             assertEquals(<js>"{f2:'f1'}"</js>, r);
+ *
+ *             n = p.parse(r, Normal.<jk>class</jk>);
+ *             assertEquals(<js>"f1"</js>, n.f1);
+ *     }
+ *
+ *     <jc>// The normal class</jc>
+ *     <jk>public class</jk> Normal {
+ *             <jk>public</jk> String f1;
+ *
+ *             <jk>public static</jk> Normal <jsm>create</jsm>() {
+ *                     Normal n = <jk>new</jk> Normal();
+ *                     n.f1 = <js>"f1"</js>;
+ *                     <jk>return</jk> n;
+ *             }
+ *     }
+ *
+ *     <jc>// The surrogate class</jc>
+ *     <jk>public static class</jk> Surrogate {
+ *             <jk>public</jk> String f2;
+ *
+ *             <jc>// Surrogate constructor</jc>
+ *             <jk>public</jk> Surrogate(Normal n) {
+ *                     f2 = n.f1;
+ *             }
+ *
+ *             <jc>// Constructor used during parsing (only needed if 
untransform method specified)</jc>
+ *             <jk>public</jk> Surrogate() {}
+ *
+ *             <jc>// Untransform method (optional)</jc>
+ *             <jk>public static</jk> Normal <jsm>toNormal</jsm>(Surrogate f) {
+ *                     Normal n = <jk>new</jk> Normal();
+ *                     n.f1 = f.f2;
+ *                     <jk>return</jk> n;
+ *             }
+ *     }
+ * </p>
+ * <p>
+ * It should be noted that a surrogate class is functionally equivalent to the 
following {@link PojoTransform} implementation:
+ * <p class='bcode'>
+ *     <jk>public static class</jk> SurrogateTransform <jk>extends</jk> 
PojoTransform&lt;Normal,Surrogate&gt; {
+ *             <jk>public</jk> Surrogate transform(Normal n) <jk>throws</jk> 
SerializeException {
+ *                     <jk>return new</jk> Surrogate(n);
+ *             }
+ *             <jk>public</jk> Normal normalize(Surrogate s, ClassMeta<?> 
hint) <jk>throws</jk> ParseException {
+ *                     <jk>return</jk> Surrogate.<jsm>toNormal</jsm>(s);
+ *             }
+ *     }
+ * </p>
+ *
+ * @author James Bognar ([email protected])
+ * @param <T> The class type that this transform applies to.
+ * @param <F> The transformed class type.
+ */
+public class SurrogateTransform<T,F> extends PojoTransform<T,F> {
+
+       private Constructor<F> constructor;   // public F(T t);
+       private Method untransformMethod;        // public static T valueOf(F 
f);
+
+       /**
+        * Constructor.
+        *
+        * @param forClass The normal class.
+        * @param constructor The constructor on the surrogate class that takes 
the normal class as a parameter.
+        * @param untransformMethod The static method that converts surrogate 
objects into normal objects.
+        */
+       protected SurrogateTransform(Class<T> forClass, Constructor<F> 
constructor, Method untransformMethod) {
+               super(forClass, constructor.getDeclaringClass());
+               this.constructor = constructor;
+               this.untransformMethod = untransformMethod;
+       }
+
+       /**
+        * Given the specified surrogate class, return the list of POJO 
transforms.
+        * A transform is returned for each public 1-arg constructor found.
+        * Returns an empty list if no public 1-arg constructors are found.
+        *
+        * @param c The surrogate class.
+        * @return The list of POJO transforms that apply to this class.
+        */
+       @SuppressWarnings({"unchecked", "rawtypes"})
+       public static List<SurrogateTransform<?,?>> findTransforms(Class<?> c) {
+               List<SurrogateTransform<?,?>> l = new 
LinkedList<SurrogateTransform<?,?>>();
+               for (Constructor<?> cc : c.getConstructors()) {
+                       if (cc.getAnnotation(BeanIgnore.class) == null) {
+                               Class<?>[] pt = cc.getParameterTypes();
+
+                               // Only constructors with one parameter.
+                               // Ignore instance class constructors.
+                               if (pt.length == 1 && pt[0] != 
c.getDeclaringClass()) {
+                                       int mod = cc.getModifiers();
+                                       if (Modifier.isPublic(mod)) {  // Only 
public constructors.
+
+                                               // Find the untransform method 
if there is one.
+                                               Method untransformMethod = null;
+                                               for (Method m : c.getMethods()) 
{
+                                                       if 
(pt[0].equals(m.getReturnType())) {
+                                                               Class<?>[] mpt 
= m.getParameterTypes();
+                                                               if (mpt.length 
== 1 && mpt[0].equals(c)) { // Only methods with one parameter and where the 
return type matches this class.
+                                                                       int 
mod2 = m.getModifiers();
+                                                                       if 
(Modifier.isPublic(mod2) && Modifier.isStatic(mod2))  // Only public static 
methods.
+                                                                               
untransformMethod = m;
+                                                               }
+                                                       }
+                                               }
+
+                                               l.add(new 
SurrogateTransform(pt[0], cc, untransformMethod));
+                                       }
+                               }
+                       }
+               }
+               return l;
+       }
+
+       @Override /* PojoTransform */
+       public F transform(T o) throws SerializeException {
+               try {
+                       return constructor.newInstance(o);
+               } catch (Exception e) {
+                       throw new SerializeException(e);
+               }
+       }
+
+       @Override /* PojoTransform */
+       @SuppressWarnings("unchecked")
+       public T normalize(F f, ClassMeta<?> hint) throws ParseException {
+               if (untransformMethod == null)
+                       throw new ParseException("static valueOf({0}) method 
not implement on surrogate class ''{1}''", f.getClass().getName(), 
getNormalClass().getName());
+               try {
+                       return (T)untransformMethod.invoke(null, f);
+               } catch (Exception e) {
+                       throw new ParseException(e);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/transform/Transform.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/transform/Transform.java 
b/juneau-core/src/main/java/org/apache/juneau/transform/Transform.java
new file mode 100644
index 0000000..3fa17f7
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/transform/Transform.java
@@ -0,0 +1,138 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ 
***************************************************************************************************************************/
+package org.apache.juneau.transform;
+
+import org.apache.juneau.*;
+
+/**
+ * Parent class for all bean and POJO transforms.
+ *
+ *
+ * <h6 class='topic'>Description</h6>
+ * <p>
+ *     Transforms are used to alter how POJOs are handled by bean contexts 
(and subsequently serializers and parsers).
+ *     The are a very powerful feature of the Juneau framework that allows 
virtually any POJO to be serialized and parsed.
+ *     For example, they can be used to...
+ * <ul class='spaced-list'>
+ *     <li>Convert a non-serializable POJO into a serializable POJO during 
serialization (and optionally vis-versa during parsing).
+ *     <li>Control various aspects of beans, such as what properties are 
visible, bean subclasses, etc...
+ * </ul>
+ * <p>
+ *     There are 2 subclasses of transforms:
+ * <ul class='spaced-list'>
+ *     <li>{@link PojoTransform} - Non-bean transforms for converting POJOs 
into serializable equivalents.
+ *     <li>{@link BeanTransform} - Bean transforms for configuring how beans 
are handled.
+ * </ul>
+ * <p>
+ *     Transforms are associated with bean contexts (and serializers/parsers) 
through the {@link ContextFactory#addToProperty(String,Object)}
+ *             and {@link CoreApi#addTransforms(Class[])} methods.
+ *
+ *
+ * <h6 class='topic'>Additional information</h6>
+ *     See {@link org.apache.juneau.transform} for more information.
+ *
+ *
+ * @author James Bognar ([email protected])
+ */
+public class Transform {
+
+       /** Represents no transform. */
+       public static class NULL extends Transform {}
+
+       /** The transform subtype */
+       public static enum TransformType {
+               /** PojoTransform */
+               POJO,
+               /** BeanTransform */
+               BEAN
+       }
+
+       /** The class that this transform applies to. */
+       protected Class<?> forClass;
+
+       /** The bean context that this transform instance belongs to. */
+       protected BeanContext beanContext;
+
+       /** Whether this is a BeanTransform or PojoTransform. */
+       protected TransformType type = TransformType.POJO;
+
+       Transform() {}
+
+       Transform(Class<?> forClass) {
+               this.forClass = forClass;
+       }
+
+
+       /**
+        * Returns the class that this transform applies to.
+        *
+        * @return The class that this transform applies to.
+        */
+       public Class<?> forClass() {
+               return forClass;
+       }
+
+       /**
+        * Returns the implementation class.
+        * Useful for debugging when calling {@link BeanContext#toString()}.
+        *
+        * @return The implementation class of this transform.
+        */
+       public Class<?> getImplClass() {
+               return this.getClass();
+       }
+
+       /**
+        * Returns whether this is an instance of {@link PojoTransform} or 
{@link BeanTransform}.
+        *
+        * @return The transform type.
+        */
+       public TransformType getType() {
+               return type;
+       }
+
+       /**
+        * Returns the {@link BeanContext} that created this transform.
+        *
+        * @return The bean context that created this transform.
+        */
+       protected BeanContext getBeanContext() {
+               return beanContext;
+       }
+
+       /**
+        * Sets the bean context that this transform instance was created by.
+        *
+        * @param beanContext The bean context that created this transform.
+        * @return This object (for method chaining).
+        */
+       public Transform setBeanContext(BeanContext beanContext) {
+               this.beanContext = beanContext;
+               return this;
+       }
+
+       @Override /* Object */
+       public int hashCode() {
+               return getClass().getName().hashCode() + 
forClass().getName().hashCode();
+       }
+
+       /**
+        * Checks if the specified transform class is the same as this one.
+        *
+        * @param f The transform to check.
+        * @return <jk>true</jk> if the specified transform is equivalent to 
this one.
+        */
+       public boolean isSameAs(Transform f) {
+               return f.getClass().equals(getClass()) && 
f.forClass().equals(forClass());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e6bf97a8/juneau-core/src/main/java/org/apache/juneau/transform/doc-files/classes.png
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/transform/doc-files/classes.png 
b/juneau-core/src/main/java/org/apache/juneau/transform/doc-files/classes.png
new file mode 100644
index 0000000..0a2ef0d
Binary files /dev/null and 
b/juneau-core/src/main/java/org/apache/juneau/transform/doc-files/classes.png 
differ

Reply via email to