http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/df0f8689/org.apache.juneau/src/test/java/org/apache/juneau/utils/PojoRestTest.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/test/java/org/apache/juneau/utils/PojoRestTest.java 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/PojoRestTest.java
new file mode 100755
index 0000000..ae945b1
--- /dev/null
+++ b/org.apache.juneau/src/test/java/org/apache/juneau/utils/PojoRestTest.java
@@ -0,0 +1,852 @@
+/***************************************************************************************************************************
+ * 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.utils;
+
+import static org.apache.juneau.serializer.SerializerContext.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.parser.*;
+import org.junit.*;
+
+@SuppressWarnings({"unchecked","rawtypes","serial"})
+public class PojoRestTest {
+
+       
//====================================================================================================
+       // testBasic
+       
//====================================================================================================
+       @Test
+       public void testBasic() {
+
+               // TODO: Need to write some exhaustive tests here. Will open 
work item
+               // to do that later.
+               PojoRest model = new PojoRest(new ObjectMap()); // An empty 
model.
+
+               // Do a PUT
+               model.put("A", new ObjectMap());
+               model.put("A/B", new ObjectMap());
+               model.put("A/B/C", "A new string");
+               assertEquals("{A:{B:{C:'A new string'}}}", model.toString());
+
+               // Do a POST to a list.
+               model.put("A/B/C", new LinkedList());
+               model.post("A/B/C", "String #1");
+               model.post("A/B/C", "String #2");
+               assertEquals("{A:{B:{C:['String #1\','String #2']}}}", 
model.toString());
+
+               // Do some GETs
+               String s = (String) model.get("A/B/C/0");
+               assertEquals("String #1", s);
+
+               Map m = (Map) model.get("A/B");
+               assertEquals("{C:['String #1','String #2']}", m.toString());
+       }
+
+       
//====================================================================================================
+       // testBeans
+       
//====================================================================================================
+       @Test
+       public void testBeans() throws Exception {
+               PojoRest model;
+
+               // Java beans.
+               model = new PojoRest(new ObjectMap());
+               Person p = new Person("some name", 123,
+                       new Address("street A", "city A", "state A", 12345, 
true),
+                       new Address("street B", "city B", "state B", 12345, 
false)
+               );
+               model.put("/person1", p);
+
+               // Make sure it got stored correctly.
+               JsonSerializer serializer = JsonSerializer.DEFAULT_LAX;
+               assertEquals("{person1:{name:'some 
name',age:123,addresses:[{street:'street A',city:'city A',state:'state 
A',zip:12345,isCurrent:true},{street:'street B',city:'city B',state:'state 
B',zip:12345,isCurrent:false}]}}", serializer.serialize(model.getRootObject()));
+
+               // Get the original Person object back.
+               p = (Person)model.get("/person1");
+               assertEquals("city B", p.addresses[1].city);
+
+               // Look for deep information inside beans.
+               Address a3 = (Address)model.get("/person1/addresses/1");
+               assertEquals("city B", a3.city);
+
+               serializer = new 
JsonSerializer.Simple().setProperty(SERIALIZER_addClassAttrs, true);
+               p = new Person("some name", 123,
+                       new Address("street A", "city A", "state A", 12345, 
true),
+                       new Address("street B", "city B", "state B", 12345, 
false)
+               );
+
+               // Serialize it to JSON.
+               String s = serializer.serialize(p);
+               String expectedValue = 
"{_class:'org.apache.juneau.utils.PojoRestTest$Person',name:'some 
name',age:123,addresses:[{street:'street A',city:'city A',state:'state 
A',zip:12345,isCurrent:true},{street:'street B',city:'city B',state:'state 
B',zip:12345,isCurrent:false}]}";
+               assertEquals(expectedValue, s);
+
+               // Parse it back to Java objects.
+               p = 
(Person)JsonParser.DEFAULT.clone().setClassLoader(getClass().getClassLoader()).parse(s,
 Object.class);
+               expectedValue = "city B";
+               s = p.addresses[1].city;
+               assertEquals(expectedValue, s);
+
+               // Parse it back into JSON again.
+               s = serializer.serialize(p);
+               expectedValue = 
"{_class:'org.apache.juneau.utils.PojoRestTest$Person',name:'some 
name',age:123,addresses:[{street:'street A',city:'city A',state:'state 
A',zip:12345,isCurrent:true},{street:'street B',city:'city B',state:'state 
B',zip:12345,isCurrent:false}]}";
+               assertEquals(expectedValue, s);
+
+               // Try adding an address
+               model = new PojoRest(p);
+               model.post("addresses", new Address("street C", "city C", 
"state C", 12345, true));
+               s = ((Address)model.get("addresses/2")).toString();
+               expectedValue = "Address(street=street C,city=city 
C,state=state C,zip=12345,isCurrent=true)";
+               assertEquals(expectedValue, s);
+
+               // Try replacing addresses
+               model.put("addresses/0", new Address("street D", "city D", 
"state D", 12345, false));
+               model.put("addresses/1", new Address("street E", "city E", 
"state E", 12345, false));
+               model.put("addresses/2", new Address("street F", "city F", 
"state F", 12345, false));
+               serializer = JsonSerializer.DEFAULT_LAX;
+               s = serializer.serialize(p);
+               expectedValue = "{name:'some 
name',age:123,addresses:[{street:'street D',city:'city D',state:'state 
D',zip:12345,isCurrent:false},{street:'street E',city:'city E',state:'state 
E',zip:12345,isCurrent:false},{street:'street F',city:'city F',state:'state 
F',zip:12345,isCurrent:false}]}";
+               assertEquals(expectedValue, s);
+
+               // Try removing an address
+               model.delete("addresses/1");
+               s = serializer.serialize(p);
+               expectedValue = "{name:'some 
name',age:123,addresses:[{street:'street D',city:'city D',state:'state 
D',zip:12345,isCurrent:false},{street:'street F',city:'city F',state:'state 
F',zip:12345,isCurrent:false}]}";
+               assertEquals(expectedValue, s);
+
+               model.delete("addresses/0");
+               model.delete("addresses/0");
+               s = serializer.serialize(p);
+               expectedValue = "{name:'some name',age:123,addresses:[]}";
+               assertEquals(expectedValue, s);
+
+               // Try adding an out-of-bounds address (should pad it with 
nulls)
+               model.put("addresses/2", new Address("street A", "city A", 
"state A", 12345, true));
+               s = serializer.serialize(p);
+               expectedValue = "{name:'some 
name',age:123,addresses:[null,null,{street:'street A',city:'city 
A',state:'state A',zip:12345,isCurrent:true}]}";
+               assertEquals(expectedValue, s);
+
+               // Try adding an address as a map (should be automatically 
converted to an Address)
+               Map m = new HashMap();
+               m.put("street","street D");
+               m.put("city","city D");
+               m.put("state","state D");
+               m.put("zip",new Integer(12345));
+
+               // Try the same for an address in an array.
+               model.put("addresses/1", m);
+               s = ((Address)model.get("addresses/1")).toString();
+               expectedValue = "Address(street=street D,city=city 
D,state=state D,zip=12345,isCurrent=false)";
+               assertEquals(expectedValue, s);
+
+               // Try setting some fields.
+               model.put("addresses/1/zip", new Integer(99999));
+               s = model.get("addresses/1/zip").toString();
+               expectedValue = "99999";
+               assertEquals(expectedValue, s);
+
+               // Make sure we can get non-existent branches without throwing 
any exceptions.
+               // get() method should just return null.
+               model = new PojoRest(new ObjectMap());
+               Object o = model.get("xxx");
+               assertEquals("null", (""+o));
+
+               // Make sure blanks and "/" returns the root object.
+               s = model.get("").toString();
+               assertEquals("{}", s);
+               s = model.get("/").toString();
+               assertEquals("{}", s);
+
+               // Make sure doing a PUT against "" or "/" replaces the root 
object.
+               ObjectMap m2 = new ObjectMap("{x:1}");
+               model.put("", m2);
+               s = model.get("").toString();
+               assertEquals("{x:1}", s);
+               m2 = new ObjectMap("{x:2}");
+               model.put("/", m2);
+               s = model.get("").toString();
+               assertEquals("{x:2}", s);
+
+               // Make sure doing a POST against "" or "/" adds to the root 
object.
+               model = new PojoRest(new ObjectList());
+               model.post("", new Integer(1));
+               model.post("/", new Integer(2));
+               s = model.get("").toString();
+               assertEquals("[1,2]", s);
+       }
+
+       
//====================================================================================================
+       // testAddressBook
+       
//====================================================================================================
+       @Test
+       public void testAddressBook() {
+               PojoRest model;
+
+               model = new PojoRest(new AddressBook());
+
+               // Try adding a person to the address book.
+               Person billClinton = new Person("Bill Clinton", 65,
+                       new Address("55W. 125th Street", "New York", "NY", 
10027, true)
+               );
+
+               model.post("/", billClinton);
+
+               // Make sure we get the original person back.
+               billClinton = (Person)model.get("/0");
+       }
+
+
+       public static class AddressBook extends LinkedList<Person> {
+
+               public AddressBook init() {
+                       add(
+                               new Person("Bill Clinton", 65,
+                                       new Address("55W. 125th Street", "New 
York", "NY", 10027, true)
+                               )
+                       );
+                       return this;
+               }
+       }
+
+       public static class Address {
+               public String street;
+               public String city;
+               public String state;
+               public int zip;
+               public boolean isCurrent;
+
+               public Address() {}
+
+               public Address(String street, String city, String state, int 
zip, boolean isCurrent) {
+                       this.street = street;
+                       this.city = city;
+                       this.state = state;
+                       this.zip = zip;
+                       this.isCurrent = isCurrent;
+               }
+               @Override /* Object */
+               public String toString() {
+                       return 
"Address(street="+street+",city="+city+",state="+state+",zip="+zip+",isCurrent="+isCurrent+")";
+               }
+       }
+
+       public static class Person {
+               public String name;
+               public int age;
+               public Address[] addresses;
+
+               public Person() {}
+
+               public Person(String name, int age, Address...addresses) {
+                       this.name = name;
+                       this.age = age;
+                       this.addresses = addresses;
+               }
+
+               @Override /* Object */
+               public String toString() {
+                       return "Person(name="+name+",age="+age+")";
+               }
+       }
+
+       
//====================================================================================================
+       // PojoRest(Object,ReaderParser)
+       
//====================================================================================================
+       @Test
+       public void testConstructors() throws Exception {
+               PojoRest model = new PojoRest(new AddressBook(), 
JsonParser.DEFAULT);
+
+               // Try adding a person to the address book.
+               Person billClinton = new Person("Bill Clinton", 65,
+                       new Address("55W. 125th Street", "New York", "NY", 
10027, true)
+               );
+
+               model.post("/", billClinton);
+
+               // Make sure we get the original person back.
+               billClinton = (Person)model.get("/0");
+       }
+
+       
//====================================================================================================
+       // setRootLocked()
+       
//====================================================================================================
+       @Test
+       public void testRootLocked() throws Exception {
+               PojoRest model = new PojoRest(new 
AddressBook()).setRootLocked();
+               try {
+                       model.put("", new AddressBook());
+                       fail();
+               } catch (PojoRestException e) {
+                       assertEquals("Cannot overwrite root object", 
e.getLocalizedMessage());
+               }
+               try {
+                       model.put(null, new AddressBook());
+                       fail();
+               } catch (PojoRestException e) {
+                       assertEquals("Cannot overwrite root object", 
e.getLocalizedMessage());
+               }
+               try {
+                       model.put("/", new AddressBook());
+                       fail();
+               } catch (PojoRestException e) {
+                       assertEquals("Cannot overwrite root object", 
e.getLocalizedMessage());
+               }
+       }
+
+       
//====================================================================================================
+       // getRootObject()
+       
//====================================================================================================
+       @Test
+       public void testGetRootObject() throws Exception {
+               PojoRest model = new PojoRest(new AddressBook());
+               assertTrue(model.getRootObject() instanceof AddressBook);
+               model.put("", "foobar");
+               assertTrue(model.getRootObject() instanceof String);
+               model.put("", null);
+               assertNull(model.getRootObject());
+       }
+
+       
//====================================================================================================
+       // get(Class<T> type, String url)
+       // get(Class<T> type, String url, T def)
+       // getString(String url)
+       // getString(String url, String defVal)
+       // getInt(String url)
+       // getInt(String url, Integer defVal)
+       // getLong(String url)
+       // getLong(String url, Long defVal)
+       // getBoolean(String url)
+       // getBoolean(String url, Boolean defVal)
+       // getMap(String url)
+       // getMap(String url, Map<?,?> defVal)
+       // getList(String url)
+       // getList(String url, List<?> defVal)
+       // getObjectMap(String url)
+       // getObjectMap(String url, ObjectMap defVal)
+       // getObjectList(String url)
+       // getObjectList(String url, ObjectList defVal)
+       
//====================================================================================================
+       @Test
+       public void testGetMethods() throws Exception {
+               PojoRest model = new PojoRest(new A());
+               ObjectList l = new ObjectList("[{a:'b'}]");
+               ObjectMap m = new ObjectMap("{a:'b'}");
+
+               assertNull(model.get("f1"));
+               assertEquals(0, model.get("f2"));
+               assertEquals(0l, model.get("f3"));
+               assertFalse((Boolean)model.get("f4"));
+               assertNull(model.get("f2a"));
+               assertNull(model.get("f3a"));
+               assertNull(model.get("f4a"));
+               assertNull(model.get("f5"));
+               assertNull(model.get("f6"));
+               assertNull(model.get("f7"));
+               assertNull(model.get("f8"));
+
+               assertEquals("foo", model.get("f1", "foo"));
+               assertEquals(0, model.get("f2", "foo"));
+               assertEquals(0l, model.get("f3", "foo"));
+               assertEquals(false, model.get("f4", "foo"));
+               assertEquals("foo", model.get("f2a", "foo"));
+               assertEquals("foo", model.get("f3a", "foo"));
+               assertEquals("foo", model.get("f4a", "foo"));
+               assertEquals("foo", model.get("f5", "foo"));
+               assertEquals("foo", model.get("f6", "foo"));
+               assertEquals("foo", model.get("f7", "foo"));
+               assertEquals("foo", model.get("f8", "foo"));
+
+               assertNull(model.getString("f1"));
+               assertEquals("0", model.getString("f2"));
+               assertEquals("0", model.getString("f3"));
+               assertEquals("false", model.getString("f4"));
+               assertNull(model.getString("f2a"));
+               assertNull(model.getString("f3a"));
+               assertNull(model.getString("f4a"));
+               assertNull(model.getString("f5"));
+               assertNull(model.getString("f6"));
+               assertNull(model.getString("f7"));
+               assertNull(model.getString("f8"));
+
+               assertEquals("foo", model.getString("f1", "foo"));
+               assertEquals("0", model.getString("f2", "foo"));
+               assertEquals("0", model.getString("f3", "foo"));
+               assertEquals("false", model.getString("f4", "foo"));
+               assertEquals("foo", model.getString("f2a", "foo"));
+               assertEquals("foo", model.getString("f3a", "foo"));
+               assertEquals("foo", model.getString("f4a", "foo"));
+               assertEquals("foo", model.getString("f5", "foo"));
+               assertEquals("foo", model.getString("f6", "foo"));
+               assertEquals("foo", model.getString("f7", "foo"));
+               assertEquals("foo", model.getString("f8", "foo"));
+
+               assertNull(model.getInt("f1"));
+               assertEquals(0, (int)model.getInt("f2"));
+               assertEquals(0, (int)model.getInt("f3"));
+               assertEquals(0, (int)model.getInt("f4"));
+               assertNull(model.getInt("f2a"));
+               assertNull(model.getInt("f3a"));
+               assertNull(model.getInt("f4a"));
+               assertNull(model.getInt("f5"));
+               assertNull(model.getInt("f6"));
+               assertNull(model.getInt("f7"));
+               assertNull(model.getInt("f8"));
+
+               assertEquals(1, (int)model.getInt("f1", 1));
+               assertEquals(0, (int)model.getInt("f2", 1));
+               assertEquals(0, (int)model.getInt("f3", 1));
+               assertEquals(0, (int)model.getInt("f4", 1));
+               assertEquals(1, (int)model.getInt("f2a", 1));
+               assertEquals(1, (int)model.getInt("f3a", 1));
+               assertEquals(1, (int)model.getInt("f4a", 1));
+               assertEquals(1, (int)model.getInt("f5", 1));
+               assertEquals(1, (int)model.getInt("f6", 1));
+               assertEquals(1, (int)model.getInt("f7", 1));
+               assertEquals(1, (int)model.getInt("f8", 1));
+
+               assertNull(model.getLong("f1"));
+               assertEquals(0, (long)model.getLong("f2"));
+               assertEquals(0, (long)model.getLong("f3"));
+               assertEquals(0, (long)model.getLong("f4"));
+               assertNull(model.getLong("f2a"));
+               assertNull(model.getLong("f3a"));
+               assertNull(model.getLong("f4a"));
+               assertNull(model.getLong("f5"));
+               assertNull(model.getLong("f6"));
+               assertNull(model.getLong("f7"));
+               assertNull(model.getLong("f8"));
+
+               assertEquals(1, (long)model.getLong("f1", 1l));
+               assertEquals(0, (long)model.getLong("f2", 1l));
+               assertEquals(0, (long)model.getLong("f3", 1l));
+               assertEquals(0, (long)model.getLong("f4", 1l));
+               assertEquals(1, (long)model.getLong("f2a", 1l));
+               assertEquals(1, (long)model.getLong("f3a", 1l));
+               assertEquals(1, (long)model.getLong("f4a", 1l));
+               assertEquals(1, (long)model.getLong("f5", 1l));
+               assertEquals(1, (long)model.getLong("f6", 1l));
+               assertEquals(1, (long)model.getLong("f7", 1l));
+               assertEquals(1, (long)model.getLong("f8", 1l));
+
+               assertNull(model.getBoolean("f1"));
+               assertEquals(false, model.getBoolean("f2"));
+               assertEquals(false, model.getBoolean("f3"));
+               assertEquals(false, model.getBoolean("f4"));
+               assertNull(model.getBoolean("f2a"));
+               assertNull(model.getBoolean("f3a"));
+               assertNull(model.getBoolean("f4a"));
+               assertNull(model.getBoolean("f5"));
+               assertNull(model.getBoolean("f6"));
+               assertNull(model.getBoolean("f7"));
+               assertNull(model.getBoolean("f8"));
+
+               assertEquals(true, model.getBoolean("f1", true));
+               assertEquals(false, model.getBoolean("f2", true));
+               assertEquals(false, model.getBoolean("f3", true));
+               assertEquals(false, model.getBoolean("f4", true));
+               assertEquals(true, model.getBoolean("f2a", true));
+               assertEquals(true, model.getBoolean("f3a", true));
+               assertEquals(true, model.getBoolean("f4a", true));
+               assertEquals(true, model.getBoolean("f5", true));
+               assertEquals(true, model.getBoolean("f6", true));
+               assertEquals(true, model.getBoolean("f7", true));
+               assertEquals(true, model.getBoolean("f8", true));
+
+               assertNull(model.getMap("f1"));
+               try { model.getMap("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertNull(model.getMap("f2a"));
+               assertNull(model.getMap("f3a"));
+               assertNull(model.getMap("f4a"));
+               assertNull(model.getMap("f5"));
+               assertNull(model.getMap("f6"));
+               assertNull(model.getMap("f7"));
+               assertNull(model.getMap("f8"));
+
+               assertEquals("{a:'b'}", model.getMap("f1", m).toString());
+               try { model.getMap("f2", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f3", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f4", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{a:'b'}", model.getMap("f2a", m).toString());
+               assertEquals("{a:'b'}", model.getMap("f3a", m).toString());
+               assertEquals("{a:'b'}", model.getMap("f4a", m).toString());
+               assertEquals("{a:'b'}", model.getMap("f5", m).toString());
+               assertEquals("{a:'b'}", model.getMap("f6", m).toString());
+               assertEquals("{a:'b'}", model.getMap("f7", m).toString());
+               assertEquals("{a:'b'}", model.getMap("f8", m).toString());
+
+               assertNull(model.getMap("f1"));
+               try { model.getObjectMap("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertNull(model.getObjectMap("f2a"));
+               assertNull(model.getObjectMap("f3a"));
+               assertNull(model.getObjectMap("f4a"));
+               assertNull(model.getObjectMap("f5"));
+               assertNull(model.getObjectMap("f6"));
+               assertNull(model.getObjectMap("f7"));
+               assertNull(model.getObjectMap("f8"));
+
+               assertEquals("{a:'b'}", model.getObjectMap("f1", m).toString());
+               try { model.getObjectMap("f2", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f3", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f4", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{a:'b'}", model.getObjectMap("f2a", 
m).toString());
+               assertEquals("{a:'b'}", model.getObjectMap("f3a", 
m).toString());
+               assertEquals("{a:'b'}", model.getObjectMap("f4a", 
m).toString());
+               assertEquals("{a:'b'}", model.getObjectMap("f5", m).toString());
+               assertEquals("{a:'b'}", model.getObjectMap("f6", m).toString());
+               assertEquals("{a:'b'}", model.getObjectMap("f7", m).toString());
+               assertEquals("{a:'b'}", model.getObjectMap("f8", m).toString());
+
+               assertNull(model.getList("f1"));
+               try { model.getList("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertNull(model.getList("f2a"));
+               assertNull(model.getList("f3a"));
+               assertNull(model.getList("f4a"));
+               assertNull(model.getList("f5"));
+               assertNull(model.getList("f6"));
+               assertNull(model.getList("f7"));
+               assertNull(model.getList("f8"));
+
+               assertEquals("[{a:'b'}]", model.getList("f1", l).toString());
+               try { model.getList("f2", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f3", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f4", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("[{a:'b'}]", model.getList("f2a", l).toString());
+               assertEquals("[{a:'b'}]", model.getList("f3a", l).toString());
+               assertEquals("[{a:'b'}]", model.getList("f4a", l).toString());
+               assertEquals("[{a:'b'}]", model.getList("f5", l).toString());
+               assertEquals("[{a:'b'}]", model.getList("f6", l).toString());
+               assertEquals("[{a:'b'}]", model.getList("f7", l).toString());
+               assertEquals("[{a:'b'}]", model.getList("f8", l).toString());
+
+               assertNull(model.getObjectList("f1"));
+               try { model.getObjectList("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertNull(model.getObjectList("f2a"));
+               assertNull(model.getObjectList("f3a"));
+               assertNull(model.getObjectList("f4a"));
+               assertNull(model.getObjectList("f5"));
+               assertNull(model.getObjectList("f6"));
+               assertNull(model.getObjectList("f7"));
+               assertNull(model.getObjectList("f8"));
+
+               assertEquals("[{a:'b'}]", model.getObjectList("f1", 
l).toString());
+               try { model.getObjectList("f2", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f3", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f4", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("[{a:'b'}]", model.getObjectList("f2a", 
l).toString());
+               assertEquals("[{a:'b'}]", model.getObjectList("f3a", 
l).toString());
+               assertEquals("[{a:'b'}]", model.getObjectList("f4a", 
l).toString());
+               assertEquals("[{a:'b'}]", model.getObjectList("f5", 
l).toString());
+               assertEquals("[{a:'b'}]", model.getObjectList("f6", 
l).toString());
+               assertEquals("[{a:'b'}]", model.getObjectList("f7", 
l).toString());
+               assertEquals("[{a:'b'}]", model.getObjectList("f8", 
l).toString());
+
+               ((A)model.getRootObject()).init();
+
+               assertEquals("1", model.get("f1"));
+               assertEquals("2", model.get("f2").toString());
+               assertEquals("3", model.get("f3").toString());
+               assertEquals("true", model.get("f4").toString());
+               assertEquals("2", model.get("f2a").toString());
+               assertEquals("3", model.get("f3a").toString());
+               assertEquals("true", model.get("f4a").toString());
+               assertEquals("{f5a:'a'}", model.get("f5").toString());
+               assertEquals("[{f6a:'a'}]", model.get("f6").toString());
+               assertEquals("{f5a:'a'}", model.get("f7").toString());
+               assertEquals("[{f6a:'a'}]", model.get("f8").toString());
+
+               assertEquals("1", model.get("f1", "foo"));
+               assertEquals("2", model.get("f2", "foo").toString());
+               assertEquals("3", model.get("f3", "foo").toString());
+               assertEquals("true", model.get("f4", "foo").toString());
+               assertEquals("2", model.get("f2a", "foo").toString());
+               assertEquals("3", model.get("f3a", "foo").toString());
+               assertEquals("true", model.get("f4a", "foo").toString());
+               assertEquals("{f5a:'a'}", model.get("f5", "foo").toString());
+               assertEquals("[{f6a:'a'}]", model.get("f6", "foo").toString());
+               assertEquals("{f5a:'a'}", model.get("f7", "foo").toString());
+               assertEquals("[{f6a:'a'}]", model.get("f8", "foo").toString());
+
+               assertEquals("1", model.getString("f1"));
+               assertEquals("2", model.getString("f2"));
+               assertEquals("3", model.getString("f3"));
+               assertEquals("true", model.getString("f4"));
+               assertEquals("2", model.getString("f2a"));
+               assertEquals("3", model.getString("f3a"));
+               assertEquals("true", model.getString("f4a"));
+               assertEquals("{f5a:'a'}", model.getString("f5"));
+               assertEquals("[{f6a:'a'}]", model.getString("f6"));
+               assertEquals("{f5a:'a'}", model.getString("f7"));
+               assertEquals("[{f6a:'a'}]", model.getString("f8"));
+
+               assertEquals("1", model.getString("f1", "foo"));
+               assertEquals("2", model.getString("f2", "foo"));
+               assertEquals("3", model.getString("f3", "foo"));
+               assertEquals("true", model.getString("f4", "foo"));
+               assertEquals("2", model.getString("f2a", "foo"));
+               assertEquals("3", model.getString("f3a", "foo"));
+               assertEquals("true", model.getString("f4a", "foo"));
+               assertEquals("{f5a:'a'}", model.getString("f5", "foo"));
+               assertEquals("[{f6a:'a'}]", model.getString("f6", "foo"));
+               assertEquals("{f5a:'a'}", model.getString("f7", "foo"));
+               assertEquals("[{f6a:'a'}]", model.getString("f8", "foo"));
+
+               assertEquals(1, (int)model.getInt("f1"));
+               assertEquals(2, (int)model.getInt("f2"));
+               assertEquals(3, (int)model.getInt("f3"));
+               assertEquals(1, (int)model.getInt("f4"));
+               assertEquals(2, (int)model.getInt("f2a"));
+               assertEquals(3, (int)model.getInt("f3a"));
+               assertEquals(1, (int)model.getInt("f4a"));
+               try { model.getInt("f5"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getInt("f6"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getInt("f7"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getInt("f8"); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               assertEquals(1, (int)model.getInt("f1", 9));
+               assertEquals(2, (int)model.getInt("f2", 9));
+               assertEquals(3, (int)model.getInt("f3", 9));
+               assertEquals(1, (int)model.getInt("f4", 9));
+               assertEquals(2, (int)model.getInt("f2a", 9));
+               assertEquals(3, (int)model.getInt("f3a", 9));
+               assertEquals(1, (int)model.getInt("f4a", 9));
+               try { model.getInt("f5", 9); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getInt("f6", 9); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getInt("f7", 9); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getInt("f8", 9); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               assertEquals(1, (long)model.getLong("f1"));
+               assertEquals(2, (long)model.getLong("f2"));
+               assertEquals(3, (long)model.getLong("f3"));
+               assertEquals(1, (long)model.getLong("f4"));
+               assertEquals(2, (long)model.getLong("f2a"));
+               assertEquals(3, (long)model.getLong("f3a"));
+               assertEquals(1, (long)model.getLong("f4a"));
+               try { model.getLong("f5"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getLong("f6"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getLong("f7"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getInt("f8"); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               assertEquals(1, (long)model.getLong("f1", 9l));
+               assertEquals(2, (long)model.getLong("f2", 9l));
+               assertEquals(3, (long)model.getLong("f3", 9l));
+               assertEquals(1, (long)model.getLong("f4", 9l));
+               assertEquals(2, (long)model.getLong("f2a", 9l));
+               assertEquals(3, (long)model.getLong("f3a", 9l));
+               assertEquals(1, (long)model.getLong("f4a", 9l));
+               try { model.getLong("f5", 9l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getLong("f6", 9l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getLong("f7", 9l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getLong("f8", 9l); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               assertEquals(false, model.getBoolean("f1"));  // String "1" 
equates to false.
+               assertEquals(true, model.getBoolean("f2"));
+               assertEquals(true, model.getBoolean("f3"));
+               assertEquals(true, model.getBoolean("f4"));
+               assertEquals(true, model.getBoolean("f2a"));
+               assertEquals(true, model.getBoolean("f3a"));
+               assertEquals(true, model.getBoolean("f4a"));
+               assertEquals(false, model.getBoolean("f5"));  // "{a:'b'}" 
equates to false.
+               assertEquals(false, model.getBoolean("f6"));
+               assertEquals(false, model.getBoolean("f7"));
+               assertEquals(false, model.getBoolean("f8"));
+
+               assertEquals(false, model.getBoolean("f1", true));  // String 
"1" equates to false.
+               assertEquals(true, model.getBoolean("f2", true));
+               assertEquals(true, model.getBoolean("f3", true));
+               assertEquals(true, model.getBoolean("f4", true));
+               assertEquals(true, model.getBoolean("f2a", true));
+               assertEquals(true, model.getBoolean("f3a", true));
+               assertEquals(true, model.getBoolean("f4a", true));
+               assertEquals(false, model.getBoolean("f5", true));  // 
"{a:'b'}" equates to false.
+               assertEquals(false, model.getBoolean("f6", true));
+               assertEquals(false, model.getBoolean("f7", true));
+               assertEquals(false, model.getBoolean("f8", true));
+
+               try { model.getMap("f1"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f2a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f3a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f4a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getMap("f5").toString());
+               try { model.getMap("f6"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getMap("f7").toString());
+               try { model.getMap("f8"); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               try { model.getMap("f1", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f2", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f3", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f4", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f2a", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f3a", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getMap("f4a", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getMap("f5", m).toString());
+               try { model.getMap("f6", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getMap("f7", m).toString());
+               try { model.getMap("f8", m); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               try { model.getObjectMap("f1"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f2a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f3a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f4a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getObjectMap("f5").toString());
+               try { model.getObjectMap("f6"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getObjectMap("f7").toString());
+               try { model.getObjectMap("f8"); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               try { model.getObjectMap("f1", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f2", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f3", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f4", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f2a", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f3a", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectMap("f4a", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getObjectMap("f5", 
m).toString());
+               try { model.getObjectMap("f6", m); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("{f5a:'a'}", model.getObjectMap("f7", 
m).toString());
+               try { model.getObjectMap("f8", m); fail(); } catch 
(InvalidDataConversionException e) {}
+
+               try { model.getList("f1"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f2a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f3a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f4a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("[{f5a:'a'}]", model.getList("f5").toString());
+               assertEquals("[{f6a:'a'}]", model.getList("f6").toString());
+               assertEquals("[{f5a:'a'}]", model.getList("f7").toString());
+               assertEquals("[{f6a:'a'}]", model.getList("f8").toString());
+
+               try { model.getList("f1", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f2", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f3", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f4", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f2a", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f3a", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getList("f4a", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("[{f5a:'a'}]", model.getList("f5", l).toString());
+               assertEquals("[{f6a:'a'}]", model.getList("f6", l).toString());
+               assertEquals("[{f5a:'a'}]", model.getList("f7", l).toString());
+               assertEquals("[{f6a:'a'}]", model.getList("f8", l).toString());
+
+               try { model.getObjectList("f1"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f2"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f3"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f4"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f2a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f3a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f4a"); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("[{f5a:'a'}]", 
model.getObjectList("f5").toString());
+               assertEquals("[{f6a:'a'}]", 
model.getObjectList("f6").toString());
+               assertEquals("[{f5a:'a'}]", 
model.getObjectList("f7").toString());
+               assertEquals("[{f6a:'a'}]", 
model.getObjectList("f8").toString());
+
+               try { model.getObjectList("f1", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f2", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f3", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f4", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f2a", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f3a", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               try { model.getObjectList("f4a", l); fail(); } catch 
(InvalidDataConversionException e) {}
+               assertEquals("[{f5a:'a'}]", model.getObjectList("f5", 
l).toString());
+               assertEquals("[{f6a:'a'}]", model.getObjectList("f6", 
l).toString());
+               assertEquals("[{f5a:'a'}]", model.getObjectList("f7", 
l).toString());
+               assertEquals("[{f6a:'a'}]", model.getObjectList("f8", 
l).toString());
+       }
+
+       public static class A {
+               public String f1;
+               public int f2;
+               public long f3;
+               public boolean f4;
+               public Integer f2a;
+               public Long f3a;
+               public Boolean f4a;
+               public Map f5;
+               public List f6;
+               public ObjectMap f7;
+               public ObjectList f8;
+
+               public A init() {
+                       f1 = "1";
+                       f2 = 2;
+                       f3 = 3l;
+                       f4 = true;
+                       f2a = 2;
+                       f3a = 3l;
+                       f4a = true;
+                       try {
+                               f5 = new ObjectMap("{f5a:'a'}");
+                               f6 = new ObjectList("[{f6a:'a'}]");
+                               f7 = new ObjectMap("{f5a:'a'}");
+                               f8 = new ObjectList("[{f6a:'a'}]");
+                       } catch (ParseException e) {
+                               throw new RuntimeException(e);
+                       }
+                       return this;
+               }
+       }
+
+       
//====================================================================================================
+       // invokeMethod(String url, String method, String args)
+       
//====================================================================================================
+       @Test
+       public void testInvokeMethod() throws Exception {
+
+               PojoRest model = new PojoRest(new AddressBook().init());
+               assertEquals("Person(name=Bill Clinton,age=65)", 
model.invokeMethod("0", "toString", ""));
+
+               model = new PojoRest(new AddressBook().init(), 
JsonParser.DEFAULT);
+               assertEquals("Person(name=Bill Clinton,age=65)", 
model.invokeMethod("0", "toString", ""));
+               assertEquals("NY", model.invokeMethod("0/addresses/0/state", 
"toString", ""));
+               assertNull(model.invokeMethod("1", "toString", ""));
+       }
+
+       
//====================================================================================================
+       // getPublicMethods(String url)
+       
//====================================================================================================
+       @Test
+       public void testGetPublicMethods() throws Exception {
+               PojoRest model = new PojoRest(new AddressBook().init());
+               
assertTrue(JsonSerializer.DEFAULT_LAX.toString(model.getPublicMethods("0")).contains("'toString'"));
+               
assertTrue(JsonSerializer.DEFAULT_LAX.toString(model.getPublicMethods("0/addresses/0/state")).contains("'toString'"));
+               assertNull(model.getPublicMethods("1"));
+       }
+
+       
//====================================================================================================
+       // getClassMeta(String url)
+       
//====================================================================================================
+       @Test
+       public void testGetClassMeta() throws Exception {
+               PojoRest model = new PojoRest(new AddressBook().init());
+               assertEquals("Person", 
model.getClassMeta("0").getInnerClass().getSimpleName());
+               assertEquals("String", 
model.getClassMeta("0/addresses/0/state").getInnerClass().getSimpleName());
+               assertNull(model.getClassMeta("1"));
+               assertNull(model.getClassMeta("0/addresses/1/state"));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/df0f8689/org.apache.juneau/src/test/java/org/apache/juneau/utils/SimpleMapTest.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/test/java/org/apache/juneau/utils/SimpleMapTest.java 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/SimpleMapTest.java
new file mode 100755
index 0000000..371222c
--- /dev/null
+++ b/org.apache.juneau/src/test/java/org/apache/juneau/utils/SimpleMapTest.java
@@ -0,0 +1,48 @@
+/***************************************************************************************************************************
+ * 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.utils;
+
+import static org.apache.juneau.TestUtils.*;
+import static org.junit.Assert.*;
+
+import org.apache.juneau.internal.*;
+import org.junit.*;
+
+public class SimpleMapTest {
+
+       @Test
+       public void doTest() throws Exception {
+               String[] keys = {"a","b"};
+               Object[] vals = {"A","B"};
+               SimpleMap m = new SimpleMap(keys, vals);
+               assertEquals(2, m.size());
+               assertEquals("A", m.get("a"));
+               assertEquals("B", m.get("b"));
+               assertObjectEquals("{a:'A',b:'B'}", m);
+               assertObjectEquals("['a','b']", m.keySet());
+               m.put("a", "1");
+               assertObjectEquals("{a:'1',b:'B'}", m);
+               m.entrySet().iterator().next().setValue("2");
+               assertObjectEquals("{a:'2',b:'B'}", m);
+               try { m.put("c", "1"); fail(); } catch 
(IllegalArgumentException e) {}
+
+               assertNull(m.get("c"));
+
+               try { m = new SimpleMap(null, vals); fail(); } catch 
(IllegalArgumentException e) {}
+               try { m = new SimpleMap(keys, null); fail(); } catch 
(IllegalArgumentException e) {}
+               try { m = new SimpleMap(keys, new Object[0]); fail(); } catch 
(IllegalArgumentException e) {}
+
+               keys[0] = null;
+               try { m = new SimpleMap(keys, vals); fail(); } catch 
(IllegalArgumentException e) {}
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/df0f8689/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringBuilderWriterTest.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringBuilderWriterTest.java
 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringBuilderWriterTest.java
new file mode 100755
index 0000000..2868fa4
--- /dev/null
+++ 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringBuilderWriterTest.java
@@ -0,0 +1,59 @@
+/***************************************************************************************************************************
+ * 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.utils;
+
+import static org.junit.Assert.*;
+
+import org.apache.juneau.internal.*;
+import org.junit.*;
+
+public class StringBuilderWriterTest {
+
+       
//====================================================================================================
+       // Basic tests
+       
//====================================================================================================
+       @Test
+       public void test() throws Exception {
+               StringBuilderWriter sbw = new StringBuilderWriter();
+               sbw.write("abc");
+               assertEquals("abc", sbw.toString());
+               sbw.append("abc");
+               assertEquals("abcabc", sbw.toString());
+               sbw.write("abc", 1, 1);
+               assertEquals("abcabcb", sbw.toString());
+               sbw.append("abc", 1, 2);
+               assertEquals("abcabcbb", sbw.toString());
+               sbw.write((String)null);
+               assertEquals("abcabcbbnull", sbw.toString());
+               sbw.append((String)null);
+               assertEquals("abcabcbbnullnull", sbw.toString());
+               sbw.append((String)null,0,4);
+               assertEquals("abcabcbbnullnullnull", sbw.toString());
+
+               char[] buff = "abc".toCharArray();
+               sbw = new StringBuilderWriter();
+               sbw.write(buff, 0, buff.length);
+               assertEquals("abc", sbw.toString());
+               sbw.write(buff, 0, 0);
+               assertEquals("abc", sbw.toString());
+
+               try { sbw.write(buff, -1, buff.length); fail(); } catch 
(IndexOutOfBoundsException e) {}
+               try { sbw.write(buff, buff.length+1, 0); fail(); } catch 
(IndexOutOfBoundsException e) {}
+               try { sbw.write(buff, buff.length-1, 2); fail(); } catch 
(IndexOutOfBoundsException e) {}
+               try { sbw.write(buff, 0, buff.length+1); fail(); } catch 
(IndexOutOfBoundsException e) {}
+               try { sbw.write(buff, 0, -1); fail(); } catch 
(IndexOutOfBoundsException e) {}
+
+               sbw.flush();
+               sbw.close();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/df0f8689/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringUtilsTest.java 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
new file mode 100755
index 0000000..139e575
--- /dev/null
+++ 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringUtilsTest.java
@@ -0,0 +1,676 @@
+/***************************************************************************************************************************
+ * 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.utils;
+
+import static org.apache.juneau.TestUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+import static org.junit.Assert.*;
+
+import java.io.ObjectInputStream.*;
+import java.math.*;
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transforms.*;
+import org.junit.*;
+
+public class StringUtilsTest {
+
+       
//====================================================================================================
+       // isNumeric(String,Class)
+       // parseNumber(String,Class)
+       
//====================================================================================================
+       @Test
+       public void testParseNumber() throws Exception {
+
+               // Integers
+               assertTrue(isNumeric("123"));
+               assertEquals(123, parseNumber("123", null));
+               assertEquals(123, parseNumber("123", Integer.class));
+               assertEquals((short)123, parseNumber("123", Short.class));
+               assertEquals((long)123, parseNumber("123", Long.class));
+
+               assertTrue(isNumeric("0123"));
+               assertEquals(0123, parseNumber("0123", null));
+
+               assertTrue(isNumeric("-0123"));
+               assertEquals(-0123, parseNumber("-0123", null));
+
+               // Hexadecimal
+               assertTrue(isNumeric("0x123"));
+               assertEquals(0x123, parseNumber("0x123", null));
+
+               assertTrue(isNumeric("-0x123"));
+               assertEquals(-0x123, parseNumber("-0x123", null));
+
+               assertTrue(isNumeric("0X123"));
+               assertEquals(0X123, parseNumber("0X123", null));
+
+               assertTrue(isNumeric("-0X123"));
+               assertEquals(-0X123, parseNumber("-0X123", null));
+
+               assertTrue(isNumeric("#123"));
+               assertEquals(0x123, parseNumber("#123", null));
+
+               assertTrue(isNumeric("-#123"));
+               assertEquals(-0x123, parseNumber("-#123", null));
+
+               assertFalse(isNumeric("x123"));
+               assertFalse(isNumeric("0x123x"));
+
+               // Decimal
+               assertTrue(isNumeric("0.123"));
+               assertEquals(0.123f, parseNumber("0.123", null));
+
+               assertTrue(isNumeric("-0.123"));
+               assertEquals(-0.123f, parseNumber("-0.123", null));
+
+               assertTrue(isNumeric(".123"));
+               assertEquals(.123f, parseNumber(".123", null));
+
+               assertTrue(isNumeric("-.123"));
+               assertEquals(-.123f, parseNumber("-.123", null));
+
+               assertFalse(isNumeric("0.123.4"));
+
+               // Scientific notation
+               assertTrue(isNumeric("1e1"));
+               assertEquals(1e1f, parseNumber("1e1", null));
+
+               assertTrue(isNumeric("1e+1"));
+               assertEquals(1e+1f, parseNumber("1e+1", null));
+
+               assertTrue(isNumeric("1e-1"));
+               assertEquals(1e-1f, parseNumber("1e-1", null));
+
+               assertTrue(isNumeric("1.1e1"));
+               assertEquals(1.1e1f, parseNumber("1.1e1", null));
+
+               assertTrue(isNumeric("1.1e+1"));
+               assertEquals(1.1e+1f, parseNumber("1.1e+1", null));
+
+               assertTrue(isNumeric("1.1e-1"));
+               assertEquals(1.1e-1f, parseNumber("1.1e-1", null));
+
+               assertTrue(isNumeric(".1e1"));
+               assertEquals(.1e1f, parseNumber(".1e1", null));
+
+               assertTrue(isNumeric(".1e+1"));
+               assertEquals(.1e+1f, parseNumber(".1e+1", null));
+
+               assertTrue(isNumeric(".1e-1"));
+               assertEquals(.1e-1f, parseNumber(".1e-1", null));
+
+               // Hexadecimal + scientific
+               assertTrue(isNumeric("0x123e1"));
+               assertEquals(0x123e1, parseNumber("0x123e1", null));
+
+               try {
+                       parseNumber("x", Number.class);
+                       fail();
+               } catch (ParseException e) {
+                       assertTrue(e.getCause() instanceof 
NumberFormatException);
+               }
+
+               try {
+                       parseNumber("x", null);
+                       fail();
+               } catch (ParseException e) {
+                       assertTrue(e.getCause() instanceof 
NumberFormatException);
+               }
+
+               try {
+                       parseNumber("x", BadNumber.class);
+                       fail();
+               } catch (ParseException e) {
+                       
assertTrue(e.getLocalizedMessage().startsWith("Unsupported Number type"));
+               }
+       }
+
+       @SuppressWarnings("serial")
+       private abstract static class BadNumber extends Number {}
+
+       
//====================================================================================================
+       // parseNumber(ParserReader,Class)
+       
//====================================================================================================
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       @Test
+       public void testParseNumberFromReader() throws Exception {
+               ParserReader in;
+               Number n;
+
+               for (Class c : new Class[]{ Integer.class, Double.class, 
Float.class, Long.class, Short.class, Byte.class, BigInteger.class, 
BigDecimal.class, Number.class, AtomicInteger.class, AtomicLong.class}) {
+                       in = new ParserReader("123'");
+                       n = parseNumber(in, c);
+                       assertTrue(c.isInstance(n));
+                       assertEquals(123, n.intValue());
+               }
+       }
+
+       
//====================================================================================================
+       // test - Basic tests
+       
//====================================================================================================
+       @Test
+       public void testNumberRanges() throws Exception {
+               String s;
+
+               // An integer range is -2,147,483,648 to 2,147,483,647
+
+               assertFalse(isNumeric(null));
+               assertFalse(isNumeric(""));
+               assertFalse(isNumeric("x"));
+
+               s = "-2147483648";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Integer);
+               assertEquals(-2147483648, parseNumber(s, null));
+
+               s = "2147483647";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Integer);
+               assertEquals(2147483647, parseNumber(s, null));
+
+               s = "-2147483649";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Long);
+               assertEquals(-2147483649L, parseNumber(s, null));
+
+               s = "2147483648";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Long);
+               assertEquals(2147483648L, parseNumber(s, null));
+
+               // An long range is -9,223,372,036,854,775,808 to 
+9,223,372,036,854,775,807
+
+               s = "-9223372036854775808";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Long);
+               assertEquals(-9223372036854775808L, parseNumber(s, null));
+
+               s = "9223372036854775807";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Long);
+               assertEquals(9223372036854775807L, parseNumber(s, null));
+
+               // Anything that falls outside this range should be a double.
+
+               s = "-9223372036854775809";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Double);
+               assertEquals(-9223372036854775808L, parseNumber(s, 
null).longValue());
+               assertEquals(-9.223372036854776E18, parseNumber(s, null));
+
+               s = "9223372036854775808";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Double);
+               assertEquals(9223372036854775807L, parseNumber(s, 
null).longValue());
+               assertEquals(9.223372036854776E18, parseNumber(s, null));
+
+               // Check case where string is longer than 20 characters since 
it's a different code path.
+
+               s = "-123456789012345678901";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Double);
+               assertEquals(-9223372036854775808L, parseNumber(s, 
null).longValue());
+               assertEquals(-1.2345678901234568E20, parseNumber(s, null));
+
+               s = "123456789012345678901";
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Double);
+               assertEquals(9223372036854775807L, parseNumber(s, 
null).longValue());
+               assertEquals(1.2345678901234568E20, parseNumber(s, null));
+
+               // Autodetected floating point numbers smaller than 
Float.MAX_VALUE
+               s = String.valueOf(Float.MAX_VALUE / 2);
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Float);
+               assertEquals(1.7014117E38f, parseNumber(s, null));
+
+               s = String.valueOf((-Float.MAX_VALUE) / 2);
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Float);
+               assertEquals(-1.7014117E38f, parseNumber(s, null));
+
+               // Autodetected floating point numbers larger than 
Float.MAX_VALUE
+               s = String.valueOf((double)Float.MAX_VALUE * 2);
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Double);
+               assertEquals("6.805646932770577E38", parseNumber(s, 
null).toString());
+
+               s = String.valueOf((double)Float.MAX_VALUE * -2);
+               assertTrue(isNumeric(s));
+               assertTrue(parseNumber(s, null) instanceof Double);
+               assertEquals("-6.805646932770577E38", parseNumber(s, 
null).toString());
+
+               s = String.valueOf("214748364x");
+               assertFalse(isNumeric(s));
+               try {
+                       parseNumber(s, Number.class);
+               } catch (ParseException e) {}
+
+               s = String.valueOf("2147483640x");
+               assertFalse(isNumeric(s));
+               try {
+                       parseNumber(s, Long.class);
+               } catch (ParseException e) {}
+
+
+       }
+
+       
//====================================================================================================
+       // testReplaceVars
+       
//====================================================================================================
+       @Test
+       public void testReplaceVars() throws Exception {
+               ObjectMap m = new 
ObjectMap("{a:'A',b:1,c:true,d:'{e}',e:'E{f}E',f:'F',g:'{a}',h:'a',i:null}");
+
+               String s = "xxx";
+               assertEquals("xxx", replaceVars(s, m));
+
+               s = "{a}";
+               assertEquals("A", replaceVars(s, m));
+               s = "{a}{a}";
+               assertEquals("AA", replaceVars(s, m));
+               s = "x{a}x";
+               assertEquals("xAx", replaceVars(s, m));
+               s = "x{a}x{a}x";
+               assertEquals("xAxAx", replaceVars(s, m));
+
+               s = "{b}";
+               assertEquals("1", replaceVars(s, m));
+               s = "{b}{b}";
+               assertEquals("11", replaceVars(s, m));
+               s = "x{b}x";
+               assertEquals("x1x", replaceVars(s, m));
+               s = "x{b}x{b}x";
+               assertEquals("x1x1x", replaceVars(s, m));
+
+               s = "{c}";
+               assertEquals("true", replaceVars(s, m));
+               s = "{c}{c}";
+               assertEquals("truetrue", replaceVars(s, m));
+               s = "x{c}x{c}x";
+               assertEquals("xtruextruex", replaceVars(s, m));
+
+               s = "{d}";
+               assertEquals("EFE", replaceVars(s, m));
+               s = "{d}{d}";
+               assertEquals("EFEEFE", replaceVars(s, m));
+               s = "x{d}x";
+               assertEquals("xEFEx", replaceVars(s, m));
+               s = "x{d}x{d}x";
+               assertEquals("xEFExEFEx", replaceVars(s, m));
+
+               s = "{g}";
+               assertEquals("A", replaceVars(s, m));
+               s = "{g}{g}";
+               assertEquals("AA", replaceVars(s, m));
+               s = "x{g}x";
+               assertEquals("xAx", replaceVars(s, m));
+               s = "x{g}x{g}x";
+               assertEquals("xAxAx", replaceVars(s, m));
+
+               s = "{x}";
+               assertEquals("{x}", replaceVars(s, m));
+               s = "{x}{x}";
+               assertEquals("{x}{x}", replaceVars(s, m));
+               s = "x{x}x{x}x";
+               assertEquals("x{x}x{x}x", replaceVars(s, m));
+
+               s = "{{g}}";
+               assertEquals("{A}", replaceVars(s, m));
+               s = "{{h}}";
+               assertEquals("A", replaceVars(s, m));
+
+               s = "{{i}}";
+               assertEquals("{}", replaceVars(s, m));
+               s = "{}";
+               assertEquals("{}", replaceVars(s, m));
+       }
+
+       
//====================================================================================================
+       // isFloat(String)
+       
//====================================================================================================
+       @Test
+       public void testisFloat() throws Exception {
+               String[] valid = {
+                       "+1.0",
+                       "-1.0",
+                       ".0",
+                       "NaN",
+                       "Infinity",
+                       "1e1",
+                       "-1e-1",
+                       "+1e+1",
+                       "-1.1e-1",
+                       "+1.1e+1",
+                       "1.1f",
+                       "1.1F",
+                       "1.1d",
+                       "1.1D",
+                       "0x1.fffffffffffffp1023",
+                       "0x1.FFFFFFFFFFFFFP1023",
+               };
+               for (String s : valid)
+                       assertTrue(isFloat(s));
+
+               String[] invalid = {
+                       null,
+                       "",
+                       "a",
+                       "+",
+                       "-",
+                       ".",
+                       "a",
+                       "+a",
+                       "11a",
+               };
+               for (String s : invalid)
+                       assertFalse(isFloat(s));
+       }
+
+       
//====================================================================================================
+       // isDecimal(String)
+       
//====================================================================================================
+       @Test
+       public void testisDecimal() throws Exception {
+               String[] valid = {
+                       "+1",
+                       "-1",
+                       "0x123",
+                       "0X123",
+                       "0xdef",
+                       "0XDEF",
+                       "#def",
+                       "#DEF",
+                       "0123",
+               };
+               for (String s : valid)
+                       assertTrue(isDecimal(s));
+
+               String[] invalid = {
+                       null,
+                       "",
+                       "a",
+                       "+",
+                       "-",
+                       ".",
+                       "0xdeg",
+                       "0XDEG",
+                       "#deg",
+                       "#DEG",
+                       "0128",
+                       "012A",
+               };
+               for (String s : invalid)
+                       assertFalse(isDecimal(s));
+       }
+
+       
//====================================================================================================
+       // join(Object[],String)
+       // join(int[],String)
+       // join(Collection,String)
+       // join(Object[],char)
+       // join(int[],char)
+       // join(Collection,char)
+       
//====================================================================================================
+       @Test
+       public void testJoin() throws Exception {
+               assertNull(join((Object[])null, ","));
+               assertEquals("1", join(new Object[]{1}, ","));
+               assertEquals("1,2", join(new Object[]{1,2}, ","));
+
+               assertNull(join((int[])null, ","));
+               assertEquals("1", join(new int[]{1}, ","));
+               assertEquals("1,2", join(new int[]{1,2}, ","));
+
+               assertNull(join((Collection<?>)null, ","));
+               assertEquals("1", join(Arrays.asList(new Integer[]{1}), ","));
+               assertEquals("1,2", join(Arrays.asList(new Integer[]{1,2}), 
","));
+
+               assertNull(join((Object[])null, ','));
+               assertEquals("1", join(new Object[]{1}, ','));
+               assertEquals("1,2", join(new Object[]{1,2}, ','));
+
+               assertNull(join((int[])null, ','));
+               assertEquals("1", join(new int[]{1}, ','));
+               assertEquals("1,2", join(new int[]{1,2}, ','));
+
+               assertNull(join((Collection<?>)null, ','));
+               assertEquals("1", join(Arrays.asList(new Integer[]{1}), ','));
+               assertEquals("1,2", join(Arrays.asList(new Integer[]{1,2}), 
','));
+       }
+
+       
//====================================================================================================
+       // split(String,char)
+       
//====================================================================================================
+       @Test
+       public void testSplit() throws Exception {
+               String[] r;
+
+               assertNull(split(null, ','));
+               assertObjectEquals("[]", split("", ','));
+               assertObjectEquals("['1']", split("1", ','));
+               assertObjectEquals("['1','2']", split("1,2", ','));
+               assertObjectEquals("['1,2']", split("1\\,2", ','));
+
+               r = split("1\\\\,2", ',');
+               assertEquals("1\\", r[0]);
+               assertEquals("2", r[1]);
+
+               r = split("1\\\\\\,2", ',');
+               assertEquals(1, r.length);
+               assertEquals("1\\,2", r[0]);
+
+               r = split("1,2\\", ',');
+               assertEquals("2\\", r[1]);
+
+               r = split("1,2\\\\", ',');
+               assertEquals("2\\", r[1]);
+
+               r = split("1,2\\,", ',');
+               assertEquals("2,", r[1]);
+
+               r = split("1,2\\\\,", ',');
+               assertEquals("2\\", r[1]);
+               assertEquals("", r[2]);
+       }
+
+       
//====================================================================================================
+       // nullIfEmpty(String)
+       
//====================================================================================================
+       @Test
+       public void testNullIfEmpty() throws Exception {
+               assertNull(nullIfEmpty(null));
+               assertNull(nullIfEmpty(""));
+               assertNotNull(nullIfEmpty("x"));
+       }
+
+       
//====================================================================================================
+       // unescapeChars(String,char[],char)
+       
//====================================================================================================
+       @Test
+       public void testUnescapeChars() throws Exception {
+               char[] toEscape = {'\\',',','|'};
+               char escape = '\\';
+
+               assertNull(unEscapeChars(null, toEscape, escape));
+               assertEquals("xxx", unEscapeChars("xxx", new char[0], escape));
+               assertEquals("xxx", unEscapeChars("xxx", null, escape));
+               assertEquals("xxx", unEscapeChars("xxx", toEscape, (char)0));
+
+               assertEquals("xxx", unEscapeChars("xxx", toEscape, escape));
+               assertEquals("x,xx", unEscapeChars("x\\,xx", toEscape, escape));
+               assertEquals("x\\xx", unEscapeChars("x\\xx", toEscape, escape));
+               assertEquals("x\\,xx", unEscapeChars("x\\\\,xx", toEscape, 
escape));
+               assertEquals("x\\,xx", unEscapeChars("x\\\\\\,xx", toEscape, 
escape));
+               assertEquals("\\", unEscapeChars("\\", toEscape, escape));
+               assertEquals(",", unEscapeChars("\\,", toEscape, escape));
+               assertEquals("|", unEscapeChars("\\|", toEscape, escape));
+
+               toEscape = new char[] {',','|'};
+               assertEquals("x\\\\xx", unEscapeChars("x\\\\xx", toEscape, 
escape));
+       }
+
+       
//====================================================================================================
+       // decodeHex(String)
+       
//====================================================================================================
+       @Test
+       public void testDecodeHex() throws Exception {
+               assertNull(decodeHex(null));
+               assertEquals("19azAZ", decodeHex("19azAZ"));
+               assertEquals("[0][1][ffff]", decodeHex("\u0000\u0001\uFFFF"));
+       }
+
+       
//====================================================================================================
+       // startsWith(String,char)
+       
//====================================================================================================
+       @Test
+       public void testStartsWith() throws Exception {
+               assertFalse(startsWith(null, 'a'));
+               assertFalse(startsWith("", 'a'));
+               assertTrue(startsWith("a", 'a'));
+               assertTrue(startsWith("ab", 'a'));
+       }
+
+       
//====================================================================================================
+       // endsWith(String,char)
+       
//====================================================================================================
+       @Test
+       public void testEndsWith() throws Exception {
+               assertFalse(endsWith(null, 'a'));
+               assertFalse(endsWith("", 'a'));
+               assertTrue(endsWith("a", 'a'));
+               assertTrue(endsWith("ba", 'a'));
+       }
+
+       
//====================================================================================================
+       // base64EncodeToString(String)
+       // base64DecodeToString(String)
+       
//====================================================================================================
+       @Test
+       public void testBase64EncodeToString() throws Exception {
+               String s = null;
+
+               assertEquals(s, base64DecodeToString(base64EncodeToString(s)));
+               s = "";
+               assertEquals(s, base64DecodeToString(base64EncodeToString(s)));
+               s = "foobar";
+               assertEquals(s, base64DecodeToString(base64EncodeToString(s)));
+               s = "\u0000\uffff";
+               assertEquals(s, base64DecodeToString(base64EncodeToString(s)));
+
+               try {
+                       base64Decode("a");
+                       fail();
+               } catch (IllegalArgumentException e) {
+                       assertEquals("Invalid BASE64 string length.  Must be 
multiple of 4.", e.getLocalizedMessage());
+                       // OK.
+               }
+               try {
+                       base64Decode("aaa");
+                       fail();
+               } catch (IllegalArgumentException e) {
+                       // OK.
+               }
+       }
+
+       
//====================================================================================================
+       // generateUUID(String)
+       
//====================================================================================================
+       @Test
+       public void testGenerateUUID() throws Exception {
+               for (int i = 0; i < 10; i++) {
+                       String s = generateUUID(i);
+                       assertEquals(i, s.length());
+                       for (char c : s.toCharArray())
+                               assertTrue(Character.isLowerCase(c) || 
Character.isDigit(c));
+               }
+       }
+
+       
//====================================================================================================
+       // trim(String)
+       
//====================================================================================================
+       @Test
+       public void testTrim() throws Exception {
+               assertNull(trim(null));
+               assertEquals("", trim(""));
+               assertEquals("", trim("  "));
+       }
+
+       
//====================================================================================================
+       // parseISO8601Date(String)
+       
//====================================================================================================
+       @Test
+       public void testParseISO8601Date() throws Exception {
+               WriterSerializer s = new 
JsonSerializer.Simple().addTransforms(DateTransform.ISO8601DTPNZ.class);
+
+               assertNull(parseISO8601Date(null));
+               assertNull(parseISO8601Date(""));
+
+               assertEquals("'2000-01-01T00:00:00.000'", 
s.serialize(parseISO8601Date("2000")));
+               assertEquals("'2000-02-01T00:00:00.000'", 
s.serialize(parseISO8601Date("2000-02")));
+               assertEquals("'2000-02-03T00:00:00.000'", 
s.serialize(parseISO8601Date("2000-02-03")));
+               assertEquals("'2000-02-03T04:00:00.000'", 
s.serialize(parseISO8601Date("2000-02-03T04")));
+               assertEquals("'2000-02-03T04:05:00.000'", 
s.serialize(parseISO8601Date("2000-02-03T04:05")));
+               assertEquals("'2000-02-03T04:05:06.000'", 
s.serialize(parseISO8601Date("2000-02-03T04:05:06")));
+               assertEquals("'2000-02-03T04:00:00.000'", 
s.serialize(parseISO8601Date("2000-02-03 04")));
+               assertEquals("'2000-02-03T04:05:00.000'", 
s.serialize(parseISO8601Date("2000-02-03 04:05")));
+               assertEquals("'2000-02-03T04:05:06.000'", 
s.serialize(parseISO8601Date("2000-02-03 04:05:06")));
+
+               // ISO8601 doesn't support milliseconds, so it gets trimmed.
+               assertEquals("'2000-02-03T04:05:06.000'", 
s.serialize(parseISO8601Date("2000-02-03 04:05:06,789")));
+       }
+
+       
//====================================================================================================
+       // pathStartsWith(String, String)
+       
//====================================================================================================
+       @Test
+       public void testPathStartsWith() throws Exception {
+               assertTrue(pathStartsWith("foo", "foo"));
+               assertTrue(pathStartsWith("foo/bar", "foo"));
+               assertFalse(pathStartsWith("foo2/bar", "foo"));
+               assertFalse(pathStartsWith("foo2", "foo"));
+               assertFalse(pathStartsWith("foo2", ""));
+       }
+
+       
//====================================================================================================
+       // getField(int, String, char)
+       
//====================================================================================================
+       @Test
+       public void testGetField() {
+               String in = "0,1,2";
+               assertEquals("0", getField(0, in, ','));
+               assertEquals("1", getField(1, in, ','));
+               assertEquals("2", getField(2, in, ','));
+               assertEquals("", getField(3, in, ','));
+
+               in = ",1,,3,";
+               assertEquals("", getField(0, in, ','));
+               assertEquals("1", getField(1, in, ','));
+               assertEquals("", getField(2, in, ','));
+               assertEquals("3", getField(3, in, ','));
+               assertEquals("", getField(4, in, ','));
+               assertEquals("", getField(5, in, ','));
+
+               in = "";
+               assertEquals("", getField(0, in, ','));
+
+               in = null;
+               assertEquals("", getField(0, in, ','));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/df0f8689/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
new file mode 100755
index 0000000..4f603bb
--- /dev/null
+++ 
b/org.apache.juneau/src/test/java/org/apache/juneau/utils/StringVarResolverTest.java
@@ -0,0 +1,332 @@
+/***************************************************************************************************************************
+ * 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.utils;
+
+import static org.junit.Assert.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.svl.*;
+import org.junit.*;
+
+public class StringVarResolverTest {
+
+       
//====================================================================================================
+       // test - Basic tests
+       
//====================================================================================================
+       @Test
+       public void test() throws Exception {
+               VarResolver vr = new VarResolver().addVars(XVar.class);
+               String t;
+
+               t = null;
+               assertEquals("", vr.resolve(t));
+
+               t = "";
+               assertEquals("", vr.resolve(t));
+
+               t = "foo";
+               assertEquals("foo", vr.resolve(t));
+
+               t = "$X{y}";
+               assertEquals("xyx", vr.resolve(t));
+
+               t = "$X{y}x";
+               assertEquals("xyxx", vr.resolve(t));
+
+               t = "x$X{y}";
+               assertEquals("xxyx", vr.resolve(t));
+
+               t = "$X{y}$X{y}";
+               assertEquals("xyxxyx", vr.resolve(t));
+
+               t = "z$X{y}z$X{y}z";
+               assertEquals("zxyxzxyxz", vr.resolve(t));
+
+               t = "$X{$X{y}}";
+               assertEquals("xxyxx", vr.resolve(t));
+
+               t = "$X{z$X{y}z}";
+               assertEquals("xzxyxzx", vr.resolve(t));
+
+               t = "$X.{y}";
+               assertEquals("$X.{y}", vr.resolve(t));
+
+               t = "z$X.{y}z";
+               assertEquals("z$X.{y}z", vr.resolve(t));
+
+               t = "z$X.{$X.{z}}z";
+               assertEquals("z$X.{$X.{z}}z", vr.resolve(t));
+
+               // Non-existent vars
+               t = "$Y{y}";
+               assertEquals("$Y{y}", vr.resolve(t));
+
+               t = "$Y{y}x";
+               assertEquals("$Y{y}x", vr.resolve(t));
+
+               t = "x$Y{y}";
+               assertEquals("x$Y{y}", vr.resolve(t));
+
+               // Incomplete vars
+               // TODO - fix
+//             t = "x$Y{y";
+//             assertEquals("x$Y{y", vr.resolve(t));
+       }
+
+       public static class XVar extends SimpleVar {
+               public XVar() {
+                       super("X");
+               }
+               @Override
+               public String resolve(VarResolverSession session, String arg) {
+                       return "x" + arg + "x";
+               }
+       }
+
+       
//====================================================================================================
+       // test - No-name variables
+       
//====================================================================================================
+       @Test
+       public void test2() throws Exception {
+               VarResolver vr = new VarResolver().addVars(BlankVar.class);
+               String t;
+
+               t = "${y}";
+               assertEquals("xyx", vr.resolve(t));
+
+               t = "${${y}}";
+               assertEquals("xxyxx", vr.resolve(t));
+
+               t = "${${y}${y}}";
+               assertEquals("xxyxxyxx", vr.resolve(t));
+
+               t = "z${z${y}z}z";
+               assertEquals("zxzxyxzxz", vr.resolve(t));
+       }
+
+       public static class BlankVar extends SimpleVar {
+               public BlankVar() {
+                       super("");
+               }
+               @Override
+               public String resolve(VarResolverSession session, String arg) {
+                       return "x" + arg + "x";
+               }
+       }
+
+       
//====================================================================================================
+       // test - No-name variables
+       
//====================================================================================================
+       @Test
+       public void testEscaped$() throws Exception {
+               VarResolver vr = new VarResolver().addVars(BlankVar.class);
+               String t;
+
+               t = "${y}";
+               assertEquals("xyx", vr.resolve(t));
+               t = "\\${y}";
+               assertEquals("${y}", vr.resolve(t));
+
+               t = "foo\\${y}foo";
+               assertEquals("foo${y}foo", vr.resolve(t));
+
+               // TODO - This doesn't work.
+               //t = "${\\${y}}";
+               //assertEquals("x${y}x", vr.resolve(t));
+       }
+
+       
//====================================================================================================
+       // test - Escape sequences.
+       
//====================================================================================================
+       @Test
+       public void testEscapedSequences() throws Exception {
+               VarResolver vr = new VarResolver().addVars(XVar.class);
+               String t;
+               char b = '\\';
+
+               t = "A|A".replace('|',b);
+               assertEquals("A|A".replace('|',b), vr.resolve(t));
+               t = "A||A".replace('|',b);
+               assertEquals("A|A".replace('|',b), vr.resolve(t));
+               t = "A|A$X{B}".replace('|',b);
+               assertEquals("A|AxBx".replace('|',b), vr.resolve(t));
+               t = "A||A$X{B}".replace('|',b);
+               assertEquals("A|AxBx".replace('|',b), vr.resolve(t));
+               t = "A|$X{B}".replace('|',b);
+               assertEquals("A$X{B}".replace('|',b), vr.resolve(t));
+               t = "A||$X{B}".replace('|',b);
+               assertEquals("A|xBx".replace('|',b), vr.resolve(t));
+               t = "A$X|{B}".replace('|',b);
+               assertEquals("A$X{B}".replace('|',b), vr.resolve(t));
+               t = "A$X{B|}".replace('|',b);
+               assertEquals("A$X{B}".replace('|',b), vr.resolve(t));
+               t = "A$X{B}|".replace('|',b);
+               assertEquals("AxBx|".replace('|',b), vr.resolve(t));
+       }
+
+       
//====================================================================================================
+       // Test $E variables
+       
//====================================================================================================
+       @Test
+       public void test$E() throws Exception {
+               String t;
+
+               t = "$E{PATH}";
+               
assertFalse(StringUtils.isEmpty(VarResolver.DEFAULT.resolve(t)));
+       }
+
+       
//====================================================================================================
+       // Test that StringResolver(parent) works as expected.
+       
//====================================================================================================
+       @Test
+       public void testParent() throws Exception {
+               VarResolver svr = 
VarResolver.DEFAULT.clone().addVars(XMultipartVar.class);
+               String t;
+               System.setProperty("a", "a1");
+               System.setProperty("b", "b1");
+
+               t = "$X{$S{a},$S{b}}";
+               assertEquals("a1+b1", svr.resolve(t));
+               t = "$X{$S{a}}";
+               assertEquals("a1", svr.resolve(t));
+       }
+
+       public static class XMultipartVar extends MultipartVar {
+               public XMultipartVar() {
+                       super("X");
+               }
+               @Override /* MultipartVar */
+               public String resolve(VarResolverSession session, String[] 
args) {
+                       return StringUtils.join(args, '+');
+               }
+       }
+
+       
//====================================================================================================
+       // Test false triggers.
+       
//====================================================================================================
+       @Test
+       public void testFalseTriggers() throws Exception {
+               VarResolver svr = VarResolver.DEFAULT.clone();
+               String in = null;
+
+               // Should reject names with characters outside A-Za-z
+               for (Class<?> c : new Class[]{InvalidVar1.class, 
InvalidVar2.class, InvalidVar3.class, InvalidVar4.class, InvalidVar5.class}) {
+                       try {
+                               svr.addVars(c);
+                               fail();
+                       } catch (IllegalArgumentException e) {
+                               assertEquals("Invalid var name.  Must consist 
of only uppercase and lowercase ASCII letters.", e.getLocalizedMessage());
+                       }
+               }
+
+               // These should all be unchanged.
+               in = "$@{foobar}";
+               assertEquals(in, svr.resolve(in));
+               in = "$[{foobar}";
+               assertEquals(in, svr.resolve(in));
+               in = "$`{foobar}";
+               assertEquals(in, svr.resolve(in));
+               in = "$|{foobar}";
+               assertEquals(in, svr.resolve(in));
+               in = "${{foobar}";
+               assertEquals(in, svr.resolve(in));
+               in = "${$foobar}";
+               assertEquals(in, svr.resolve(in));
+
+               System.setProperty("foobar", "baz");
+
+               in = "$";
+               assertEquals(in, svr.resolve(in));
+
+               in = "$S";
+               assertEquals(in, svr.resolve(in));
+
+               in = "$S{";
+               assertEquals(in, svr.resolve(in));
+
+               in = "$S{foobar";
+
+               assertEquals(in, svr.resolve(in));
+               in = "$S{foobar}$";
+               assertEquals("baz$", svr.resolve(in));
+
+               in = "$S{foobar}$S";
+               assertEquals("baz$S", svr.resolve(in));
+
+               in = "$S{foobar}$S{";
+               assertEquals("baz$S{", svr.resolve(in));
+
+               in = "$S{foobar}$S{foobar";
+               assertEquals("baz$S{foobar", svr.resolve(in));
+
+               System.clearProperty("foobar");
+               in = "$S{foobar}";
+
+               // Test nulls returned by StringVar.
+               // Should be converted to blanks.
+               svr.addVars(AlwaysNullVar.class);
+
+               in = "$A{xxx}";
+               assertEquals("", svr.resolve(in));
+               in = "x$A{xxx}";
+               assertEquals("x", svr.resolve(in));
+               in = "$A{xxx}x";
+               assertEquals("x", svr.resolve(in));
+       }
+
+       public static class AlwaysNullVar extends SimpleVar {
+               public AlwaysNullVar() {
+                       super("A");
+               }
+               @Override
+               public String resolve(VarResolverSession session, String key) {
+                       return null;
+               }
+       }
+
+       public static class InvalidVar extends SimpleVar {
+               public InvalidVar(String c) {
+                       super(c);
+               }
+               @Override
+               public String resolve(VarResolverSession session, String key) {
+                       return null;
+               }
+       }
+
+       public static class InvalidVar1 extends InvalidVar {
+               public InvalidVar1() {
+                       super(null);
+               }
+       }
+       public static class InvalidVar2 extends InvalidVar {
+               public InvalidVar2() {
+                       super("@");
+               }
+       }
+       public static class InvalidVar3 extends InvalidVar {
+               public InvalidVar3() {
+                       super("[");
+               }
+       }
+       public static class InvalidVar4 extends InvalidVar {
+               public InvalidVar4() {
+                       super("`");
+               }
+       }
+       public static class InvalidVar5 extends InvalidVar {
+               public InvalidVar5() {
+                       super("|");
+               }
+       }
+}

Reply via email to