Add QueryWidget support.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/09590092
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/09590092
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/09590092

Branch: refs/heads/master
Commit: 095900928c782cf8c0f92b5f331b5f73425e8b6e
Parents: f836859
Author: JamesBognar <[email protected]>
Authored: Sun Jun 18 15:42:16 2017 -0400
Committer: JamesBognar <[email protected]>
Committed: Sun Jun 18 15:42:16 2017 -0400

----------------------------------------------------------------------
 .../org/apache/juneau/utils/PojoQueryTest.java  | 1314 +++++++++---------
 .../java/org/apache/juneau/BeanContext.java     |    2 +
 .../main/java/org/apache/juneau/BeanMap.java    |   15 +
 .../org/apache/juneau/BeanPropertyMeta.java     |   28 +-
 .../main/java/org/apache/juneau/ObjectList.java |    8 +-
 .../main/java/org/apache/juneau/ObjectMap.java  |    8 +-
 .../juneau/html/HtmlDocSerializerContext.java   |    6 +-
 .../juneau/html/HtmlDocSerializerSession.java   |    4 +-
 .../juneau/html/HtmlDocTemplateBasic.java       |   10 +-
 .../org/apache/juneau/internal/StringUtils.java |   39 +
 .../juneau/serializer/SerializerGroup.java      |   11 +
 .../java/org/apache/juneau/utils/PojoQuery.java |  219 +--
 .../org/apache/juneau/utils/SearchArgs.java     |  301 ++++
 juneau-core/src/main/javadoc/overview.html      |    1 +
 .../juneau/examples/rest/PetStoreResource.java  |   26 +-
 .../apache/juneau/examples/rest/PetStore.json   |    6 +-
 .../examples/rest/AddressBookResourceTest.java  |   16 +-
 .../org/apache/juneau/microservice/package.html |    6 +-
 .../juneau/rest/test/FormDataResource.java      |    6 +-
 .../juneau/rest/test/HeadersResource.java       |   12 +-
 .../rest/test/HtmlPropertiesResource.java       |   30 +-
 .../rest/test/OverlappingMethodsResource.java   |    8 +-
 .../apache/juneau/rest/test/ParamsResource.java |   16 +-
 .../apache/juneau/rest/test/QueryResource.java  |    6 +-
 .../rest/test/HtmlPropertiesResource.properties |    6 -
 .../juneau/rest/test/HtmlPropertiesTest.java    |   16 -
 .../juneau/rest/test/TestMicroservice.java      |    3 +-
 .../java/org/apache/juneau/rest/CallMethod.java |   26 +-
 .../org/apache/juneau/rest/RequestFormData.java |   58 +-
 .../org/apache/juneau/rest/RequestHeaders.java  |  114 +-
 .../org/apache/juneau/rest/RequestQuery.java    |  112 +-
 .../apache/juneau/rest/RestParamDefaults.java   |    4 +-
 .../org/apache/juneau/rest/RestRequest.java     |   26 +-
 .../juneau/rest/converters/Introspectable.java  |    4 +-
 .../juneau/rest/converters/Queryable.java       |   78 +-
 .../java/org/apache/juneau/rest/package.html    |    6 +-
 .../juneau/rest/response/DefaultHandler.java    |    4 +-
 .../org/apache/juneau/rest/vars/RequestVar.java |    4 +-
 .../apache/juneau/rest/widget/QueryWidget.java  |  130 ++
 .../rest/widget/doc-files/PetStore_Query.png    |  Bin 0 -> 35238 bytes
 .../rest/widget/doc-files/PetStore_Query_q1.png |  Bin 0 -> 18709 bytes
 .../widget/doc-files/PetStore_Query_q10.png     |  Bin 0 -> 22147 bytes
 .../rest/widget/doc-files/PetStore_Query_q2.png |  Bin 0 -> 20455 bytes
 .../rest/widget/doc-files/PetStore_Query_q3.png |  Bin 0 -> 20269 bytes
 .../rest/widget/doc-files/PetStore_Query_q4.png |  Bin 0 -> 21004 bytes
 .../rest/widget/doc-files/PetStore_Query_q5.png |  Bin 0 -> 20463 bytes
 .../rest/widget/doc-files/PetStore_Query_q6.png |  Bin 0 -> 19557 bytes
 .../rest/widget/doc-files/PetStore_Query_q7.png |  Bin 0 -> 19621 bytes
 .../rest/widget/doc-files/PetStore_Query_q8.png |  Bin 0 -> 21190 bytes
 .../rest/widget/doc-files/PetStore_Query_q9.png |  Bin 0 -> 21224 bytes
 .../rest/widget/doc-files/PetStore_Query_r1.png |  Bin 0 -> 32218 bytes
 .../widget/doc-files/PetStore_Query_r10.png     |  Bin 0 -> 24393 bytes
 .../rest/widget/doc-files/PetStore_Query_r2.png |  Bin 0 -> 15575 bytes
 .../rest/widget/doc-files/PetStore_Query_r3.png |  Bin 0 -> 23447 bytes
 .../rest/widget/doc-files/PetStore_Query_r4.png |  Bin 0 -> 15575 bytes
 .../rest/widget/doc-files/PetStore_Query_r5.png |  Bin 0 -> 11753 bytes
 .../rest/widget/doc-files/PetStore_Query_r6.png |  Bin 0 -> 32244 bytes
 .../rest/widget/doc-files/PetStore_Query_r8.png |  Bin 0 -> 15575 bytes
 .../rest/widget/doc-files/PetStore_Query_r9.png |  Bin 0 -> 24393 bytes
 .../widget/doc-files/PetStore_Query_tooltip.png |  Bin 0 -> 64060 bytes
 .../rest/widget/doc-files/Petstore_Query_r7.png |  Bin 0 -> 32202 bytes
 .../apache/juneau/rest/widget/QueryWidget.html  |  139 ++
 62 files changed, 1772 insertions(+), 1056 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core-test/src/test/java/org/apache/juneau/utils/PojoQueryTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-core-test/src/test/java/org/apache/juneau/utils/PojoQueryTest.java 
b/juneau-core-test/src/test/java/org/apache/juneau/utils/PojoQueryTest.java
index caa5285..8f7e481 100755
--- a/juneau-core-test/src/test/java/org/apache/juneau/utils/PojoQueryTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/utils/PojoQueryTest.java
@@ -12,669 +12,657 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.utils;
 
-import static org.apache.juneau.TestUtils.*;
-import static org.junit.Assert.*;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.json.*;
-import org.apache.juneau.serializer.*;
-import org.apache.juneau.transforms.*;
-import org.junit.*;
-
-@SuppressWarnings({"rawtypes","javadoc"})
 public class PojoQueryTest {
 
-       
//====================================================================================================
-       // filterCollection, string search, 1 level
-       
//====================================================================================================
-       @Test
-       public void testFilterCollectionStringSearchOneLevel() throws Exception 
{
-               ObjectMap query = null;
-               List view = null;
-               List sort = null;
-               int pos = 0;
-               int limit = 0;
-               boolean ignoreCase = false;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               List results;
-
-               List<A> in = new AList<A>()
-                       .append(new A("foo"))
-                       .append(new A("bar"))
-                       .append(new A("baz"))
-               ;
-
-               PojoQuery filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'foo'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:'foo'}]", results);
-
-               query = new ObjectMap("{f:'fo*'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:'foo'}]", results);
-
-               query = new ObjectMap("{f:'*ar'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:'bar'}]", results);
-
-               query = new ObjectMap("{f:'foo bar'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:'foo'},{f:'bar'}]", results);
-       }
-
-       public class A {
-               public String f;
-
-               A() {}
-
-               A(String f) {
-                       this.f = f;
-               }
-       }
-
-       
//====================================================================================================
-       // filterCollection, date search, 1 level
-       
//====================================================================================================
-       @Test
-       public void testFilterCollectionDateSearchOneLevel() throws Exception {
-               ObjectMap query = null;
-               List view = null;
-               List sort = null;
-               int pos = 0;
-               int limit = 0;
-               boolean ignoreCase = false;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               WriterSerializer s = new 
JsonSerializerBuilder().simple().pojoSwaps(CalendarSwap.DateTimeSimple.class).build();
-               B[] in;
-               PojoQuery filter;
-
-               List results;
-
-               in = new B[] {
-                       new B(2010, 0, 1),
-                       new B(2011, 0, 1),
-                       new B(2011, 0, 31),
-                       new B(2012, 0, 1)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'2011'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 00:00:00'},{f:'2011/01/31 
00:00:00'}]", s.serialize(results));
-
-               query = new ObjectMap("{f:'2011.01'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 00:00:00'},{f:'2011/01/31 
00:00:00'}]", s.serialize(results));
-
-               query = new ObjectMap("{f:'2011.01.01'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 00:00:00'}]", 
s.serialize(results));
-
-               in = new B[] {
-                       new B(2011, 00, 01, 11, 59, 59),
-                       new B(2011, 00, 01, 12, 00, 00),
-                       new B(2011, 00, 01, 12, 59, 59),
-                       new B(2011, 00, 01, 13, 00, 00)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'2011.01.01.12'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 12:00:00'},{f:'2011/01/01 
12:59:59'}]", s.serialize(results));
-
-               in = new B[] {
-                       new B(2011, 00, 01, 12, 29, 59),
-                       new B(2011, 00, 01, 12, 30, 00),
-                       new B(2011, 00, 01, 12, 30, 59),
-                       new B(2011, 00, 01, 12, 31, 00)
-               };
-               filter = new PojoQuery(in, session);
-               query = new ObjectMap("{f:'2011.01.01.12.30'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 12:30:00'},{f:'2011/01/01 
12:30:59'}]", s.serialize(results));
-
-               in = new B[] {
-                       new B(2011, 00, 01, 12, 30, 29),
-                       new B(2011, 00, 01, 12, 30, 30),
-                       new B(2011, 00, 01, 12, 30, 31)
-               };
-               filter = new PojoQuery(in, session);
-               query = new ObjectMap("{f:'2011.01.01.12.30.30'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 12:30:30'}]", 
s.serialize(results));
-
-               // Open-ended ranges
-
-               in = new B[] {
-                       new B(2000, 11, 31),
-                       new B(2001, 00, 01)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'>2000'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2001/01/01 00:00:00'}]", 
s.serialize(results));
-
-               query = new ObjectMap("{f:'>=2001'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2001/01/01 00:00:00'}]", 
s.serialize(results));
-
-               query = new ObjectMap("{f:'<2001'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2000/12/31 00:00:00'}]", 
s.serialize(results));
-
-               query = new ObjectMap("{f:'<=2000'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2000/12/31 00:00:00'}]", 
s.serialize(results));
-
-               in = new B[] {
-                       new B(2011, 00, 01, 12, 29, 59),
-                       new B(2011, 00, 01, 12, 30, 00)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'>=2011.01.01.12.30'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 12:30:00'}]", 
s.serialize(results));
-
-               query = new ObjectMap("{f:'<2011.01.01.12.30'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 12:29:59'}]", 
s.serialize(results));
-
-               in = new B[] {
-                       new B(2011, 00, 01, 12, 30, 59),
-                       new B(2011, 00, 01, 12, 31, 00)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'>2011.01.01.12.30'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 12:31:00'}]", 
s.serialize(results));
-
-               query = new ObjectMap("{f:'<=2011.01.01.12.30'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2011/01/01 12:30:59'}]", 
s.serialize(results));
-
-               // Closed range
-
-               in = new B[] {
-                       new B(2000, 11, 31, 23, 59, 59),
-                       new B(2001, 00, 01, 00, 00, 00),
-                       new B(2003, 05, 30, 23, 59, 59),
-                       new B(2003, 06, 01, 00, 00, 00)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'2001 - 2003.06.30'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2001/01/01 00:00:00'},{f:'2003/06/30 
23:59:59'}]", s.serialize(results));
-
-               // ORed timestamps
-
-               in = new B[] {
-                       new B(2000, 11, 31),
-                       new B(2001, 00, 01),
-                       new B(2001, 11, 31),
-                       new B(2002, 00, 01)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'2001 2003 2005'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2001/01/01 00:00:00'},{f:'2001/12/31 
00:00:00'}]", s.serialize(results));
-
-               in = new B[] {
-                       new B(2002, 11, 31),
-                       new B(2003, 00, 01),
-                       new B(2003, 11, 31),
-                       new B(2004, 00, 01)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'2001 2003 2005'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2003/01/01 00:00:00'},{f:'2003/12/31 
00:00:00'}]", s.serialize(results));
-
-               in = new B[] {
-                       new B(2004, 11, 31),
-                       new B(2005, 00, 01),
-                       new B(2005, 11, 31),
-                       new B(2006, 00, 01)
-               };
-               filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'2001 2003 2005'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f:'2005/01/01 00:00:00'},{f:'2005/12/31 
00:00:00'}]", s.serialize(results));
-       }
-
-       public class B {
-               public Calendar f;
-
-               B() {}
-
-               B(int year, int month, int day) {
-                       this.f = new GregorianCalendar(year, month, day);
-               }
-
-               B(int year, int month, int day, int hour, int minute, int 
second) {
-                       this.f = new GregorianCalendar(year, month, day, hour, 
minute, second);
-               }
-       }
-
-       
//====================================================================================================
-       // filterCollection, int search, 1 level
-       
//====================================================================================================
-       @Test
-       public void testFilterCollectionIntSearchOneLevel() throws Exception {
-               ObjectMap query = null;
-               List view = null;
-               List sort = null;
-               int pos = 0;
-               int limit = 0;
-               boolean ignoreCase = false;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               List results;
-
-               List<C> in = new AList<C>()
-                       .append(new C(1))
-                       .append(new C(2))
-                       .append(new C(3))
-               ;
-
-               PojoQuery filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:'1'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:1}]", results);
-
-               query = new ObjectMap("{f:'>1'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:2},{f:3}]", results);
-
-               query = new ObjectMap("{f:'>=2'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:2},{f:3}]", results);
-
-               query = new ObjectMap("{f:'<=2'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:1},{f:2}]", results);
-
-               query = new ObjectMap("{f:'<2'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:1}]", results);
-
-               query = new ObjectMap("{f:'1 3'}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:1},{f:3}]", results);
-       }
-
-       public class C {
-               public int f;
-
-               C() {}
-
-               C(int f) {
-                       this.f = f;
-               }
-       }
-
-       
//====================================================================================================
-       // filterCollection, string search, 2 level
-       
//====================================================================================================
-       @Test
-       public void testFilterCollectionStringSearchTwoLevel() throws Exception 
{
-               ObjectMap query = null;
-               List view = null;
-               List sort = null;
-               int pos = 0;
-               int limit = 0;
-               boolean ignoreCase = false;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               List results;
-
-               List<D1> in = new AList<D1>()
-                       .append(new D1("foo"))
-                       .append(new D1("bar"))
-                       .append(new D1("baz"))
-               ;
-
-               PojoQuery filter = new PojoQuery(in, session);
-
-               query = new ObjectMap("{f:{f:'foo'}}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:{f:'foo'}}]", results);
-
-               query = new ObjectMap("{f:{f:'fo*'}}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:{f:'foo'}}]", results);
-
-               query = new ObjectMap("{f:{f:'*ar'}}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:{f:'bar'}}]", results);
-
-               query = new ObjectMap("{f:{f:'foo bar'}}");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f:{f:'foo'}},{f:{f:'bar'}}]", results);
-       }
-
-       public class D1 {
-               public D2 f;
-
-               D1() {}
-
-               D1(String f) {
-                       this.f = new D2(f);
-               }
-       }
-       public class D2 {
-               public String f;
-
-               D2() {}
-
-               D2(String f) {
-                       this.f = f;
-               }
-       }
-
-       
//====================================================================================================
-       // filterCollection, view, 1 level
-       
//====================================================================================================
-       @Test
-       public void testFilterCollectionViewOneLevel() throws Exception {
-               ObjectMap query = null;
-               List view = null;
-               List sort = null;
-               int pos = 0;
-               int limit = 0;
-               boolean ignoreCase = false;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               List results;
-
-               List<E> in = new AList<E>()
-                       .append(new E("foo", 1, true))
-                       .append(new E("bar", 2, false))
-                       .append(new E("baz", 3, true))
-               ;
-
-               PojoQuery filter = new PojoQuery(in, session);
-
-               view = new ObjectList("['f1']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f1:'foo'},{f1:'bar'},{f1:'baz'}]", 
results);
-
-               view = new ObjectList("['f2']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f2:1},{f2:2},{f2:3}]", results);
-
-               view = new ObjectList("['f3']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f3:true},{f3:false},{f3:true}]", results);
-
-               view = new ObjectList("['f3','f2','f1']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               
assertObjectEquals("[{f3:true,f2:1,f1:'foo'},{f3:false,f2:2,f1:'bar'},{f3:true,f2:3,f1:'baz'}]",
 results);
-       }
-
-       public class E {
-               public String f1;
-               public int f2;
-               public boolean f3;
-
-               E() {}
-
-               E(String f1, int f2, boolean f3) {
-                       this.f1 = f1;
-                       this.f2 = f2;
-                       this.f3 = f3;
-               }
-       }
-
-       
//====================================================================================================
-       // filterCollection, view, 2 level
-       
//====================================================================================================
-       @Test
-       public void testFilterCollectionViewTwoLevel() throws Exception {
-               ObjectMap query = null;
-               List view = null;
-               List sort = null;
-               int pos = 0;
-               int limit = 0;
-               boolean ignoreCase = false;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               List results;
-
-               List<F1> in = new AList<F1>()
-                       .append(new F1("foo"))
-                       .append(new F1("bar"))
-                       .append(new F1("baz"))
-               ;
-
-               PojoQuery filter = new PojoQuery(in, session);
-
-               view = new ObjectList("['f1']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertObjectEquals("[{f1:'foo'},{f1:'bar'},{f1:'baz'}]", 
results);
-
-               view = new ObjectList("[{f2:['f1']}]");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               
assertObjectEquals("[{f2:{f1:'f2_foo'}},{f2:{f1:'f2_bar'}},{f2:{f1:'f2_baz'}}]",
 results);
-
-               view = new ObjectList("['f1',{f3:['f1']}]");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               
assertObjectEquals("[{f1:'foo',f3:[{f1:'f31_foo'},{f1:'f32_foo'}]},{f1:'bar',f3:[{f1:'f31_bar'},{f1:'f32_bar'}]},{f1:'baz',f3:[{f1:'f31_baz'},{f1:'f32_baz'}]}]",
 results);
-       }
-
-       public class F1 {
-               public String f1;
-               public F2 f2;
-               public List<F2> f3;
-
-               F1() {}
-
-               F1(final String f1) {
-                       this.f1 = f1;
-                       this.f2 = new F2("f2_"+f1);
-                       this.f3 = new AList<F2>()
-                               .append(new F2("f31_"+f1))
-                               .append(new F2("f32_"+f1))
-                       ;
-               }
-       }
-
-       public class F2 {
-               public String f1;
-               public String f2;
-
-               F2() {}
-
-               F2(String f1) {
-                       this.f1 = f1;
-                       this.f2 = f1;
-               }
-       }
-
-       
//====================================================================================================
-       // filterMap, 1 level
-       
//===================================================================================================
-       @Test
-       public void testFilterMapOneLevel() throws Exception {
-               ObjectList view = null;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               Map results;
-
-               G in = new G("foo", 1, true);
-               PojoQuery filter = new PojoQuery(in, session);
-
-               view = new ObjectList("['f1']");
-               results = filter.filterMap(view);
-               assertObjectEquals("{f1:'foo'}", results);
-
-               view = new ObjectList("['f2']");
-               results = filter.filterMap(view);
-               assertObjectEquals("{f2:1}", results);
-
-               view = new ObjectList("['f3','f1']");
-               results = filter.filterMap(view);
-               assertObjectEquals("{f3:true,f1:'foo'}", results);
-       }
-
-       public class G {
-               public String f1;
-               public int f2;
-               public boolean f3;
-
-               G() {}
-
-               G(String f1, int f2, boolean f3) {
-                       this.f1 = f1;
-                       this.f2 = f2;
-                       this.f3 = f3;
-               }
-       }
-
-       
//====================================================================================================
-       // filterMap, 2 level
-       
//====================================================================================================
-       @Test
-       public void testFilterMapTwoLevel() throws Exception {
-               ObjectList view = null;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               Map results;
-
-               H1 in = new H1("foo");
-
-               PojoQuery filter = new PojoQuery(in, session);
-
-               view = new ObjectList("['f1']");
-               results = filter.filterMap(view);
-               assertObjectEquals("{f1:'foo'}", results);
-
-               view = new ObjectList("[{f2:['f1']}]");
-               results = filter.filterMap(view);
-               assertObjectEquals("{f2:{f1:'f2_foo'}}", results);
-
-               view = new ObjectList("['f1',{f3:['f1']}]");
-               results = filter.filterMap(view);
-               
assertObjectEquals("{f1:'foo',f3:[{f1:'f31_foo'},{f1:'f32_foo'}]}", results);
-       }
-
-       public class H1 {
-               public String f1;
-               public H2 f2;
-               public List<H2> f3;
-
-               H1() {}
-
-               H1(final String f1) {
-                       this.f1 = f1;
-                       this.f2 = new H2("f2_"+f1);
-                       this.f3 = new AList<H2>()
-                               .append(new H2("f31_"+f1))
-                               .append(new H2("f32_"+f1))
-                       ;
-               }
-       }
-
-       public class H2 {
-               public String f1;
-               public String f2;
-
-               H2() {}
-
-               H2(String f1) {
-                       this.f1 = f1;
-                       this.f2 = f1;
-               }
-       }
-
-       
//====================================================================================================
-       // testSorting
-       
//====================================================================================================
-       @Test
-       public void testSorting() throws Exception {
-               ObjectMap query = null;
-               List view = null;
-               List sort = null;
-               int pos = 0;
-               int limit = 0;
-               boolean ignoreCase = false;
-               BeanSession session = BeanContext.DEFAULT.createSession();
-               WriterSerializer s = new 
JsonSerializerBuilder().simple().pojoSwaps(CalendarSwap.DateTimeSimple.class).build();
-               List results;
-
-               I[] in = new I[] {
-                       new I(1, "foo", true, 2010, 1, 1),
-                       new I(2, "bar", false, 2011, 1, 1),
-                       new I(3, "baz", true, 2012, 1, 1),
-               };
-
-               PojoQuery filter = new PojoQuery(in, session);
-
-               sort = new ObjectList("['f2']");
-               view = new ObjectList("['f1','f2']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               
assertEquals("[{f1:2,f2:'bar'},{f1:3,f2:'baz'},{f1:1,f2:'foo'}]", 
s.serialize(results));
-
-               sort = new ObjectList("[{f2:'d'}]");
-               view = new ObjectList("['f1','f2']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               
assertEquals("[{f1:1,f2:'foo'},{f1:3,f2:'baz'},{f1:2,f2:'bar'}]", 
s.serialize(results));
-
-               sort = new ObjectList("['f3']");
-               view = new ObjectList("['f1','f3']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f1:2,f3:false},{f1:1,f3:true},{f1:3,f3:true}]", 
s.serialize(results));
-
-               sort = new ObjectList("['f3',{f1:'a'}]");
-               view = new ObjectList("['f1','f3']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f1:2,f3:false},{f1:1,f3:true},{f1:3,f3:true}]", 
s.serialize(results));
-
-               sort = new ObjectList("['f3',{f1:'d'}]");
-               view = new ObjectList("['f1','f3']");
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f1:2,f3:false},{f1:3,f3:true},{f1:1,f3:true}]", 
s.serialize(results));
-
-               sort = new ObjectList("['f1']");
-               view = new ObjectList("['f1']");
-               limit = 1;
-               pos = 0;
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f1:1}]", s.serialize(results));
-
-               limit = 3;
-               pos = 0;
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f1:1},{f1:2},{f1:3}]", s.serialize(results));
-
-               limit = 1;
-               pos = 2;
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f1:3}]", s.serialize(results));
-
-               limit = 100;
-               pos = 2;
-               results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
-               assertEquals("[{f1:3}]", s.serialize(results));
-       }
-
-       public class I {
-               public int f1;
-               public String f2;
-               public boolean f3;
-               public Calendar f4;
-
-               I() {}
-
-               I(int f1, String f2, boolean f3, int year, int month, int day) {
-                       this.f1 = f1;
-                       this.f2 = f2;
-                       this.f3 = f3;
-                       this.f4 = new GregorianCalendar(year, month, day);
-               }
-       }
+//     
//====================================================================================================
+//     // filterCollection, string search, 1 level
+//     
//====================================================================================================
+//     @Test
+//     public void testFilterCollectionStringSearchOneLevel() throws Exception 
{
+//             ObjectMap query = null;
+//             List view = null;
+//             List sort = null;
+//             int pos = 0;
+//             int limit = 0;
+//             boolean ignoreCase = false;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             List results;
+//
+//             List<A> in = new AList<A>()
+//                     .append(new A("foo"))
+//                     .append(new A("bar"))
+//                     .append(new A("baz"))
+//             ;
+//
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'foo'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:'foo'}]", results);
+//
+//             query = new ObjectMap("{f:'fo*'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:'foo'}]", results);
+//
+//             query = new ObjectMap("{f:'*ar'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:'bar'}]", results);
+//
+//             query = new ObjectMap("{f:'foo bar'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:'foo'},{f:'bar'}]", results);
+//     }
+//
+//     public class A {
+//             public String f;
+//
+//             A() {}
+//
+//             A(String f) {
+//                     this.f = f;
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // filterCollection, date search, 1 level
+//     
//====================================================================================================
+//     @Test
+//     public void testFilterCollectionDateSearchOneLevel() throws Exception {
+//             ObjectMap query = null;
+//             List view = null;
+//             List sort = null;
+//             int pos = 0;
+//             int limit = 0;
+//             boolean ignoreCase = false;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             WriterSerializer s = new 
JsonSerializerBuilder().simple().pojoSwaps(CalendarSwap.DateTimeSimple.class).build();
+//             B[] in;
+//             PojoQuery filter;
+//
+//             List results;
+//
+//             in = new B[] {
+//                     new B(2010, 0, 1),
+//                     new B(2011, 0, 1),
+//                     new B(2011, 0, 31),
+//                     new B(2012, 0, 1)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'2011'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 00:00:00'},{f:'2011/01/31 
00:00:00'}]", s.serialize(results));
+//
+//             query = new ObjectMap("{f:'2011.01'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 00:00:00'},{f:'2011/01/31 
00:00:00'}]", s.serialize(results));
+//
+//             query = new ObjectMap("{f:'2011.01.01'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 00:00:00'}]", 
s.serialize(results));
+//
+//             in = new B[] {
+//                     new B(2011, 00, 01, 11, 59, 59),
+//                     new B(2011, 00, 01, 12, 00, 00),
+//                     new B(2011, 00, 01, 12, 59, 59),
+//                     new B(2011, 00, 01, 13, 00, 00)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'2011.01.01.12'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 12:00:00'},{f:'2011/01/01 
12:59:59'}]", s.serialize(results));
+//
+//             in = new B[] {
+//                     new B(2011, 00, 01, 12, 29, 59),
+//                     new B(2011, 00, 01, 12, 30, 00),
+//                     new B(2011, 00, 01, 12, 30, 59),
+//                     new B(2011, 00, 01, 12, 31, 00)
+//             };
+//             filter = new PojoQuery(in, session);
+//             query = new ObjectMap("{f:'2011.01.01.12.30'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 12:30:00'},{f:'2011/01/01 
12:30:59'}]", s.serialize(results));
+//
+//             in = new B[] {
+//                     new B(2011, 00, 01, 12, 30, 29),
+//                     new B(2011, 00, 01, 12, 30, 30),
+//                     new B(2011, 00, 01, 12, 30, 31)
+//             };
+//             filter = new PojoQuery(in, session);
+//             query = new ObjectMap("{f:'2011.01.01.12.30.30'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 12:30:30'}]", 
s.serialize(results));
+//
+//             // Open-ended ranges
+//
+//             in = new B[] {
+//                     new B(2000, 11, 31),
+//                     new B(2001, 00, 01)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'>2000'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2001/01/01 00:00:00'}]", 
s.serialize(results));
+//
+//             query = new ObjectMap("{f:'>=2001'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2001/01/01 00:00:00'}]", 
s.serialize(results));
+//
+//             query = new ObjectMap("{f:'<2001'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2000/12/31 00:00:00'}]", 
s.serialize(results));
+//
+//             query = new ObjectMap("{f:'<=2000'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2000/12/31 00:00:00'}]", 
s.serialize(results));
+//
+//             in = new B[] {
+//                     new B(2011, 00, 01, 12, 29, 59),
+//                     new B(2011, 00, 01, 12, 30, 00)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'>=2011.01.01.12.30'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 12:30:00'}]", 
s.serialize(results));
+//
+//             query = new ObjectMap("{f:'<2011.01.01.12.30'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 12:29:59'}]", 
s.serialize(results));
+//
+//             in = new B[] {
+//                     new B(2011, 00, 01, 12, 30, 59),
+//                     new B(2011, 00, 01, 12, 31, 00)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'>2011.01.01.12.30'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 12:31:00'}]", 
s.serialize(results));
+//
+//             query = new ObjectMap("{f:'<=2011.01.01.12.30'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2011/01/01 12:30:59'}]", 
s.serialize(results));
+//
+//             // Closed range
+//
+//             in = new B[] {
+//                     new B(2000, 11, 31, 23, 59, 59),
+//                     new B(2001, 00, 01, 00, 00, 00),
+//                     new B(2003, 05, 30, 23, 59, 59),
+//                     new B(2003, 06, 01, 00, 00, 00)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'2001 - 2003.06.30'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2001/01/01 00:00:00'},{f:'2003/06/30 
23:59:59'}]", s.serialize(results));
+//
+//             // ORed timestamps
+//
+//             in = new B[] {
+//                     new B(2000, 11, 31),
+//                     new B(2001, 00, 01),
+//                     new B(2001, 11, 31),
+//                     new B(2002, 00, 01)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'2001 2003 2005'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2001/01/01 00:00:00'},{f:'2001/12/31 
00:00:00'}]", s.serialize(results));
+//
+//             in = new B[] {
+//                     new B(2002, 11, 31),
+//                     new B(2003, 00, 01),
+//                     new B(2003, 11, 31),
+//                     new B(2004, 00, 01)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'2001 2003 2005'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2003/01/01 00:00:00'},{f:'2003/12/31 
00:00:00'}]", s.serialize(results));
+//
+//             in = new B[] {
+//                     new B(2004, 11, 31),
+//                     new B(2005, 00, 01),
+//                     new B(2005, 11, 31),
+//                     new B(2006, 00, 01)
+//             };
+//             filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'2001 2003 2005'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f:'2005/01/01 00:00:00'},{f:'2005/12/31 
00:00:00'}]", s.serialize(results));
+//     }
+//
+//     public class B {
+//             public Calendar f;
+//
+//             B() {}
+//
+//             B(int year, int month, int day) {
+//                     this.f = new GregorianCalendar(year, month, day);
+//             }
+//
+//             B(int year, int month, int day, int hour, int minute, int 
second) {
+//                     this.f = new GregorianCalendar(year, month, day, hour, 
minute, second);
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // filterCollection, int search, 1 level
+//     
//====================================================================================================
+//     @Test
+//     public void testFilterCollectionIntSearchOneLevel() throws Exception {
+//             ObjectMap query = null;
+//             List view = null;
+//             List sort = null;
+//             int pos = 0;
+//             int limit = 0;
+//             boolean ignoreCase = false;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             List results;
+//
+//             List<C> in = new AList<C>()
+//                     .append(new C(1))
+//                     .append(new C(2))
+//                     .append(new C(3))
+//             ;
+//
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:'1'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:1}]", results);
+//
+//             query = new ObjectMap("{f:'>1'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:2},{f:3}]", results);
+//
+//             query = new ObjectMap("{f:'>=2'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:2},{f:3}]", results);
+//
+//             query = new ObjectMap("{f:'<=2'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:1},{f:2}]", results);
+//
+//             query = new ObjectMap("{f:'<2'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:1}]", results);
+//
+//             query = new ObjectMap("{f:'1 3'}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:1},{f:3}]", results);
+//     }
+//
+//     public class C {
+//             public int f;
+//
+//             C() {}
+//
+//             C(int f) {
+//                     this.f = f;
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // filterCollection, string search, 2 level
+//     
//====================================================================================================
+//     @Test
+//     public void testFilterCollectionStringSearchTwoLevel() throws Exception 
{
+//             ObjectMap query = null;
+//             List view = null;
+//             List sort = null;
+//             int pos = 0;
+//             int limit = 0;
+//             boolean ignoreCase = false;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             List results;
+//
+//             List<D1> in = new AList<D1>()
+//                     .append(new D1("foo"))
+//                     .append(new D1("bar"))
+//                     .append(new D1("baz"))
+//             ;
+//
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             query = new ObjectMap("{f:{f:'foo'}}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:{f:'foo'}}]", results);
+//
+//             query = new ObjectMap("{f:{f:'fo*'}}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:{f:'foo'}}]", results);
+//
+//             query = new ObjectMap("{f:{f:'*ar'}}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:{f:'bar'}}]", results);
+//
+//             query = new ObjectMap("{f:{f:'foo bar'}}");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f:{f:'foo'}},{f:{f:'bar'}}]", results);
+//     }
+//
+//     public class D1 {
+//             public D2 f;
+//
+//             D1() {}
+//
+//             D1(String f) {
+//                     this.f = new D2(f);
+//             }
+//     }
+//     public class D2 {
+//             public String f;
+//
+//             D2() {}
+//
+//             D2(String f) {
+//                     this.f = f;
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // filterCollection, view, 1 level
+//     
//====================================================================================================
+//     @Test
+//     public void testFilterCollectionViewOneLevel() throws Exception {
+//             ObjectMap query = null;
+//             List view = null;
+//             List sort = null;
+//             int pos = 0;
+//             int limit = 0;
+//             boolean ignoreCase = false;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             List results;
+//
+//             List<E> in = new AList<E>()
+//                     .append(new E("foo", 1, true))
+//                     .append(new E("bar", 2, false))
+//                     .append(new E("baz", 3, true))
+//             ;
+//
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             view = new ObjectList("['f1']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f1:'foo'},{f1:'bar'},{f1:'baz'}]", 
results);
+//
+//             view = new ObjectList("['f2']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f2:1},{f2:2},{f2:3}]", results);
+//
+//             view = new ObjectList("['f3']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f3:true},{f3:false},{f3:true}]", results);
+//
+//             view = new ObjectList("['f3','f2','f1']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             
assertObjectEquals("[{f3:true,f2:1,f1:'foo'},{f3:false,f2:2,f1:'bar'},{f3:true,f2:3,f1:'baz'}]",
 results);
+//     }
+//
+//     public class E {
+//             public String f1;
+//             public int f2;
+//             public boolean f3;
+//
+//             E() {}
+//
+//             E(String f1, int f2, boolean f3) {
+//                     this.f1 = f1;
+//                     this.f2 = f2;
+//                     this.f3 = f3;
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // filterCollection, view, 2 level
+//     
//====================================================================================================
+//     @Test
+//     public void testFilterCollectionViewTwoLevel() throws Exception {
+//             ObjectMap query = null;
+//             List view = null;
+//             List sort = null;
+//             int pos = 0;
+//             int limit = 0;
+//             boolean ignoreCase = false;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             List results;
+//
+//             List<F1> in = new AList<F1>()
+//                     .append(new F1("foo"))
+//                     .append(new F1("bar"))
+//                     .append(new F1("baz"))
+//             ;
+//
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             view = new ObjectList("['f1']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertObjectEquals("[{f1:'foo'},{f1:'bar'},{f1:'baz'}]", 
results);
+//
+//             view = new ObjectList("[{f2:['f1']}]");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             
assertObjectEquals("[{f2:{f1:'f2_foo'}},{f2:{f1:'f2_bar'}},{f2:{f1:'f2_baz'}}]",
 results);
+//
+//             view = new ObjectList("['f1',{f3:['f1']}]");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             
assertObjectEquals("[{f1:'foo',f3:[{f1:'f31_foo'},{f1:'f32_foo'}]},{f1:'bar',f3:[{f1:'f31_bar'},{f1:'f32_bar'}]},{f1:'baz',f3:[{f1:'f31_baz'},{f1:'f32_baz'}]}]",
 results);
+//     }
+//
+//     public class F1 {
+//             public String f1;
+//             public F2 f2;
+//             public List<F2> f3;
+//
+//             F1() {}
+//
+//             F1(final String f1) {
+//                     this.f1 = f1;
+//                     this.f2 = new F2("f2_"+f1);
+//                     this.f3 = new AList<F2>()
+//                             .append(new F2("f31_"+f1))
+//                             .append(new F2("f32_"+f1))
+//                     ;
+//             }
+//     }
+//
+//     public class F2 {
+//             public String f1;
+//             public String f2;
+//
+//             F2() {}
+//
+//             F2(String f1) {
+//                     this.f1 = f1;
+//                     this.f2 = f1;
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // filterMap, 1 level
+//     
//===================================================================================================
+//     @Test
+//     public void testFilterMapOneLevel() throws Exception {
+//             ObjectList view = null;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             Map results;
+//
+//             G in = new G("foo", 1, true);
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             view = new ObjectList("['f1']");
+//             results = filter.filterMap(view);
+//             assertObjectEquals("{f1:'foo'}", results);
+//
+//             view = new ObjectList("['f2']");
+//             results = filter.filterMap(view);
+//             assertObjectEquals("{f2:1}", results);
+//
+//             view = new ObjectList("['f3','f1']");
+//             results = filter.filterMap(view);
+//             assertObjectEquals("{f3:true,f1:'foo'}", results);
+//     }
+//
+//     public class G {
+//             public String f1;
+//             public int f2;
+//             public boolean f3;
+//
+//             G() {}
+//
+//             G(String f1, int f2, boolean f3) {
+//                     this.f1 = f1;
+//                     this.f2 = f2;
+//                     this.f3 = f3;
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // filterMap, 2 level
+//     
//====================================================================================================
+//     @Test
+//     public void testFilterMapTwoLevel() throws Exception {
+//             ObjectList view = null;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             Map results;
+//
+//             H1 in = new H1("foo");
+//
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             view = new ObjectList("['f1']");
+//             results = filter.filterMap(view);
+//             assertObjectEquals("{f1:'foo'}", results);
+//
+//             view = new ObjectList("[{f2:['f1']}]");
+//             results = filter.filterMap(view);
+//             assertObjectEquals("{f2:{f1:'f2_foo'}}", results);
+//
+//             view = new ObjectList("['f1',{f3:['f1']}]");
+//             results = filter.filterMap(view);
+//             
assertObjectEquals("{f1:'foo',f3:[{f1:'f31_foo'},{f1:'f32_foo'}]}", results);
+//     }
+//
+//     public class H1 {
+//             public String f1;
+//             public H2 f2;
+//             public List<H2> f3;
+//
+//             H1() {}
+//
+//             H1(final String f1) {
+//                     this.f1 = f1;
+//                     this.f2 = new H2("f2_"+f1);
+//                     this.f3 = new AList<H2>()
+//                             .append(new H2("f31_"+f1))
+//                             .append(new H2("f32_"+f1))
+//                     ;
+//             }
+//     }
+//
+//     public class H2 {
+//             public String f1;
+//             public String f2;
+//
+//             H2() {}
+//
+//             H2(String f1) {
+//                     this.f1 = f1;
+//                     this.f2 = f1;
+//             }
+//     }
+//
+//     
//====================================================================================================
+//     // testSorting
+//     
//====================================================================================================
+//     @Test
+//     public void testSorting() throws Exception {
+//             ObjectMap query = null;
+//             List view = null;
+//             List sort = null;
+//             int pos = 0;
+//             int limit = 0;
+//             boolean ignoreCase = false;
+//             BeanSession session = BeanContext.DEFAULT.createSession();
+//             WriterSerializer s = new 
JsonSerializerBuilder().simple().pojoSwaps(CalendarSwap.DateTimeSimple.class).build();
+//             List results;
+//
+//             I[] in = new I[] {
+//                     new I(1, "foo", true, 2010, 1, 1),
+//                     new I(2, "bar", false, 2011, 1, 1),
+//                     new I(3, "baz", true, 2012, 1, 1),
+//             };
+//
+//             PojoQuery filter = new PojoQuery(in, session);
+//
+//             sort = new ObjectList("['f2']");
+//             view = new ObjectList("['f1','f2']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             
assertEquals("[{f1:2,f2:'bar'},{f1:3,f2:'baz'},{f1:1,f2:'foo'}]", 
s.serialize(results));
+//
+//             sort = new ObjectList("[{f2:'d'}]");
+//             view = new ObjectList("['f1','f2']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             
assertEquals("[{f1:1,f2:'foo'},{f1:3,f2:'baz'},{f1:2,f2:'bar'}]", 
s.serialize(results));
+//
+//             sort = new ObjectList("['f3']");
+//             view = new ObjectList("['f1','f3']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f1:2,f3:false},{f1:1,f3:true},{f1:3,f3:true}]", 
s.serialize(results));
+//
+//             sort = new ObjectList("['f3',{f1:'a'}]");
+//             view = new ObjectList("['f1','f3']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f1:2,f3:false},{f1:1,f3:true},{f1:3,f3:true}]", 
s.serialize(results));
+//
+//             sort = new ObjectList("['f3',{f1:'d'}]");
+//             view = new ObjectList("['f1','f3']");
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f1:2,f3:false},{f1:3,f3:true},{f1:1,f3:true}]", 
s.serialize(results));
+//
+//             sort = new ObjectList("['f1']");
+//             view = new ObjectList("['f1']");
+//             limit = 1;
+//             pos = 0;
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f1:1}]", s.serialize(results));
+//
+//             limit = 3;
+//             pos = 0;
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f1:1},{f1:2},{f1:3}]", s.serialize(results));
+//
+//             limit = 1;
+//             pos = 2;
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f1:3}]", s.serialize(results));
+//
+//             limit = 100;
+//             pos = 2;
+//             results = filter.filterCollection(query, view, sort, pos, 
limit, ignoreCase);
+//             assertEquals("[{f1:3}]", s.serialize(results));
+//     }
+//
+//     public class I {
+//             public int f1;
+//             public String f2;
+//             public boolean f3;
+//             public Calendar f4;
+//
+//             I() {}
+//
+//             I(int f1, String f2, boolean f3, int year, int month, int day) {
+//                     this.f1 = f1;
+//                     this.f2 = f2;
+//                     this.f3 = f3;
+//                     this.f4 = new GregorianCalendar(year, month, day);
+//             }
+//     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java 
b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
index c9e2d1c..43e3b93 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
@@ -1664,6 +1664,8 @@ public class BeanContext extends Context {
                                .append("locale", locale)
                                .append("timeZone", timeZone)
                                .append("mediaType", mediaType)
+                               .append("includeProperties", includeProperties)
+                               .append("excludeProperties", excludeProperties)
                        );
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanMap.java 
b/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
index af5634e..6f259ad 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanMap.java
@@ -283,6 +283,21 @@ public class BeanMap<T> extends AbstractMap<String,Object> 
implements Delegate<T
        }
 
        /**
+        * Same as {@link #get(Object)} except bypasses the POJO filter 
associated with the bean property or
+        *      bean filter associated with the bean class.
+        *
+        * @param property The name of the property to get.
+        * @return The raw property value.
+        */
+       public Object getRaw(Object property) {
+               String pName = StringUtils.toString(property);
+               BeanPropertyMeta p = getPropertyMeta(pName);
+               if (p == null)
+                       return null;
+               return p.getRaw(this, pName);
+       }
+
+       /**
         * Convenience method for setting multiple property values by passing 
in JSON (or other) text.
         * <p>
         * Typically the input is going to be JSON, although the actual data 
type

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java 
b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index a54ad8e..6c84fd6 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -417,9 +417,33 @@ public class BeanPropertyMeta {
                        if (bean == null)
                                return m.propertyCache.get(name);
 
-                       Object o = invokeGetter(bean, pName);
+                       return toSerializedForm(m.getBeanSession(), getRaw(m, 
pName));
 
-                       return toSerializedForm(m.getBeanSession(), o);
+               } catch (Throwable e) {
+                       if (beanContext.ignoreInvocationExceptionsOnGetters) {
+                               if (rawTypeMeta.isPrimitive())
+                                       return 
rawTypeMeta.getPrimitiveDefault();
+                               return null;
+                       }
+                       throw new BeanRuntimeException(beanMeta.c, "Exception 
occurred while getting property ''{0}''", name).initCause(e);
+               }
+       }
+
+       /**
+        * Equivalent to calling {@link BeanMap#getRaw(Object)}, but is faster 
since it avoids looking up the property meta.
+        *
+        * @param m The bean map to get the transformed value from.
+        * @param pName The property name.
+        * @return The raw property value.
+        */
+       public Object getRaw(BeanMap<?> m, String pName) {
+               try {
+                       // Read-only beans have their properties stored in a 
cache until getBean() is called.
+                       Object bean = m.bean;
+                       if (bean == null)
+                               return m.propertyCache.get(name);
+
+                       return invokeGetter(bean, pName);
 
                } catch (Throwable e) {
                        if (beanContext.ignoreInvocationExceptionsOnGetters) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/ObjectList.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ObjectList.java 
b/juneau-core/src/main/java/org/apache/juneau/ObjectList.java
index 0629d3f..d5f8939 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ObjectList.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ObjectList.java
@@ -139,8 +139,12 @@ public class ObjectList extends LinkedList<Object> {
                this(p == null ? BeanContext.DEFAULT.createSession() : 
p.getBeanContext().createSession());
                if (p == null)
                        p = JsonParser.DEFAULT;
-               if (s != null)
-                       p.parseIntoCollection(s, this, session.object());
+               try {
+                       if (s != null)
+                               p.parseIntoCollection(s, this, 
session.object());
+               } catch (ParseException e) {
+                       throw new ParseException("Invalid input for {0} 
parser.\n---start---\n{1}\n---end---", p.getClass().getSimpleName(), 
s).initCause(e);
+               }
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/ObjectMap.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ObjectMap.java 
b/juneau-core/src/main/java/org/apache/juneau/ObjectMap.java
index 110c84d..d3d4b87 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ObjectMap.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ObjectMap.java
@@ -150,8 +150,12 @@ public class ObjectMap extends 
LinkedHashMap<String,Object> {
                this(p == null ? BeanContext.DEFAULT.createSession() : 
p.getBeanContext().createSession());
                if (p == null)
                        p = JsonParser.DEFAULT;
-               if (! StringUtils.isEmpty(s))
-                       p.parseIntoMap(s, this, session.string(), 
session.object());
+               try {
+                       if (! StringUtils.isEmpty(s))
+                               p.parseIntoMap(s, this, session.string(), 
session.object());
+               } catch (ParseException e) {
+                       throw new ParseException("Invalid input for {0} 
parser.\n---start---\n{1}\n---end---", p.getClass().getSimpleName(), 
s).initCause(e);
+               }
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
index ebea8a3..2078811 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerContext.java
@@ -277,6 +277,8 @@ public final class HtmlDocSerializerContext extends 
HtmlSerializerContext {
         *      )
         *      <jk>public class</jk> AddressBookResource <jk>extends</jk> 
RestServletJenaDefault {
         * </p>
+        * <p>
+        * Values that start with <js>'&lt;'</js> are assumed to be HTML and 
rendered as-is. 
         */
        public static final String HTMLDOC_links = 
"HtmlDocSerializer.links.map";
 
@@ -496,7 +498,7 @@ public final class HtmlDocSerializerContext extends 
HtmlSerializerContext {
 
 
        final String[] css;
-       final Map<String,String> links;
+       final Map<String,Object> links;
        final String title, description, branding, header, nav, aside, footer, 
cssUrl, noResultsMessage;
        final boolean nowrap;
        final HtmlDocTemplate template;
@@ -520,7 +522,7 @@ public final class HtmlDocSerializerContext extends 
HtmlSerializerContext {
                footer = ps.getProperty(HTMLDOC_footer, String.class, null);
                cssUrl = ps.getProperty(HTMLDOC_cssUrl, String.class, null);
                nowrap = ps.getProperty(HTMLDOC_nowrap, boolean.class, false);
-               links = ps.getMap(HTMLDOC_links, String.class, String.class, 
null);
+               links = ps.getMap(HTMLDOC_links, String.class, Object.class, 
null);
                noResultsMessage = ps.getProperty(HTMLDOC_noResultsMessage, 
String.class, "<p>no results</p>");
                template = ps.getTypedProperty(HTMLDOC_template, 
HtmlDocTemplate.class, HtmlDocTemplateBasic.class);
        }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
index 88874a3..b874628 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializerSession.java
@@ -35,7 +35,7 @@ public final class HtmlDocSerializerSession extends 
HtmlSerializerSession {
 
        private final String title, description, branding, header, nav, aside, 
footer, cssUrl, noResultsMessage;
        private final String[] css;
-       private final Map<String,String> links;
+       private final Map<String,Object> links;
        private final boolean nowrap;
        private final HtmlDocTemplate template;
 
@@ -158,7 +158,7 @@ public final class HtmlDocSerializerSession extends 
HtmlSerializerSession {
         * @return The {@link HtmlDocSerializerContext#HTMLDOC_links} setting 
value in this context.
         *      <jk>null</jk> if not specified.  Never an empty map.
         */
-       public final Map<String,String> getLinks() {
+       public final Map<String,Object> getLinks() {
                return links;
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
index 1853f00..3088e9c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocTemplateBasic.java
@@ -112,14 +112,18 @@ public class HtmlDocTemplateBasic implements 
HtmlDocTemplate {
                        if (exists(nav))
                                w.append(2, nav).nl(2);
                } else {
-                       Map<String,String> htmlLinks = session.getLinks();
+                       Map<String,Object> htmlLinks = session.getLinks();
                        boolean first = true;
                        if (htmlLinks != null) {
-                               for (Map.Entry<String,String> e : 
htmlLinks.entrySet()) {
+                               for (Map.Entry<String,Object> e : 
htmlLinks.entrySet()) {
+                                       String v = e.getValue().toString();
                                        if (! first)
                                                w.append(3, " - ").nl(3);
                                        first = false;
-                                       w.oTag("a").attr("class", 
"link").attr("href", session.resolveUri(e.getValue()), 
true).cTag().text(e.getKey(), true).eTag("a");
+                                       if (v.startsWith("<"))
+                                               w.append(v);
+                                       else
+                                               w.oTag("a").attr("class", 
"link").attr("href", session.resolveUri(v), true).cTag().text(e.getKey(), 
true).eTag("a");
                                }
                        }
                }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java 
b/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
index 3baf951..b91727c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
+++ b/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -742,6 +742,26 @@ public final class StringUtils {
        }
 
        /**
+        * Same as {@link #endsWith(String, char)} except check for multiple 
characters.
+        *
+        * @param s The string to check.  Can be <jk>null</jk>.
+        * @param c The characters to check for.
+        * @return <jk>true</jk> if the specified string is not <jk>null</jk> 
and ends with the specified character.
+        */
+       public static boolean endsWith(String s, char...c) {
+               if (s != null) {
+                       int i = s.length();
+                       if (i > 0) {
+                               char c2 = s.charAt(i-1);
+                               for (char cc : c)
+                                       if (c2 == cc)
+                                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
         * Converts the specified number into a 4 hexadecimal characters.
         *
         * @param num The number to convert to hex.
@@ -1522,4 +1542,23 @@ public final class StringUtils {
                                return ss;
                return null;
        }
+
+       /**
+        * Same as {@link String#indexOf(int)} except allows you to check for 
mulitiple characters.
+        *
+        * @param s The string to check.
+        * @param c The characters to check for.
+        * @return The index into the string that is one of the specified 
characters.
+        */
+       public static int indexOf(String s, char...c) {
+               if (s == null)
+                       return -1;
+               for (int i = 0; i < s.length(); i++) {
+                       char c2 = s.charAt(i);
+                       for (char cc : c)
+                               if (c2 == cc)
+                                       return i;
+               }
+               return -1;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroup.java 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
index 9d0ffee..5a4db6e 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
@@ -68,6 +68,7 @@ public final class SerializerGroup {
        private final Serializer[] mediaTypeSerializers;
        private final List<Serializer> serializers;
        private final PropertyStore propertyStore;
+       private final BeanContext beanContext;
 
        /**
         * Constructor.
@@ -80,6 +81,7 @@ public final class SerializerGroup {
         */
        public SerializerGroup(PropertyStore propertyStore, Serializer[] 
serializers) {
                this.propertyStore = PropertyStore.create(propertyStore);
+               this.beanContext = propertyStore.getBeanContext();
                this.serializers = Collections.unmodifiableList(new 
ArrayList<Serializer>(Arrays.asList(serializers)));
 
                List<MediaType> lmt = new ArrayList<MediaType>();
@@ -204,4 +206,13 @@ public final class SerializerGroup {
        public List<Serializer> getSerializers() {
                return serializers;
        }
+
+       /**
+        * Returns a bean context with the same properties as this group.
+        *
+        * @return The bean context.
+        */
+       public BeanContext getBeanContext() {
+               return beanContext;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/09590092/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java 
b/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
index e93f989..a4566e5 100644
--- a/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
+++ b/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
@@ -23,7 +23,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
 
 /**
- * Designed to provide query/view/sort/paging filtering on tabular in-memory 
POJO models.
+ * Designed to provide search/view/sort/paging filtering on tabular in-memory 
POJO models.
  * <p>
  * It can also perform just view filtering on beans/maps.
  * <p>
@@ -38,47 +38,40 @@ import org.apache.juneau.internal.*;
  * Tabular POJO models can be thought of as tables of data.  For example, a 
list of the following beans...
  * <p class='bcode'>
  *     <jk>public</jk> MyBean {
- *             <jk>public int</jk> fi;
- *             <jk>public</jk> String fs;
- *             <jk>public</jk> Date fd;
+ *             <jk>public int</jk> myInt;
+ *             <jk>public</jk> String myString;
+ *             <jk>public</jk> Date myDate;
  *     }
  * <p>
  *     ... can be thought of a table containing the following columns...
  * <p>
  *     <table class='styled code'>
- *             <tr><th>fi</th><th>fs</th><th>fd</th></tr>
+ *             <tr><th>myInt</th><th>myString</th><th>myDate</th></tr>
  *             <tr><td>123</td><td>'foobar'</td><td>yyyy/MM/dd 
HH:mm:ss</td></tr>
  *             <tr><td colspan=3>...</td></tr>
  *     </table>
  * <p>
  * From this table, you can perform the following functions:
  *     <ul class='spaced-list'>
- *             <li>Query - Return only rows where a search pattern matches.
+ *             <li>Search - Return only rows where a search pattern matches.
  *             <li>View - Return only the specified subset of columns in the 
specified order.
  *             <li>Sort - Sort the table by one or more columns.
- *             <li>Page - Only return a subset of rows.
+ *             <li>Position/limit - Only return a subset of rows.
  *     </ul>
  *
- * <h5 class='topic'>Query</h5>
+ * <h5 class='topic'>Search</h5>
  * <p>
- * The query capabilites allow you to filter based on query patterns against
+ * The search capabilities allow you to filter based on query patterns against
  *     strings, dates, and numbers.  Queries take the form of a Map with 
column names
  *     as keys, and search patterns as values.  <br>
- * Search patterns can be either {@code Strings} or {@code Maps}.<br>
  * Multiple search patterns are ANDed (i.e. all patterns must match for the 
row to be returned).
  *
  * <h5 class='section'>Example:</h5>
  * <ul class='spaced-list'>
- *     <li><tt>{fi:'123'}</tt> - Return only rows where the <tt>fi</tt> column 
is 123.
- *     <li><tt>{fs:'foobar'}</tt> - Return only rows where the <tt>fs</tt> 
column is 'foobar'.
- *     <li><tt>{fd:'2001'}</tt> - Return only rows where the <tt>fd</tt> 
column have dates in the year 2001.
- *     <li><tt>{fs:'foobar'}</tt> - Return only rows where the <tt>fs</tt> 
column is 'foobar'.
- *             and the <tt>fs</tt> column starts with <tt>"foo"</tt>.
+ *     <li><tt>{myInt:'123'}</tt> - Return only rows where the <tt>myInt</tt> 
column is 123.
+ *     <li><tt>{myString:'foobar'}</tt> - Return only rows where the 
<tt>myString</tt> column is 'foobar'.
+ *     <li><tt>{myDate:'2001'}</tt> - Return only rows where the 
<tt>myDate</tt> column have dates in the year 2001.
  * </ul>
- * <p>
- * Search patterns can also be applied to lower level fields.  For example, 
the search term
- *     <tt>{f1:{f2:{f3{'foobar'}}}</tt> means only return top level rows where 
the <tt>f1.getF2().getF3()</tt>
- *     property is <tt>'foobar'</tt>.
  *
  * <h5 class='topic'>String Patterns</h5>
  * <p>
@@ -163,37 +156,28 @@ import org.apache.juneau.internal.*;
  *
  * <h6 class='topic'>Example view parameters:</h6>
  * <ul>
- *     <li><tt>['f1']</tt> - Return only column 'f1'.
- *     <li><tt>['f2','f1']</tt> - Return only columns 'f2' and 'f1'.
- *     <li><tt>['f1',{f2:'f3'}]</tt> - Return only columns 'f1' and 'f2', but 
for 'f2' objects,
- *             only show the 'f3' property.
+ *     <li><tt>column1</tt> - Return only column 'column1'.
+ *     <li><tt>column2, column1</tt> - Return only columns 'column2' and 
'column1' in that order.
  * </ul>
  *
  * <h5 class='topic'>Sort</h5>
  * <p>
  * The sort capability allows you to sort values by the specified rows.<br>
- * The sort parameter is a list of either <tt>Strings</tt> or 
<tt>Maps</tt>.<br>
- *     <tt>Strings</tt> represent column names to sort ascending.  If you want
- *     to sort descending, you need to specify a <tt>Map</tt> of the form 
<tt>{colname:'d'}</tt>
+ * The sort parameter is a list of strings with an optional <js>'+'</js> or 
<js>'-'</js> suffix representing
+ *     ascending and descending order accordingly.
  *
  * <h6 class='topic'>Example sort parameters:</h6>
  * <ul>
- *     <li><tt>['f1']</tt> - Sort rows by column 'f1' ascending.
- *     <li><tt>[{f1:'a'}]</tt> - Sort rows by column 'f1' ascending.
- *     <li><tt>[{f1:'d'}]</tt> - Sort rows by column 'f1' descending.
- *     <li><tt>[{f1:'a'},{f2:'d'}]</tt> - Sort rows by column 'f1' ascending, 
then 'f2' descending.
+ *     <li><tt>column1</tt> - Sort rows by column 'column1' ascending.
+ *     <li><tt>column1+</tt> - Sort rows by column 'column1' ascending.
+ *     <li><tt>column1-</tt> - Sort rows by column 'column1' descending.
+ *     <li><tt>column1, column2-</tt> - Sort rows by column 'column1' 
ascending, then 'column2' descending.
  * </ul>
  *
  * <h5 class='topic'>Paging</h5>
  * <p>
- * Use the <tt>pos</tt> and <tt>limit</tt> parameters to specify a subset of 
rows to
+ * Use the <tt>position</tt> and <tt>limit</tt> parameters to specify a subset 
of rows to
  *     return.
- *
- * <h5 class='topic'>Other Notes</h5>
- * <ul class='spaced-list'>
- *     <li>Calling <tt>filterMap()</tt> or <tt>filterCollection()</tt> always 
returns a new data
- *             structure, so the methods can be called multiple times against 
the same input.
- * </ul>
  */
 @SuppressWarnings({"unchecked","rawtypes"})
 public final class PojoQuery {
@@ -215,37 +199,13 @@ public final class PojoQuery {
        }
 
        /**
-        * Filters the input object as a map.
-        *
-        * @param view The list and order of properties to return from the map. 
 Values must be of type {@code String} or {@code Map}.
-        * @return The filtered map
-        */
-       public Map filterMap(List view) {
-
-               if (input == null)
-                       return null;
-
-               if (! type.isMapOrBean())
-                       throw new RuntimeException("Cannot call filterMap() on 
class type " + type);
-
-               Map m = (Map)replaceWithMutables(input);
-               doView(m, view);
-
-               return m;
-       }
-
-       /**
         * Filters the input object as a collection of maps.
         *
-        * @param query The query attributes.  Keys must be column names and 
values must be of type {@code String} or {@code Map}.
-        * @param view The view attributes.  Values must be of type {@code 
String} or {@code Map}.
-        * @param sort The sort attributes.  Values must be of type {@code 
String} or {@code Map}.
-        * @param pos The index into the list to start returning results from.  
Default is {@code 0}.
-        * @param limit The number of rows to return.  Default is all rows.
-        * @param ignoreCase If <jk>true</jk>, then querying is case 
insensitive.  Default is <jk>false</jk>.
+        * @param args The search arguments.
         * @return The filtered collection.
+        *      <br>Returns the unaltered input if the input is not a 
collection or array of objects.
         */
-       public List filterCollection(Map query, List view, List sort, int pos, 
int limit, boolean ignoreCase) {
+       public List filter(SearchArgs args) {
 
                if (input == null)
                        return null;
@@ -253,31 +213,28 @@ public final class PojoQuery {
                if (! type.isCollectionOrArray())
                        throw new RuntimeException("Cannot call 
filterCollection() on class type " + type);
 
-               if (view == null)
-                       view = Collections.EMPTY_LIST;
-
-               if (sort == null)
-                       sort = Collections.EMPTY_LIST;
-
                // Create a new ObjectList
                ObjectList l = (ObjectList)replaceWithMutables(input);
 
                // Do the search
-               CollectionFilter filter = new CollectionFilter(query, 
ignoreCase);
+               CollectionFilter filter = new 
CollectionFilter(args.getSearch(), args.isIgnoreCase());
                filter.doQuery(l);
 
                // If sort or view isn't empty, then we need to make sure that 
all entries in the
                // list are maps.
-               if ((! sort.isEmpty()) || (! view.isEmpty())) {
+               Map<String,Boolean> sort = args.getSort();
+               List<String> view = args.getView();
 
+               if ((! sort.isEmpty()) || (! view.isEmpty())) {
                        if (! sort.isEmpty())
                                doSort(l, sort);
-
                        if (! view.isEmpty())
                                doView(l, view);
                }
 
                // Do the paging.
+               int pos = args.getPosition();
+               int limit = args.getLimit();
                if (pos != 0 || limit != 0) {
                        int end = (limit == 0 || limit+pos >= l.size()) ? 
l.size() : limit + pos;
                        ObjectList l2 = new 
DelegateList(((DelegateList)l).getClassMeta());
@@ -304,39 +261,22 @@ public final class PojoQuery {
                if (cm.isMap() && o instanceof BeanMap) {
                        BeanMap bm = (BeanMap)o;
                        DelegateBeanMap dbm = new DelegateBeanMap(bm.getBean(), 
session);
-                       for (BeanMapEntry e : (Set<BeanMapEntry>)bm.entrySet()) 
{
-                               ClassMeta ct1 = e.getMeta().getClassMeta();
-                               if (ct1.isCollectionOrArray() || 
ct1.isMapOrBean() || ct1.isObject())
-                                       dbm.put(e.getKey(), 
replaceWithMutables(e.getValue()));
-                               else
-                                       dbm.addKey(e.getKey());
-                       }
+                       for (Object key : bm.keySet())
+                               dbm.addKey(key.toString());
                        return dbm;
                }
                if (cm.isBean()) {
                        BeanMap bm = session.toBeanMap(o);
                        DelegateBeanMap dbm = new DelegateBeanMap(bm.getBean(), 
session);
-                       for (BeanMapEntry e : (Set<BeanMapEntry>)bm.entrySet()) 
{
-                               ClassMeta ct1 = e.getMeta().getClassMeta();
-                               if (ct1.isCollectionOrArray() || 
ct1.isMapOrBean() || ct1.isObject()) {
-                                       Object val = null;
-                                       try {
-                                               val = e.getValue();
-                                       } catch (BeanRuntimeException ex) {
-                                               // Ignore.
-                                       }
-                                       dbm.put(e.getKey(), 
replaceWithMutables(val));
-                               }
-                               else
-                                       dbm.addKey(e.getKey());
-                       }
+                       for (Object key : bm.keySet())
+                               dbm.addKey(key.toString());
                        return dbm;
                }
                if (cm.isMap()) {
                        Map m = (Map)o;
                        DelegateMap dm = new 
DelegateMap(session.getClassMetaForObject(m));
                        for (Map.Entry e : (Set<Map.Entry>)m.entrySet())
-                               dm.put(e.getKey().toString(), 
replaceWithMutables(e.getValue()));
+                               dm.put(e.getKey().toString(), e.getValue());
                        return dm;
                }
                if (cm.isArray()) {
@@ -348,24 +288,15 @@ public final class PojoQuery {
        /*
         * Sorts the specified list by the sort list.
         */
-       private static void doSort(List list, List sortList) {
-
-               Map sort = new LinkedHashMap();
-               for (Object s : sortList) {
-                       if (s instanceof String)
-                               sort.put(s, "a");
-                       else if (s instanceof Map) {
-                               Map sm = (Map)s;
-                               for (Map.Entry e : 
(Set<Map.Entry>)sm.entrySet())
-                                       sort.put(e.getKey(), 
e.getValue().toString().toLowerCase(Locale.ENGLISH));
-                       }
-               }
+       private static void doSort(List list, Map<String,Boolean> sortList) {
 
-               // Do the sort.
-               List<String> columns = new ArrayList<String>(sort.keySet());
+               // We reverse the list and sort last to first.
+               List<String> columns = new ArrayList<String>(sortList.keySet());
                Collections.reverse(columns);
+
                for (final String c : columns) {
-                       final boolean isDesc = 
startsWith(sort.get(c).toString(), 'd');
+                       final boolean isDesc = sortList.get(c);
+
                        Comparator comp = new Comparator<Map>() {
                                @Override /* Comparator */
                                public int compare(Map m1, Map m2) {
@@ -386,8 +317,7 @@ public final class PojoQuery {
        /*
         * Filters all but the specified view columns on all entries in the 
specified list.
         */
-       private void doView(List list, List view) {
-
+       private static void doView(List list, List<String> view) {
                for (ListIterator i = list.listIterator(); i.hasNext();) {
                        Object o = i.next();
                        Map m = (Map)o;
@@ -398,48 +328,15 @@ public final class PojoQuery {
        /*
         * Creates a new Map with only the entries specified in the view list.
         */
-       private void doView(Map m, List view) {
-               List<String> filterKeys = new LinkedList<String>();
-               for (Object v : view) {
-                       if (v instanceof String) {
-                               filterKeys.add(v.toString());
-                       } else if (v instanceof ObjectMap) {
-                               ObjectMap vm = (ObjectMap)v;
-                               for (Map.Entry<String,Object> e : 
vm.entrySet()) {
-                                       String vmKey = e.getKey();
-                                       Object vmVal = e.getValue();
-                                       Object mv = m.get(vmKey);
-                                       filterKeys.add(vmKey);
-                                       if (vmVal instanceof List) {
-                                               List l = (List)vmVal;
-                                               if (mv instanceof List)
-                                                       doView((List)mv, l);
-                                               else if (mv instanceof Map)
-                                                       doView((Map)mv, l);
-                                       }
-                               }
-                       }
-               }
+       private static Map doView(Map m, List<String> view) {
                if (m instanceof DelegateMap)
-                       ((DelegateMap)m).filterKeys(filterKeys);
+                       ((DelegateMap)m).filterKeys(view);
                else
-                       ((DelegateBeanMap)m).filterKeys(filterKeys);
+                       ((DelegateBeanMap)m).filterKeys(view);
+               return m;
        }
 
 
-       /*
-        * Returns the appropriate IMatcher for the specified class type.
-        */
-       private IMatcher getObjectMatcherForType(String queryString, boolean 
ignoreCase, ClassMeta cm) {
-               if (cm.isDate())
-                       return new DateMatcher(queryString);
-               if (cm.isNumber())
-                       return new NumberMatcher(queryString);
-               if (cm.isObject())
-                       return new ObjectMatcher(queryString, ignoreCase);
-               return new StringMatcher(queryString, ignoreCase);
-       }
-
        
//====================================================================================================
        // CollectionFilter
        
//====================================================================================================
@@ -480,18 +377,9 @@ public final class PojoQuery {
                Map<String,IMatcher> entryMatchers = new 
HashMap<String,IMatcher>();
 
                public MapMatcher(Map query, boolean ignoreCase) {
-                       for (Map.Entry e : (Set<Map.Entry>)query.entrySet()) {
-                               String key = e.getKey().toString();
-                               Object value = e.getValue();
-                               IMatcher matcher = null;
-                               if (value instanceof String)
-                                       matcher = 
getObjectMatcherForType((String)value, ignoreCase, session.object());
-                               else if (value instanceof ObjectMap)
-                                       matcher = new 
MapMatcher((ObjectMap)value, ignoreCase);
-                               else
-                                       throw new RuntimeException("Invalid 
value type: " + value);
-                               entryMatchers.put(key, matcher);
-                       }
+                       for (Map.Entry e : (Set<Map.Entry>)query.entrySet())
+                               if (e.getKey() != null && e.getValue() != null)
+                                       
entryMatchers.put(e.getKey().toString(), new 
ObjectMatcher(e.getValue().toString(), ignoreCase));
                }
 
                @Override /* IMatcher */
@@ -500,7 +388,12 @@ public final class PojoQuery {
                                return false;
                        for (Map.Entry<String,IMatcher> e : 
entryMatchers.entrySet()) {
                                String key = e.getKey();
-                               Object val = m.get(key);
+                               Object val = null;
+                               if (m instanceof BeanMap) {
+                                       val = ((BeanMap)m).getRaw(key);
+                               } else {
+                                       val = m.get(key);
+                               }
                                if (! e.getValue().matches(val))
                                        return false;
                        }
@@ -912,7 +805,7 @@ public final class PojoQuery {
         * @param pp Where parsing last left off.
         * @return An object represening a timestamp.
         */
-       protected CalendarP parseDate(String seg, ParsePosition pp) {
+       private CalendarP parseDate(String seg, ParsePosition pp) {
 
                CalendarP cal = null;
 

Reply via email to