You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2019/03/10 15:52:25 UTC

[juneau] branch master updated (f83dfaa -> 2244c05)

This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git.


    from f83dfaa  Merge pull request #45 from acoburn/jena_update
     new 3abc77c  Additional default configuration file names.
     new 6699d2b  Add Ayeshmantha to developer list in POM.
     new 32d628e  Doc fix.
     new 0ba1bd5  Minor javadoc fixes.
     new f6e2dc4  Add RestResponse access to HTML widgets.
     new 211e266  Improvements to RestMock APIs.
     new f44b3d5  Add new juneau-rest-mock project.
     new 561e701  Merge branch 'master' of https://gitbox.apache.org/repos/asf/juneau.git
     new 2244c05  Strip trailing slashes from RestMethod.path.

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../main/java/org/apache/juneau/config/Config.java |    6 +
 .../apache/juneau/config/ConfigImportsTest.java    |    2 -
 .../java/org/apache/juneau/config/ConfigTest.java  |    2 +-
 .../apache/juneau/pojotools/PojoSearcherTest.java  | 1056 ++++++++++++++++++++
 .../apache/juneau/pojotools/PojoSorterTest.java    |  265 +++++
 .../apache/juneau/pojotools/PojoViewerTest.java    |  349 +++++++
 .../org/apache/juneau/http/HttpMethodName.java     |    3 +
 .../apache/juneau/internal/DelegateBeanMap.java    |    8 +-
 .../org/apache/juneau/internal/DelegateMap.java    |   19 +-
 .../org/apache/juneau/internal/ObjectUtils.java    |   28 +
 .../apache/juneau/internal/StateMachineState.java  |    9 +-
 .../org/apache/juneau/internal/StringUtils.java    |   76 +-
 .../java/org/apache/juneau/marshall/Marshall.java  |   18 +
 .../java/org/apache/juneau/pojotools/Equality.java |   11 +-
 .../java/org/apache/juneau/pojotools/Matcher.java  |   18 +-
 .../apache/juneau/pojotools/MatcherFactory.java    |   41 +-
 .../juneau/pojotools/NumberMatcherFactory.java     |  291 ++++++
 .../apache/juneau/pojotools/PatternException.java  |   21 +-
 .../org/apache/juneau/pojotools/PojoPaginator.java |   71 ++
 .../org/apache/juneau/pojotools/PojoSearcher.java  |  185 ++++
 .../org/apache/juneau/pojotools/PojoSorter.java    |  110 ++
 .../java/org/apache/juneau/pojotools/PojoTool.java |   21 +-
 .../org/apache/juneau/pojotools/PojoViewer.java    |   80 ++
 .../{utils/ASet.java => pojotools/SearchArgs.java} |   73 +-
 .../DelegateMap.java => pojotools/SortArgs.java}   |  138 +--
 .../juneau/pojotools/StringMatcherFactory.java     |  145 +++
 .../juneau/pojotools/TimeMatcherFactory.java       |  460 +++++++++
 .../java/org/apache/juneau/pojotools/ViewArgs.java |   59 +-
 .../main/java/org/apache/juneau/utils/ASet.java    |    1 +
 .../apache/juneau/utils/MockHttpConnection.java    |    5 +-
 .../java/org/apache/juneau/utils/PojoQuery.java    |    2 +-
 juneau-doc/docs/ReleaseNotes/8.0.1.html            |    7 +
 .../docs/Topics/06.juneau-config/01.Overview.html  |    2 +-
 .../06.juneau-config/02.EntryTypes/03.Arrays.html  |    2 +-
 .../12.ConfigStores/01.ConfigMemoryStore.html      |    2 +-
 .../12.ConfigStores/03.CustomConfigStores.html     |    6 +-
 .../06.juneau-config/15.SystemDefaultConfig.html   |    5 +-
 .../03.Instantiation/03.BasicRest.html             |    2 +-
 .../11.juneau-microservice-core/05.Config.html     |    9 +-
 juneau-doc/juneau-doc.jar                          |  Bin 25553 -> 25564 bytes
 .../org/apache/juneau/doc/internal/SourceTag.java  |    2 +-
 juneau-doc/src/main/javadoc/overview.html          |   51 +-
 .../juneau-examples-rest-jetty/.gitignore          |    1 +
 .../rest/petstore/rest/AddOrderMenuItem.java       |    6 +-
 .../rest/petstore/rest/AddPetMenuItem.java         |    4 +-
 .../rest/petstore/rest/UploadPhotoMenuItem.java    |    4 +-
 .../microservice/jetty/JettyMicroservice.java      |    3 +
 .../juneau-microservice-test/pom.xml               |   23 +-
 .../org/apache/juneau/rest/test/MockRestTest.java  |    9 +-
 .../rest/test/client/CallbackStringsTest.java      |    4 +-
 .../juneau/rest/test/client/ClientFuturesTest.java |    4 +-
 .../juneau/rest/test/client/FormDataTest.java      |    7 +-
 .../rest/test/client/InterfaceProxyTest.java       |    7 +-
 .../rest/test/client/RequestBeanProxyTest.java     |   78 +-
 juneau-rest/.DS_Store                              |  Bin 6148 -> 6148 bytes
 .../.classpath                                     |    6 -
 .../.gitignore                                     |    0
 .../.project                                       |    0
 .../pom.xml                                        |   15 +-
 .../rest/client/remote/BodyAnnotationTest.java     |   13 +-
 .../rest/client/remote/EndToEndInterfaceTest.java  |   27 +-
 .../rest/client/remote/FormDataAnnotationTest.java |   32 +-
 .../rest/client/remote/HeaderAnnotationTest.java   |   32 +-
 .../rest/client/remote/PathAnnotationTest.java     |   26 +-
 .../rest/client/remote/QueryAnnotationTest.java    |   32 +-
 .../client/remote/RemoteMethodAnnotationTest.java  |   20 +-
 .../remote/RemoteResourceAnnotationTest.java       |   24 +-
 .../rest/client/remote/RequestAnnotationTest.java  |   19 +-
 .../rest/client/remote/ResponseAnnotationTest.java |    6 +-
 juneau-rest/juneau-rest-client/.classpath          |    6 -
 .../.settings/org.eclipse.core.resources.prefs     |    1 -
 juneau-rest/juneau-rest-client/pom.xml             |    1 -
 .../org/apache/juneau/rest/client/RestClient.java  |   69 +-
 .../juneau/rest/client/RestClientBuilder.java      |   48 +-
 .../juneau/rest/client/mock/package-info.java      |   18 -
 .../.classpath                                     |   16 +-
 .../juneau-rest-mock}/.gitignore                   |    0
 juneau-rest/juneau-rest-mock/.project              |   26 +
 .../pom.xml                                        |   38 +-
 .../rest/mock2}/MockHttpClientConnection.java      |    6 +-
 .../mock2}/MockHttpClientConnectionManager.java    |    2 +-
 .../apache/juneau/rest/mock2}/MockHttpSession.java |    2 +-
 .../juneau/rest/mock2/MockRemoteResource.java      |  383 +++++++
 .../org/apache/juneau/rest/mock2/MockRest.java     |  538 ++++++++++
 .../apache/juneau/rest/mock2/MockRestClient.java   |  268 +++++
 .../juneau/rest/mock2}/MockServletRequest.java     |  104 +-
 .../juneau/rest/mock2}/MockServletResponse.java    |    4 +-
 .../apache/juneau/rest/mock2}/package-info.java    |    2 +-
 .../org/apache/juneau/rest/testutils/ABean.java    |    0
 .../apache/juneau/rest/testutils/Constants.java    |    0
 .../org/apache/juneau/rest/testutils/DTOs.java     |    0
 .../juneau/rest/testutils/ImplicitSwappedPojo.java |    0
 .../apache/juneau/rest/testutils/SwappedPojo.java  |    0
 .../juneau/rest/testutils/SwappedPojoSwap.java     |    0
 .../org/apache/juneau/rest/testutils/TestEnum.java |    0
 .../apache/juneau/rest/testutils/TestUtils.java    |    3 +-
 .../apache/juneau/rest/testutils/TypedBean.java    |    0
 .../juneau/rest/testutils/TypedBeanImpl.java       |    0
 .../juneau/rest/testutils/XPartSerializer.java     |    0
 .../org/apache/juneau/rest/BasicRestJenaGroup.java |    2 +
 .../.classpath                                     |    5 -
 .../.gitignore                                     |    0
 .../.project                                       |    0
 .../pom.xml                                        |   82 +-
 .../jueau/rest/helper/ReaderResourceTest.java      |    4 +-
 .../jueau/rest/helper/StreamResourceTest.java      |    4 +-
 .../juneau/rest/BasicRestInfoProviderTest.java     |    4 +-
 .../juneau/rest/BeanContextPropertiesTest.java     |    4 +-
 .../test/java/org/apache/juneau/rest/NlsTest.java  |    8 +-
 .../java/org/apache/juneau/rest/PathsTest.java     |   10 +-
 .../org/apache/juneau/rest/RestParamsTest.java     |    4 +-
 .../org/apache/juneau/rest/StatusCodesTest.java    |   10 +-
 .../apache/juneau/rest/ThreadLocalObjectsTest.java |    6 +-
 .../juneau/rest/annotation/HtmlDocAsideTest.java   |    6 +-
 .../juneau/rest/annotation/HtmlDocFooterTest.java  |    6 +-
 .../juneau/rest/annotation/HtmlDocHeaderTest.java  |    6 +-
 .../juneau/rest/annotation/HtmlDocNavTest.java     |    6 +-
 .../rest/annotation/HtmlDocNavlinksTest.java       |    6 +-
 .../juneau/rest/annotation/HtmlDocScriptTest.java  |    6 +-
 .../juneau/rest/annotation/HtmlDocStyleTest.java   |    6 +-
 .../annotation/ResponseBodyAnnotationTest.java     |    0
 .../annotation/ResponseHeaderAnnotationTest.java   |    4 +-
 .../annotation/ResponseStatusAnnotationTest.java   |    4 +-
 .../juneau/rest/annotation/RestMethodBpiTest.java  |   16 +-
 .../rest/annotation/RestMethodGuardsTest.java      |    4 +-
 .../rest/annotation/RestMethodMatchersTest.java    |    4 +-
 .../juneau/rest/annotation/RestMethodPathTest.java |    4 +-
 .../rest/annotation/RestResourceMessagesTest.java  |    6 +-
 .../rest/annotation/RestResourcePathTest.java      |    4 +-
 .../annotation/RestResourcePropertiesTest.java     |    4 +-
 .../annotation/RestResourceSerializersTest.java    |    4 +-
 .../annotation/RestResourceStaticFilesTest.java    |    6 +-
 .../annotation2/AnnotationInheritanceTest.java     |    4 +-
 .../rest/annotation2/BodyAnnotationTest.java       |   18 +-
 .../rest/annotation2/FormDataAnnotationTest.java   |    8 +-
 .../annotation2/HasFormDataAnnotationTest.java     |    4 +-
 .../rest/annotation2/HasQueryAnnotationTest.java   |    4 +-
 .../rest/annotation2/HeaderAnnotationTest.java     |    0
 .../rest/annotation2/PathAnnotationTest.java       |   12 +-
 .../annotation2/PathRemainderAnnotationTest.java   |    4 +-
 .../rest/annotation2/QueryAnnotationTest.java      |   10 +-
 .../rest/annotation2/ResponseAnnotationTest.java   |   16 +-
 .../juneau/rest/annotation2/RestHookTest.java      |   18 +-
 .../rest/annotation2/RestMethodInheritTest.java    |   10 +-
 .../rest/annotation2/RestResourceParsersTest.java  |    4 +-
 .../annotation2/RestResourcePojoSwapsTest.java     |    4 +-
 .../apache/juneau/rest/exception/BasicTest.java    |   12 +-
 .../juneau/rest/headers/AcceptCharsetTest.java     |    6 +-
 .../juneau/rest/headers/AcceptEncodingTest.java    |    8 +-
 .../org/apache/juneau/rest/headers/AcceptTest.java |   14 +-
 .../juneau/rest/headers/ClientVersionTest.java     |    6 +-
 .../juneau/rest/headers/ContentEncodingTest.java   |    7 +-
 .../juneau/rest/headers/ContentTypeTest.java       |   12 +-
 .../apache/juneau/rest/headers/HeadersTest.java    |   20 +-
 .../juneau/rest/mock/MockServletRequestTest.java   |    1 +
 .../org/apache/juneau/rest/response/BasicTest.java |   10 +-
 .../org/apache/juneau/rest/util/RestUtilsTest.java |   17 +
 .../juneau/rest/util/UrlPathPatternTest.java       |    0
 .../rest/BasicRestInfoProviderTest.properties      |    0
 .../rest/BasicRestInfoProviderTest_swagger.json    |    0
 .../org/apache/juneau/rest/NlsTest.properties      |    0
 .../apache/juneau/rest/RestParamsTest.properties   |    0
 .../juneau/rest/RestParamsTest_ja_JP.properties    |    0
 .../RestResourceMessagesTest1.properties           |    0
 .../RestResourceMessagesTest2.properties           |    0
 .../apache/juneau/rest/annotation/xdocs/test.txt   |    0
 .../juneau/rest/annotation/xdocs/xsubdocs/test.txt |    0
 juneau-rest/juneau-rest-server/.classpath          |   11 -
 .../.settings/org.eclipse.core.resources.prefs     |    2 -
 .../apache/juneau/rest/BasicRestCallHandler.java   |    3 +-
 .../apache/juneau/rest/BasicRestInfoProvider.java  |    3 +-
 .../apache/juneau/rest/BasicRestServletGroup.java  |    2 +-
 .../org/apache/juneau/rest/RestCallHandler.java    |    3 +-
 .../java/org/apache/juneau/rest/RestContext.java   |   11 +-
 .../org/apache/juneau/rest/RestJavaMethod.java     |    3 +-
 .../java/org/apache/juneau/rest/RestRequest.java   |    3 +-
 .../org/apache/juneau/rest/annotation/HtmlDoc.java |    6 +-
 .../java/org/apache/juneau/rest/mock/MockRest.java |  191 ----
 .../org/apache/juneau/rest/util/RestUtils.java     |   42 +
 .../org/apache/juneau/rest/vars/RequestVar.java    |    5 +
 .../org/apache/juneau/rest/vars/WidgetVar.java     |    8 +-
 .../juneau/rest/widget/ContentTypeMenuItem.java    |    4 +-
 .../apache/juneau/rest/widget/MenuItemWidget.java  |   32 +-
 .../apache/juneau/rest/widget/PoweredByApache.java |    2 +-
 .../apache/juneau/rest/widget/PoweredByJuneau.java |    2 +-
 .../apache/juneau/rest/widget/QueryMenuItem.java   |    8 +-
 .../apache/juneau/rest/widget/ThemeMenuItem.java   |    4 +-
 .../java/org/apache/juneau/rest/widget/Widget.java |   18 +-
 juneau-rest/pom.xml                                |    3 +
 pom.xml                                            |   11 +-
 190 files changed, 5445 insertions(+), 1004 deletions(-)
 create mode 100755 juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSearcherTest.java
 create mode 100644 juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSorterTest.java
 create mode 100644 juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoViewerTest.java
 copy juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java => juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StateMachineState.java (88%)
 copy juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java => juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Equality.java (93%)
 copy juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java => juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Matcher.java (74%)
 copy juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java => juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/MatcherFactory.java (69%)
 create mode 100644 juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/NumberMatcherFactory.java
 copy juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java => juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PatternException.java (78%)
 create mode 100644 juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoPaginator.java
 create mode 100644 juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSearcher.java
 create mode 100644 juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSorter.java
 copy juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java => juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoTool.java (75%)
 create mode 100644 juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoViewer.java
 copy juneau-core/juneau-marshall/src/main/java/org/apache/juneau/{utils/ASet.java => pojotools/SearchArgs.java} (55%)
 copy juneau-core/juneau-marshall/src/main/java/org/apache/juneau/{internal/DelegateMap.java => pojotools/SortArgs.java} (51%)
 create mode 100644 juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/StringMatcherFactory.java
 create mode 100644 juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java
 copy juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java => juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/ViewArgs.java (64%)
 copy juneau-rest/{juneau-rest-client => juneau-rest-client-test}/.classpath (77%)
 copy juneau-rest/{juneau-rest-server => juneau-rest-client-test}/.gitignore (100%)
 copy juneau-rest/{juneau-rest-client => juneau-rest-client-test}/.project (100%)
 copy juneau-rest/{juneau-rest-client => juneau-rest-client-test}/pom.xml (96%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java (95%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java (96%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java (96%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java (96%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java (96%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java (96%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java (88%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java (89%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java (91%)
 rename juneau-rest/{juneau-rest-client => juneau-rest-client-test}/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java (92%)
 delete mode 100644 juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/package-info.java
 copy juneau-rest/{juneau-rest-client => juneau-rest-mock}/.classpath (55%)
 copy {juneau-examples/juneau-examples-rest-jetty/bin => juneau-rest/juneau-rest-mock}/.gitignore (100%)
 create mode 100644 juneau-rest/juneau-rest-mock/.project
 copy juneau-rest/{juneau-rest-client => juneau-rest-mock}/pom.xml (93%)
 rename juneau-rest/{juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock => juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2}/MockHttpClientConnection.java (96%)
 rename juneau-rest/{juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock => juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2}/MockHttpClientConnectionManager.java (98%)
 rename juneau-rest/{juneau-rest-server/src/main/java/org/apache/juneau/rest/mock => juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2}/MockHttpSession.java (98%)
 create mode 100644 juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRemoteResource.java
 create mode 100644 juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRest.java
 create mode 100644 juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
 rename juneau-rest/{juneau-rest-server/src/main/java/org/apache/juneau/rest/mock => juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2}/MockServletRequest.java (92%)
 rename juneau-rest/{juneau-rest-server/src/main/java/org/apache/juneau/rest/mock => juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2}/MockServletResponse.java (99%)
 rename juneau-rest/{juneau-rest-server/src/main/java/org/apache/juneau/rest/mock => juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2}/package-info.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/ABean.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/Constants.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/DTOs.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-mock}/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java (100%)
 copy juneau-rest/{juneau-rest-server => juneau-rest-server-test}/.classpath (86%)
 copy juneau-rest/{juneau-rest-server => juneau-rest-server-test}/.gitignore (100%)
 copy juneau-rest/{juneau-rest-server => juneau-rest-server-test}/.project (100%)
 copy juneau-rest/{juneau-rest-client => juneau-rest-server-test}/pom.xml (78%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java (99%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/NlsTest.java (93%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/PathsTest.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/RestParamsTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/StatusCodesTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java (93%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java (94%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java (94%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java (97%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/exception/BasicTest.java (99%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java (94%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java (94%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java (96%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java (94%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java (95%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/mock/MockServletRequestTest.java (99%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/response/BasicTest.java (98%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java (90%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/java/org/apache/juneau/rest/util/UrlPathPatternTest.java (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest.properties (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/NlsTest.properties (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/RestParamsTest.properties (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/RestParamsTest_ja_JP.properties (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/annotation/xdocs/test.txt (100%)
 rename juneau-rest/{juneau-rest-server => juneau-rest-server-test}/src/test/resources/org/apache/juneau/rest/annotation/xdocs/xsubdocs/test.txt (100%)
 delete mode 100644 juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java


[juneau] 04/09: Minor javadoc fixes.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 0ba1bd5f68efad06a3e1d6e0ebeba60863ba544e
Author: JamesBognar <ja...@apache.org>
AuthorDate: Sun Jan 13 16:08:50 2019 -0500

    Minor javadoc fixes.
---
 .../docs/Topics/06.juneau-config/01.Overview.html   |   2 +-
 .../12.ConfigStores/01.ConfigMemoryStore.html       |   2 +-
 .../12.ConfigStores/03.CustomConfigStores.html      |   6 +++---
 .../06.juneau-config/15.SystemDefaultConfig.html    |   2 +-
 .../03.Instantiation/03.BasicRest.html              |   2 +-
 juneau-doc/juneau-doc.jar                           | Bin 25553 -> 25564 bytes
 .../org/apache/juneau/doc/internal/SourceTag.java   |   2 +-
 juneau-doc/src/main/javadoc/overview.html           |  14 +++++++-------
 .../org/apache/juneau/rest/BasicRestJenaGroup.java  |   2 ++
 .../apache/juneau/rest/BasicRestServletGroup.java   |   2 +-
 pom.xml                                             |   6 +++---
 11 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/juneau-doc/docs/Topics/06.juneau-config/01.Overview.html b/juneau-doc/docs/Topics/06.juneau-config/01.Overview.html
index b45cef7..11c1689 100644
--- a/juneau-doc/docs/Topics/06.juneau-config/01.Overview.html
+++ b/juneau-doc/docs/Topics/06.juneau-config/01.Overview.html
@@ -36,7 +36,7 @@ Overview
 	<ck>key4</ck> = <cv>http://bar</cv>
 </p>
 <p>
-	Config files are access through the {@link oaj.config.Config} class which
+	Config files are accessed through the {@link oaj.config.Config} class which
 	are created through the {@link oaj.config.ConfigBuilder} class.
 	Builder creator methods are provided on the <code>Config</code> class:
 </p>
diff --git a/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/01.ConfigMemoryStore.html b/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/01.ConfigMemoryStore.html
index 0c643f7..bb5bb63 100644
--- a/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/01.ConfigMemoryStore.html
+++ b/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/01.ConfigMemoryStore.html
@@ -39,7 +39,7 @@ ConfigMemoryStore
 		<jk>public synchronized</jk> String write(String name, String expectedContents, String newContents) {
 	
 			<jc>// This is a no-op.</jc>
-			<jk>if</jk> (isEquals(expectedContents, newContents))
+			<jk>if</jk> (<jsm>isEquals</jsm>(expectedContents, newContents))
 				<jk>return null</jk>;
 			
 			String currentContents = read(name);
diff --git a/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/03.CustomConfigStores.html b/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/03.CustomConfigStores.html
index 358e3ec..18c1c94 100644
--- a/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/03.CustomConfigStores.html
+++ b/juneau-doc/docs/Topics/06.juneau-config/12.ConfigStores/03.CustomConfigStores.html
@@ -50,7 +50,7 @@ Custom ConfigStores
 			<jk>this</jk>.<jf>nameColumn</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_nameColumn</jsf>);
 			<jk>this</jk>.<jf>valueColumn</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_valueColumn</jsf>);		
 
-			<jk>int</jk> pollInterval = getStringProperty(<jsf>CONFIGSQLSTORE_pollInterval</jsf>, 600);
+			<jk>int</jk> pollInterval = getStringProperty(<jsf>CONFIGSQLSTORE_pollInterval</jsf>, 600);  <jc>// Time in seconds.</jc>
 			
 			TimerTask timerTask = <jk>new</jk> TimerTask() {
 				<ja>@Override</ja>
@@ -60,7 +60,7 @@ Custom ConfigStores
 			};
 
 			<jk>this</jk>.<jf>watcher</jf> = <jk>new</jk> Timer(<js>"MyTimer"</js>);
-			<jf>watcher</jf>.scheduleAtFixedRate(timerTask, 0, pollInterval * 10000);
+			<jf>watcher</jf>.scheduleAtFixedRate(timerTask, 0, pollInterval * 1000);
 		}
 		
 		<jk>private synchronized void</jk> poll() {
@@ -97,7 +97,7 @@ Custom ConfigStores
 		<jk>public synchronized</jk> String write(String name, String expectedContents, String newContents) {
 	
 			<jc>// This is a no-op.</jc>
-			<jk>if</jk> (isEquals(expectedContents, newContents))
+			<jk>if</jk> (<jsm>isEquals</jsm>(expectedContents, newContents))
 				<jk>return null</jk>;
 			
 			String currentContents = read(name);
diff --git a/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html b/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html
index dc7fb72..b154dbc 100644
--- a/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html
+++ b/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html
@@ -41,7 +41,7 @@ System Default Config
 			<li>Any file that end with <code>.cfg</code>.  First one matched alphabetically is used.
 		</ol>
 	<li>
-		In the context classpath (i.e. inside the jar itself):
+		In the context classpath root package (i.e. inside the jar itself):
 		<ol>
 			<li><code>&lt;jar-name&gt;.cfg</code>
 			<li><code>juneau.cfg</code>
diff --git a/juneau-doc/docs/Topics/07.juneau-rest-server/03.Instantiation/03.BasicRest.html b/juneau-doc/docs/Topics/07.juneau-rest-server/03.Instantiation/03.BasicRest.html
index 1c70f3d..4a2d788 100644
--- a/juneau-doc/docs/Topics/07.juneau-rest-server/03.Instantiation/03.BasicRest.html
+++ b/juneau-doc/docs/Topics/07.juneau-rest-server/03.Instantiation/03.BasicRest.html
@@ -23,7 +23,7 @@
 	annotation. 
 </p>
 <p>
-	The code for this class is virtually identical to {@link oaj.BasicRestServlet} but lacks a parent class:
+	The code for this class is virtually identical to {@link oajr.BasicRestServlet} but lacks a parent class:
 </p>
 <p class='bpcode w800'>
 	<ja>@RestResource</ja>(
diff --git a/juneau-doc/juneau-doc.jar b/juneau-doc/juneau-doc.jar
index feb28d3..219a265 100644
Binary files a/juneau-doc/juneau-doc.jar and b/juneau-doc/juneau-doc.jar differ
diff --git a/juneau-doc/src/main/java/org/apache/juneau/doc/internal/SourceTag.java b/juneau-doc/src/main/java/org/apache/juneau/doc/internal/SourceTag.java
index b1d65d4..622c675 100644
--- a/juneau-doc/src/main/java/org/apache/juneau/doc/internal/SourceTag.java
+++ b/juneau-doc/src/main/java/org/apache/juneau/doc/internal/SourceTag.java
@@ -102,7 +102,7 @@ public class SourceTag implements Taglet {
 		String path = f.getAbsolutePath();
 		String href = GITHUB_LINK + path.substring(JUNEAU_ROOT.length());
 
-		return "<a class='doclink' href='" + href + "'>" + label + "</a>";
+		return "<a class='doclink' target='_blank' href='" + href + "'>" + label + "</a>";
 	}
 
 	@Override
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index 4b8105f..4b23dcd 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -11267,7 +11267,7 @@
 	<ck>key4</ck> = <cv>http://bar</cv>
 </p>
 <p>
-	Config files are access through the {@link org.apache.juneau.config.Config} class which
+	Config files are accessed through the {@link org.apache.juneau.config.Config} class which
 	are created through the {@link org.apache.juneau.config.ConfigBuilder} class.
 	Builder creator methods are provided on the <code>Config</code> class:
 </p>
@@ -12586,7 +12586,7 @@
 		<jk>public synchronized</jk> String write(String name, String expectedContents, String newContents) {
 	
 			<jc>// This is a no-op.</jc>
-			<jk>if</jk> (isEquals(expectedContents, newContents))
+			<jk>if</jk> (<jsm>isEquals</jsm>(expectedContents, newContents))
 				<jk>return null</jk>;
 			
 			String currentContents = read(name);
@@ -12679,7 +12679,7 @@
 			<jk>this</jk>.<jf>nameColumn</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_nameColumn</jsf>);
 			<jk>this</jk>.<jf>valueColumn</jf> = getStringProperty(<jsf>CONFIGSQLSTORE_valueColumn</jsf>);		
 
-			<jk>int</jk> pollInterval = getStringProperty(<jsf>CONFIGSQLSTORE_pollInterval</jsf>, 600);
+			<jk>int</jk> pollInterval = getStringProperty(<jsf>CONFIGSQLSTORE_pollInterval</jsf>, 600);  <jc>// Time in seconds.</jc>
 			
 			TimerTask timerTask = <jk>new</jk> TimerTask() {
 				<ja>@Override</ja>
@@ -12689,7 +12689,7 @@
 			};
 
 			<jk>this</jk>.<jf>watcher</jf> = <jk>new</jk> Timer(<js>"MyTimer"</js>);
-			<jf>watcher</jf>.scheduleAtFixedRate(timerTask, 0, pollInterval * 10000);
+			<jf>watcher</jf>.scheduleAtFixedRate(timerTask, 0, pollInterval * 1000);
 		}
 		
 		<jk>private synchronized void</jk> poll() {
@@ -12726,7 +12726,7 @@
 		<jk>public synchronized</jk> String write(String name, String expectedContents, String newContents) {
 	
 			<jc>// This is a no-op.</jc>
-			<jk>if</jk> (isEquals(expectedContents, newContents))
+			<jk>if</jk> (<jsm>isEquals</jsm>(expectedContents, newContents))
 				<jk>return null</jk>;
 			
 			String currentContents = read(name);
@@ -12905,7 +12905,7 @@
 			<li>Any file that end with <code>.cfg</code>.  First one matched alphabetically is used.
 		</ol>
 	<li>
-		In the context classpath (i.e. inside the jar itself):
+		In the context classpath root package (i.e. inside the jar itself):
 		<ol>
 			<li><code>&lt;jar-name&gt;.cfg</code>
 			<li><code>juneau.cfg</code>
@@ -13489,7 +13489,7 @@
 	annotation. 
 </p>
 <p>
-	The code for this class is virtually identical to {@link org.apache.juneau.BasicRestServlet} but lacks a parent class:
+	The code for this class is virtually identical to {@link org.apache.juneau.rest.BasicRestServlet} but lacks a parent class:
 </p>
 <p class='bpcode w800'>
 	<ja>@RestResource</ja>(
diff --git a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java
index 2776ff3..e0437de 100644
--- a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java
+++ b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java
@@ -12,6 +12,8 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.rest;
 
+import javax.servlet.http.HttpServlet;
+
 import org.apache.juneau.jena.*;
 import org.apache.juneau.rest.annotation.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServletGroup.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServletGroup.java
index ddd20d0..fd40b31 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServletGroup.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestServletGroup.java
@@ -29,7 +29,7 @@ import org.apache.juneau.rest.helper.*;
  *
  * <h5 class='section'>See Also:</h5>
  * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.Instantiation.RouterPages}
+ * 	<li class='link'>{@doc juneau-rest-server.Instantiation.BasicRestServletGroup}
  * </ul>
  */
 @RestResource
diff --git a/pom.xml b/pom.xml
index f1d619c..998ebac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,9 +43,9 @@
 		<httpclient.version>4.5.6</httpclient.version>
 		<jetty.version>9.4.13.v20181111</jetty.version>
 		<juneau.compare.version>8.0.0</juneau.compare.version>
-		<javadoc.juneau.version>8.0.0</javadoc.juneau.version>
-		<juneauVersion>8.0.0</juneauVersion>
-		<juneauVersionNext>8.0.1</juneauVersionNext>
+		<javadoc.juneau.version>8.0.1</javadoc.juneau.version>
+		<juneauVersion>8.0.1</juneauVersion>
+		<juneauVersionNext>8.0.2</juneauVersionNext>
 		<derby.version>10.10.2.0</derby.version>
 		<hibernate.version>5.0.9.Final</hibernate.version>
 		<javax.inject.version>1</javax.inject.version>


[juneau] 08/09: Merge branch 'master' of https://gitbox.apache.org/repos/asf/juneau.git

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 561e70137a8676e35fd633265241f60ac4a90582
Merge: f44b3d5 f83dfaa
Author: JamesBognar <ja...@apache.org>
AuthorDate: Sun Mar 10 10:44:43 2019 -0400

    Merge branch 'master' of https://gitbox.apache.org/repos/asf/juneau.git

 .../src/main/java/org/apache/juneau/jena/RdfCommon.java              | 2 +-
 .../src/main/java/org/apache/juneau/jena/RdfParserBuilder.java       | 4 ++--
 .../src/main/java/org/apache/juneau/jena/RdfParserSession.java       | 5 ++---
 .../src/main/java/org/apache/juneau/jena/RdfSerializerBuilder.java   | 4 ++--
 .../src/main/java/org/apache/juneau/jena/RdfSerializerSession.java   | 3 +--
 juneau-doc/docs/docs.txt                                             | 2 +-
 juneau-doc/src/main/javadoc/overview.html                            | 2 +-
 juneau-doc/src/main/javadoc/resources/docs.txt                       | 2 +-
 pom.xml                                                              | 2 +-
 9 files changed, 12 insertions(+), 14 deletions(-)



[juneau] 07/09: Add new juneau-rest-mock project.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit f44b3d53554026b5eb7d98e11e8d96a646f501f6
Author: JamesBognar <ja...@apache.org>
AuthorDate: Sat Mar 9 16:56:25 2019 -0500

    Add new juneau-rest-mock project.
---
 .../juneau-microservice-test/pom.xml               |  23 +-
 .../org/apache/juneau/rest/test/MockRestTest.java  |   9 +-
 .../rest/test/client/CallbackStringsTest.java      |   4 +-
 .../juneau/rest/test/client/ClientFuturesTest.java |   4 +-
 .../juneau/rest/test/client/FormDataTest.java      |   7 +-
 .../rest/test/client/InterfaceProxyTest.java       |   5 +-
 .../rest/test/client/RequestBeanProxyTest.java     |  78 +++---
 juneau-rest/.DS_Store                              | Bin 6148 -> 6148 bytes
 .../.classpath                                     |   6 -
 juneau-rest/juneau-rest-client-test/.gitignore     |   2 +
 juneau-rest/juneau-rest-client-test/.project       |  26 ++
 .../juneau-rest-client-test}/pom.xml               | 156 ++++++++----
 .../rest/client/remote/BodyAnnotationTest.java     |   2 +-
 .../rest/client/remote/EndToEndInterfaceTest.java  |   9 +-
 .../rest/client/remote/FormDataAnnotationTest.java |   2 +-
 .../rest/client/remote/HeaderAnnotationTest.java   |   2 +-
 .../rest/client/remote/PathAnnotationTest.java     |   2 +-
 .../rest/client/remote/QueryAnnotationTest.java    |   2 +-
 .../client/remote/RemoteMethodAnnotationTest.java  |   2 +-
 .../remote/RemoteResourceAnnotationTest.java       |  14 +-
 .../rest/client/remote/RequestAnnotationTest.java  |   2 +-
 .../rest/client/remote/ResponseAnnotationTest.java |   2 +-
 juneau-rest/juneau-rest-client/.classpath          |   6 -
 .../.settings/org.eclipse.core.resources.prefs     |   1 -
 .../juneau/rest/client/RestClientBuilder.java      |  29 ++-
 .../juneau/rest/client/mock/package-info.java      |  18 --
 .../.classpath                                     |  16 +-
 juneau-rest/juneau-rest-mock/.gitignore            |   1 +
 juneau-rest/juneau-rest-mock/.project              |  26 ++
 juneau-rest/juneau-rest-mock/pom.xml               | 179 ++++++++++++++
 .../rest/mock2}/MockHttpClientConnection.java      |   2 +-
 .../mock2}/MockHttpClientConnectionManager.java    |   2 +-
 .../apache/juneau/rest/mock2}/MockHttpSession.java |   2 +-
 .../juneau/rest/mock2}/MockRemoteResource.java     | 163 ++++++-------
 .../org/apache/juneau/rest/mock2}/MockRest.java    | 240 +++++++++---------
 .../apache/juneau/rest/mock2/MockRestClient.java   | 268 +++++++++++++++++++++
 .../juneau/rest/mock2}/MockServletRequest.java     |   2 +-
 .../juneau/rest/mock2}/MockServletResponse.java    |   4 +-
 .../apache/juneau/rest/mock2}/package-info.java    |   2 +-
 .../org/apache/juneau/rest/testutils/ABean.java    |   0
 .../apache/juneau/rest/testutils/Constants.java    |   0
 .../org/apache/juneau/rest/testutils/DTOs.java     |   0
 .../juneau/rest/testutils/ImplicitSwappedPojo.java |   0
 .../apache/juneau/rest/testutils/SwappedPojo.java  |   0
 .../juneau/rest/testutils/SwappedPojoSwap.java     |   0
 .../org/apache/juneau/rest/testutils/TestEnum.java |   0
 .../apache/juneau/rest/testutils/TestUtils.java    |   2 +-
 .../apache/juneau/rest/testutils/TypedBean.java    |   0
 .../juneau/rest/testutils/TypedBeanImpl.java       |   0
 .../juneau/rest/testutils/XPartSerializer.java     |   0
 .../.classpath                                     |   5 -
 juneau-rest/juneau-rest-server-test/.gitignore     |   2 +
 juneau-rest/juneau-rest-server-test/.project       |  26 ++
 juneau-rest/juneau-rest-server-test/pom.xml        | 197 +++++++++++++++
 .../jueau/rest/helper/ReaderResourceTest.java      |   2 +-
 .../jueau/rest/helper/StreamResourceTest.java      |   2 +-
 .../juneau/rest/BasicRestInfoProviderTest.java     |   2 +-
 .../juneau/rest/BeanContextPropertiesTest.java     |   2 +-
 .../test/java/org/apache/juneau/rest/NlsTest.java  |   2 +-
 .../java/org/apache/juneau/rest/PathsTest.java     |   2 +-
 .../org/apache/juneau/rest/RestParamsTest.java     |   2 +-
 .../org/apache/juneau/rest/StatusCodesTest.java    |   2 +-
 .../apache/juneau/rest/ThreadLocalObjectsTest.java |   2 +-
 .../juneau/rest/annotation/HtmlDocAsideTest.java   |   2 +-
 .../juneau/rest/annotation/HtmlDocFooterTest.java  |   2 +-
 .../juneau/rest/annotation/HtmlDocHeaderTest.java  |   2 +-
 .../juneau/rest/annotation/HtmlDocNavTest.java     |   2 +-
 .../rest/annotation/HtmlDocNavlinksTest.java       |   2 +-
 .../juneau/rest/annotation/HtmlDocScriptTest.java  |   2 +-
 .../juneau/rest/annotation/HtmlDocStyleTest.java   |   2 +-
 .../annotation/ResponseBodyAnnotationTest.java     |   0
 .../annotation/ResponseHeaderAnnotationTest.java   |   2 +-
 .../annotation/ResponseStatusAnnotationTest.java   |   2 +-
 .../juneau/rest/annotation/RestMethodBpiTest.java  |   2 +-
 .../rest/annotation/RestMethodGuardsTest.java      |   2 +-
 .../rest/annotation/RestMethodMatchersTest.java    |   2 +-
 .../juneau/rest/annotation/RestMethodPathTest.java |   2 +-
 .../rest/annotation/RestResourceMessagesTest.java  |   2 +-
 .../rest/annotation/RestResourcePathTest.java      |   2 +-
 .../annotation/RestResourcePropertiesTest.java     |   2 +-
 .../annotation/RestResourceSerializersTest.java    |   2 +-
 .../annotation/RestResourceStaticFilesTest.java    |   2 +-
 .../annotation2/AnnotationInheritanceTest.java     |   2 +-
 .../rest/annotation2/BodyAnnotationTest.java       |   2 +-
 .../rest/annotation2/FormDataAnnotationTest.java   |   2 +-
 .../annotation2/HasFormDataAnnotationTest.java     |   2 +-
 .../rest/annotation2/HasQueryAnnotationTest.java   |   2 +-
 .../rest/annotation2/HeaderAnnotationTest.java     |   0
 .../rest/annotation2/PathAnnotationTest.java       |   2 +-
 .../annotation2/PathRemainderAnnotationTest.java   |   2 +-
 .../rest/annotation2/QueryAnnotationTest.java      |   2 +-
 .../rest/annotation2/ResponseAnnotationTest.java   |   2 +-
 .../juneau/rest/annotation2/RestHookTest.java      |   2 +-
 .../rest/annotation2/RestMethodInheritTest.java    |   2 +-
 .../rest/annotation2/RestResourceParsersTest.java  |   2 +-
 .../annotation2/RestResourcePojoSwapsTest.java     |   2 +-
 .../apache/juneau/rest/exception/BasicTest.java    |   2 +-
 .../juneau/rest/headers/AcceptCharsetTest.java     |   2 +-
 .../juneau/rest/headers/AcceptEncodingTest.java    |   2 +-
 .../org/apache/juneau/rest/headers/AcceptTest.java |   4 +-
 .../juneau/rest/headers/ClientVersionTest.java     |   2 +-
 .../juneau/rest/headers/ContentEncodingTest.java   |   2 +-
 .../juneau/rest/headers/ContentTypeTest.java       |   2 +-
 .../apache/juneau/rest/headers/HeadersTest.java    |   2 +-
 .../juneau/rest/mock/MockServletRequestTest.java   |   1 +
 .../org/apache/juneau/rest/response/BasicTest.java |   2 +-
 .../org/apache/juneau/rest/util/RestUtilsTest.java |   0
 .../juneau/rest/util/UrlPathPatternTest.java       |   0
 .../rest/BasicRestInfoProviderTest.properties      |   0
 .../rest/BasicRestInfoProviderTest_swagger.json    |   0
 .../org/apache/juneau/rest/NlsTest.properties      |   0
 .../apache/juneau/rest/RestParamsTest.properties   |   0
 .../juneau/rest/RestParamsTest_ja_JP.properties    |   0
 .../RestResourceMessagesTest1.properties           |   0
 .../RestResourceMessagesTest2.properties           |   0
 .../apache/juneau/rest/annotation/xdocs/test.txt   |   0
 .../juneau/rest/annotation/xdocs/xsubdocs/test.txt |   0
 juneau-rest/juneau-rest-server/.classpath          |  11 -
 .../.settings/org.eclipse.core.resources.prefs     |   2 -
 juneau-rest/pom.xml                                |   3 +
 120 files changed, 1206 insertions(+), 463 deletions(-)

diff --git a/juneau-microservice/juneau-microservice-test/pom.xml b/juneau-microservice/juneau-microservice-test/pom.xml
index 03c6f1b..cc1e5f5 100644
--- a/juneau-microservice/juneau-microservice-test/pom.xml
+++ b/juneau-microservice/juneau-microservice-test/pom.xml
@@ -43,19 +43,12 @@
 		</dependency>
 		<dependency>
 			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-core-test</artifactId>
-			<version>${project.version}</version>
-			<type>test-jar</type>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-rest-server</artifactId>
+			<artifactId>juneau-rest-server-jaxrs</artifactId>
 			<version>${project.version}</version>
-			<type>test-jar</type>
 		</dependency>
 		<dependency>
 			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-rest-server-jaxrs</artifactId>
+			<artifactId>juneau-rest-mock</artifactId>
 			<version>${project.version}</version>
 		</dependency>
 		<dependency>
@@ -84,6 +77,18 @@
 			<groupId>com.sun.activation</groupId>
 			<artifactId>javax.activation</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-core-test</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-rest-mock</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+		</dependency>
 	</dependencies>
 	
 	<build>
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java
index ac56130..ad50ecc 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java
@@ -17,9 +17,10 @@ import static org.junit.Assert.*;
 
 import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.json.*;
+import org.apache.juneau.marshall.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
@@ -45,15 +46,13 @@ public class MockRestTest {
 
 	@Test
 	public void a01() throws Exception {
-		MockRest a = MockRest.build(A.class, null);
-		RestClient rc = RestClient.create().mockHttpConnection(a).build();
+		RestClient rc = MockRestClient.build(A.class, null);
 		assertEquals("OK", rc.doPut("/a01", "OK").getResponseAsString());
 	}
 
 	@Test
 	public void a02() throws Exception {
-		MockRest a = MockRest.build(A.class);
-		RestClient rc = RestClient.create().json().mockHttpConnection(a).build();
+		RestClient rc = MockRestClient.build(A.class, Json.DEFAULT);
 		assertEquals("OK", rc.doPut("/a02", "OK").getResponse(String.class));
 	}
 }
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java
index 679cf84..45db140 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java
@@ -21,7 +21,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
@@ -50,7 +50,7 @@ public class CallbackStringsTest {
 			return m;
 		}
 	}
-	static RestClient a = RestClient.create().mockHttpConnection(MockRest.build(A.class, null)).build();
+	static RestClient a = MockRestClient.build(A.class, null);
 
 	@Test
 	public void a01() throws Exception {
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java
index 53ce031..ec548e1 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java
@@ -21,7 +21,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
@@ -39,7 +39,7 @@ public class ClientFuturesTest {
 			return new ObjectMap().append("foo","bar");
 		}
 	}
-	static RestClient a = RestClient.create().mockHttpConnection(MockRest.build(A.class, null)).build();
+	static RestClient a = MockRestClient.build(A.class, null);
 
 	@Test
 	public void a01() throws Exception {
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java
index b34642a..89e2b38 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java
@@ -18,10 +18,11 @@ import static org.junit.Assert.*;
 import java.io.*;
 import java.util.*;
 
+import org.apache.juneau.marshall.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.test.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
@@ -41,7 +42,7 @@ public class FormDataTest extends RestTestcase {
 			return new StringReader("Content-Type=["+req.getContentType()+"], contents=["+read(req.getReader())+"]");
 		}
 	}
-	static RestClient a = RestClient.create().mockHttpConnection(MockRest.build(A.class)).build();
+	static RestClient a = MockRestClient.build(A.class, SimpleJson.DEFAULT);
 
 	@Test
 	public void a01_formDataMethod() throws Exception {
@@ -61,7 +62,7 @@ public class FormDataTest extends RestTestcase {
 
 	@Test
 	public void a03_plainTextParams() throws Exception {
-		RestClient c = RestClient.create().mockHttpConnection(MockRest.build(A.class)).urlEnc().paramFormatPlain().build();
+		RestClient c = MockRestClient.create(A.class, UrlEncoding.DEFAULT).paramFormatPlain().build();
 		try {
 			String r;
 
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java
index c1b0a3f..be97827 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java
@@ -29,8 +29,7 @@ import org.apache.juneau.parser.*;
 import org.apache.juneau.remote.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.uon.*;
@@ -944,7 +943,7 @@ public class InterfaceProxyTest {
 	public InterfaceProxyTest(String label, Serializer serializer, Parser parser) {
 		proxy = cache.get(label);
 		if (proxy == null) {
-			proxy = RestClient.create().mockHttpConnection(interfaceProxyResource).serializer(serializer).parser(parser).build().getRrpcInterface(InterfaceProxy.class, "/proxy");
+			proxy = MockRestClient.create(InterfaceProxyResource.class, serializer, parser).build().getRrpcInterface(InterfaceProxy.class, "/proxy");
 			cache.put(label, proxy);
 		}
 	}
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
index d3ac26b..fe65ba2 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
@@ -30,7 +30,7 @@ import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
 import org.apache.juneau.rest.client.remote.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
@@ -52,7 +52,6 @@ public class RequestBeanProxyTest {
 			return req.getQuery().toString(true);
 		}
 	}
-	static MockRest a = MockRest.build(A.class, null);
 
 	//=================================================================================================================
 	// @Query - Simple values
@@ -88,8 +87,8 @@ public class RequestBeanProxyTest {
 		@Override public String getX7() { return "123"; }
 	}
 
-	static A01_RemoteResource a01a = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A01_RemoteResource.class, null);
-	static A01_RemoteResource a01b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(a).build().getRemoteResource(A01_RemoteResource.class, null);
+	static A01_RemoteResource a01a = MockRemoteResource.build(A01_RemoteResource.class, A.class, null);
+	static A01_RemoteResource a01b = MockRestClient.create(A.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(A01_RemoteResource.class);
 
 	@Test
 	public void a01a_query_simpleVals_plainText() throws Exception {
@@ -137,8 +136,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static A02_RemoteResource a02a = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A02_RemoteResource.class, null);
-	static A02_RemoteResource a02b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(a).build().getRemoteResource(A02_RemoteResource.class, null);
+	static A02_RemoteResource a02a = MockRemoteResource.build(A02_RemoteResource.class, A.class, null);
+	static A02_RemoteResource a02b = MockRestClient.create(A.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(A02_RemoteResource.class);
 
 	@Test
 	public void a02a_query_maps_plainText() throws Exception {
@@ -189,8 +188,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static A03_RemoteResource a03a = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A03_RemoteResource.class, null);
-	static A03_RemoteResource a03b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(a).build().getRemoteResource(A03_RemoteResource.class, null);
+	static A03_RemoteResource a03a = MockRemoteResource.build(A03_RemoteResource.class, A.class, null);
+	static A03_RemoteResource a03b = MockRestClient.create(A.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(A03_RemoteResource.class);
 
 	@Test
 	public void a03a_query_nameValuePairs_plainText() throws Exception {
@@ -225,7 +224,7 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static A04_RemoteResource a04a = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A04_RemoteResource.class, null);
+	static A04_RemoteResource a04a = MockRemoteResource.build(A04_RemoteResource.class, A.class, null);
 
 	@Test
 	public void a04a_query_charSequence() throws Exception {
@@ -250,7 +249,7 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static A05_RemoteResource a05a = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A05_RemoteResource.class, null);
+	static A05_RemoteResource a05a = MockRemoteResource.build(A05_RemoteResource.class, A.class, null);
 
 	@Test
 	public void a05a_query_reader() throws Exception {
@@ -311,8 +310,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static A06_RemoteResource a06a = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A06_RemoteResource.class, null);
-	static A06_RemoteResource a06b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(a).build().getRemoteResource(A06_RemoteResource.class, null);
+	static A06_RemoteResource a06a = MockRemoteResource.build(A06_RemoteResource.class, A.class, null);
+	static A06_RemoteResource a06b = MockRestClient.create(A.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(A06_RemoteResource.class);
 
 	@Test
 	public void a06a_query_collections_plainText() throws Exception {
@@ -341,7 +340,6 @@ public class RequestBeanProxyTest {
 			return req.getFormData().toString(true);
 		}
 	}
-	static MockRest c = MockRest.build(C.class, null);
 
 	//=================================================================================================================
 	// @FormData, Simple values
@@ -388,8 +386,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static C01_RemoteResource c01a = RestClient.create().mockHttpConnection(c).build().getRemoteResource(C01_RemoteResource.class, null);
-	static C01_RemoteResource c01b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(c).build().getRemoteResource(C01_RemoteResource.class, null);
+	static C01_RemoteResource c01a = MockRemoteResource.build(C01_RemoteResource.class, C.class, null);
+	static C01_RemoteResource c01b = MockRestClient.create(C.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(C01_RemoteResource.class);
 
 	@Test
 	public void c01a_formData_simpleVals_plainText() throws Exception {
@@ -440,8 +438,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static C02_RemoteResource c02a = RestClient.create().mockHttpConnection(c).build().getRemoteResource(C02_RemoteResource.class, null);
-	static C02_RemoteResource c02b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(c).build().getRemoteResource(C02_RemoteResource.class, null);
+	static C02_RemoteResource c02a = MockRemoteResource.build(C02_RemoteResource.class, C.class, null);
+	static C02_RemoteResource c02b = MockRestClient.create(C.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(C02_RemoteResource.class);
 
 	@Test
 	public void c02a_formData_maps_plainText() throws Exception {
@@ -492,8 +490,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static C03_RemoteResource c03a = RestClient.create().mockHttpConnection(c).build().getRemoteResource(C03_RemoteResource.class, null);
-	static C03_RemoteResource c03b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(c).build().getRemoteResource(C03_RemoteResource.class, null);
+	static C03_RemoteResource c03a = MockRemoteResource.build(C03_RemoteResource.class, C.class, null);
+	static C03_RemoteResource c03b = MockRestClient.create(C.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(C03_RemoteResource.class);
 
 	@Test
 	public void c03a_formData_nameValuePairs_plainText() throws Exception {
@@ -528,7 +526,7 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static C04_RemoteResource c04a = RestClient.create().mockHttpConnection(c).build().getRemoteResource(C04_RemoteResource.class, null);
+	static C04_RemoteResource c04a = MockRemoteResource.build(C04_RemoteResource.class, C.class, null);
 
 	@Test
 	public void c04a_formDataCharSequence() throws Exception {
@@ -553,7 +551,7 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static C05_RemoteResource c05a = RestClient.create().mockHttpConnection(c).build().getRemoteResource(C05_RemoteResource.class, null);
+	static C05_RemoteResource c05a = MockRemoteResource.build(C05_RemoteResource.class, C.class, null);
 
 	@Test
 	public void c05a_formDataReader() throws Exception {
@@ -614,8 +612,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static C06_RemoteResource c06a = RestClient.create().mockHttpConnection(c).build().getRemoteResource(C06_RemoteResource.class, null);
-	static C06_RemoteResource c06b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(c).build().getRemoteResource(C06_RemoteResource.class, null);
+	static C06_RemoteResource c06a = MockRemoteResource.build(C06_RemoteResource.class, C.class, null);
+	static C06_RemoteResource c06b = MockRestClient.create(C.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(C06_RemoteResource.class);
 
 	@Test
 	public void c06a_formData_collections_plainText() throws Exception {
@@ -645,7 +643,6 @@ public class RequestBeanProxyTest {
 			return req.getHeaders().subset("a,b,c,d,e,f,g,h,i,a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4").toString(true);
 		}
 	}
-	static MockRest e = MockRest.build(E.class, null);
 
 	//=================================================================================================================
 	// @Header, Simple values
@@ -692,8 +689,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static E01_RemoteResource e01a = RestClient.create().mockHttpConnection(e).build().getRemoteResource(E01_RemoteResource.class, null);
-	static E01_RemoteResource e01b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(e).build().getRemoteResource(E01_RemoteResource.class, null);
+	static E01_RemoteResource e01a = MockRemoteResource.build(E01_RemoteResource.class, E.class, null);
+	static E01_RemoteResource e01b = MockRestClient.create(E.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(E01_RemoteResource.class);
 
 	@Test
 	public void e01a_headerSimpleValsPlainText() throws Exception {
@@ -744,8 +741,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static E02_RemoteResource e02a = RestClient.create().mockHttpConnection(e).build().getRemoteResource(E02_RemoteResource.class, null);
-	static E02_RemoteResource e02b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(e).build().getRemoteResource(E02_RemoteResource.class, null);
+	static E02_RemoteResource e02a = MockRemoteResource.build(E02_RemoteResource.class, E.class, null);
+	static E02_RemoteResource e02b = MockRestClient.create(E.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(E02_RemoteResource.class);
 
 	@Test
 	public void e02a_header_maps_plainText() throws Exception {
@@ -796,8 +793,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static E03_RemoteResource e03a = RestClient.create().mockHttpConnection(e).build().getRemoteResource(E03_RemoteResource.class, null);
-	static E03_RemoteResource e03b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(e).build().getRemoteResource(E03_RemoteResource.class, null);
+	static E03_RemoteResource e03a = MockRemoteResource.build(E03_RemoteResource.class, E.class, null);
+	static E03_RemoteResource e03b = MockRestClient.create(E.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(E03_RemoteResource.class);
 
 	@Test
 	public void e03a_header_nameValuePairs_plainText() throws Exception {
@@ -868,8 +865,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static E04_RemoteResource e04a = RestClient.create().mockHttpConnection(e).build().getRemoteResource(E04_RemoteResource.class, null);
-	static E04_RemoteResource e04b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(e).build().getRemoteResource(E04_RemoteResource.class, null);
+	static E04_RemoteResource e04a = MockRemoteResource.build(E04_RemoteResource.class, E.class, null);
+	static E04_RemoteResource e04b = MockRestClient.create(E.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(E04_RemoteResource.class);
 
 	@Test
 	public void e04a_header_collections_plainText() throws Exception {
@@ -898,7 +895,6 @@ public class RequestBeanProxyTest {
 			return req.getPathMatch().getRemainder();
 		}
 	}
-	static MockRest g = MockRest.build(G.class, null);
 
 	//=================================================================================================================
 	// @Path, Simple values
@@ -941,8 +937,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static G01_RemoteResource g01a = RestClient.create().mockHttpConnection(g).build().getRemoteResource(G01_RemoteResource.class, null);
-	static G01_RemoteResource g01b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(g).build().getRemoteResource(G01_RemoteResource.class, null);
+	static G01_RemoteResource g01a = MockRemoteResource.build(G01_RemoteResource.class, G.class, null);
+	static G01_RemoteResource g01b = MockRestClient.create(G.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(G01_RemoteResource.class);
 
 	@Test
 	public void g01a_pathSimpleValsPlainText() throws Exception {
@@ -993,8 +989,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static G02_RemoteResource g02a = RestClient.create().mockHttpConnection(g).build().getRemoteResource(G02_RemoteResource.class, null);
-	static G02_RemoteResource g02b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(g).build().getRemoteResource(G02_RemoteResource.class, null);
+	static G02_RemoteResource g02a = MockRemoteResource.build(G02_RemoteResource.class, G.class, null);
+	static G02_RemoteResource g02b = MockRestClient.create(G.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(G02_RemoteResource.class);
 
 	@Test
 	public void g02a_path_maps_plainText() throws Exception {
@@ -1045,8 +1041,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static G03_RemoteResource g03a = RestClient.create().mockHttpConnection(g).build().getRemoteResource(G03_RemoteResource.class, null);
-	static G03_RemoteResource g03b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(g).build().getRemoteResource(G03_RemoteResource.class, null);
+	static G03_RemoteResource g03a = MockRemoteResource.build(G03_RemoteResource.class, G.class, null);
+	static G03_RemoteResource g03b = MockRestClient.create(G.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(G03_RemoteResource.class);
 
 	@Test
 	public void g03a_path_nameValuePairs_plainText() throws Exception {
@@ -1109,8 +1105,8 @@ public class RequestBeanProxyTest {
 		}
 	}
 
-	static G04_RemoteResource g04a = RestClient.create().mockHttpConnection(g).build().getRemoteResource(G04_RemoteResource.class, null);
-	static G04_RemoteResource g04b = RestClient.create().partSerializer(UonSerializer.class).mockHttpConnection(g).build().getRemoteResource(G04_RemoteResource.class, null);
+	static G04_RemoteResource g04a = MockRemoteResource.build(G04_RemoteResource.class, G.class, null);
+	static G04_RemoteResource g04b = MockRestClient.create(G.class, null).partSerializer(UonSerializer.class).build().getRemoteResource(G04_RemoteResource.class);
 
 	@Test
 	public void g04a_path_collections_plainText() throws Exception {
diff --git a/juneau-rest/.DS_Store b/juneau-rest/.DS_Store
index 82f59f7..739516e 100644
Binary files a/juneau-rest/.DS_Store and b/juneau-rest/.DS_Store differ
diff --git a/juneau-rest/juneau-rest-client/.classpath b/juneau-rest/juneau-rest-client-test/.classpath
similarity index 77%
copy from juneau-rest/juneau-rest-client/.classpath
copy to juneau-rest/juneau-rest-client-test/.classpath
index 3759907..0959e17 100644
--- a/juneau-rest/juneau-rest-client/.classpath
+++ b/juneau-rest/juneau-rest-client-test/.classpath
@@ -6,12 +6,6 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="src" output="target/classes" path="src/main/java">
-		<attributes>
-			<attribute name="optional" value="true"/>
-			<attribute name="maven.pomderived" value="true"/>
-		</attributes>
-	</classpathentry>
 	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
diff --git a/juneau-rest/juneau-rest-client-test/.gitignore b/juneau-rest/juneau-rest-client-test/.gitignore
new file mode 100644
index 0000000..22d1e37
--- /dev/null
+++ b/juneau-rest/juneau-rest-client-test/.gitignore
@@ -0,0 +1,2 @@
+/target/
+**/.DS_Store
diff --git a/juneau-rest/juneau-rest-client-test/.project b/juneau-rest/juneau-rest-client-test/.project
new file mode 100644
index 0000000..768df6c
--- /dev/null
+++ b/juneau-rest/juneau-rest-client-test/.project
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>juneau-rest-client</name>
+    <buildSpec>
+        <buildCommand>
+            <name>org.eclipse.jdt.core.javabuilder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+        <buildCommand>
+            <name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+        <buildCommand>
+            <name>org.eclipse.m2e.core.maven2Builder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+    </buildSpec>
+    <natures>
+        <nature>org.eclipse.m2e.core.maven2Nature</nature>
+        <nature>org.eclipse.jdt.core.javanature</nature>
+        <nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature>
+    </natures>
+</projectDescription>
diff --git a/juneau-microservice/juneau-microservice-test/pom.xml b/juneau-rest/juneau-rest-client-test/pom.xml
similarity index 51%
copy from juneau-microservice/juneau-microservice-test/pom.xml
copy to juneau-rest/juneau-rest-client-test/pom.xml
index 03c6f1b..95fd757 100644
--- a/juneau-microservice/juneau-microservice-test/pom.xml
+++ b/juneau-rest/juneau-rest-client-test/pom.xml
@@ -19,86 +19,158 @@
 
 	<parent>
 		<groupId>org.apache.juneau</groupId>
-		<artifactId>juneau-microservice</artifactId>
+		<artifactId>juneau-rest</artifactId>
 		<version>8.0.1-SNAPSHOT</version>
 	</parent>
 
-	<artifactId>juneau-microservice-test</artifactId>
-	<name>Apache Juneau Microservice Tests</name>
-	<description>Tests for Juneau Client/Server/Microservice.</description>
-
-	<properties>
-		<maven.javadoc.skip>true</maven.javadoc.skip>
-		
-		<!-- Java 8 required because Jetty requires it. -->
-		<maven.compiler.source>1.8</maven.compiler.source>
-		<maven.compiler.target>1.8</maven.compiler.target>
-	</properties>
+	<artifactId>juneau-rest-client-test</artifactId>
+	<name>Apache Juneau REST Client API - Tests</name>
+	<description>REST client API - Tests</description>
+	<packaging>bundle</packaging>
 
 	<dependencies>
 		<dependency>
 			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-examples-rest</artifactId>
+			<artifactId>juneau-marshall</artifactId>
 			<version>${project.version}</version>
 		</dependency>
 		<dependency>
-			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-core-test</artifactId>
-			<version>${project.version}</version>
-			<type>test-jar</type>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
 		</dependency>
 		<dependency>
-			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-rest-server</artifactId>
-			<version>${project.version}</version>
-			<type>test-jar</type>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-rest-server-jaxrs</artifactId>
-			<version>${project.version}</version>
+			<groupId>javax.activation</groupId>
+			<artifactId>javax.activation-api</artifactId>
 		</dependency>
 		<dependency>
-			<groupId>org.apache.juneau</groupId>
-			<artifactId>juneau-marshall-rdf</artifactId>
-			<version>${project.version}</version>
+			<groupId>com.sun.activation</groupId>
+			<artifactId>javax.activation</artifactId>
 		</dependency>
 		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>
-			<scope>compile</scope>
+			<scope>test</scope>
 		</dependency>
 		<dependency>
-			<groupId>javax.ws.rs</groupId>
-			<artifactId>jsr311-api</artifactId>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-rest-mock</artifactId>
+			<version>${project.version}</version>
 		</dependency>
 		<dependency>
-			<groupId>javax.servlet</groupId>
-			<artifactId>javax.servlet-api</artifactId>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-core-test</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+			<scope>test</scope>
 		</dependency>
 		<dependency>
-			<groupId>javax.activation</groupId>
-			<artifactId>javax.activation-api</artifactId>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-rest-mock</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+			<scope>test</scope>
 		</dependency>
 		<dependency>
-			<groupId>com.sun.activation</groupId>
-			<artifactId>javax.activation</artifactId>
+			<groupId>javax.servlet</groupId>
+			<artifactId>javax.servlet-api</artifactId>
+			<scope>test</scope>
 		</dependency>
 	</dependencies>
-	
+
+	<properties>
+		<!-- Skip javadoc generation since we generate them in the aggregate pom -->
+		<maven.javadoc.skip>true</maven.javadoc.skip>
+		
+		<maven.compiler.source>1.8</maven.compiler.source>
+		<maven.compiler.target>1.8</maven.compiler.target>
+	</properties>
+
 	<build>
 		<plugins>
 			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>3.2.0</version>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Automatic-Module-Name>org.apache.juneau.rest.client</Automatic-Module-Name>
+					</instructions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-source-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>attach-sources</id>
+						<phase>verify</phase>
+						<goals>
+							<goal>jar-no-fork</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-surefire-plugin</artifactId>
 				<configuration>
 					<includes>
-						<include>
-							**/_TestSuite.java
-						</include>
+						<include>**/*Test.class</include>
 					</includes>
 				</configuration>
 			</plugin>
+			<!--plugin>
+				<groupId>com.github.siom79.japicmp</groupId>
+				<artifactId>japicmp-maven-plugin</artifactId>
+				<version>0.13.0</version>
+				<configuration>
+					<oldVersion>
+						<dependency>
+							<groupId>org.apache.juneau</groupId>
+							<artifactId>${project.artifactId}</artifactId>
+							<version>${juneau.compare.version}</version>
+							<type>jar</type>
+						</dependency>
+					</oldVersion>
+					<newVersion>
+						<file>
+							<path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+						</file>
+					</newVersion>
+					<parameter>
+						<onlyModified>true</onlyModified>
+						<accessModifier>public</accessModifier>
+						<excludes>
+						</excludes>
+						<ignoreMissingClasses>true</ignoreMissingClasses>
+						<onlyBinaryIncompatible>true</onlyBinaryIncompatible>
+						<breakBuildOnBinaryIncompatibleModifications>true</breakBuildOnBinaryIncompatibleModifications>
+						<breakBuildIfCausedByExclusion>false</breakBuildIfCausedByExclusion>
+						<breakBuildBasedOnSemanticVersioning>true</breakBuildBasedOnSemanticVersioning>
+						<overrideCompatibilityChangeParameters>
+							<overrideCompatibilityChangeParameter>
+								<binaryCompatible>true</binaryCompatible>
+								<compatibilityChange>SUPERCLASS_REMOVED</compatibilityChange>
+								<sourceCompatible>true</sourceCompatible>
+							</overrideCompatibilityChangeParameter>
+							<overrideCompatibilityChangeParameter>
+								<binaryCompatible>true</binaryCompatible>
+								<compatibilityChange>FIELD_REMOVED_IN_SUPERCLASS</compatibilityChange>
+								<sourceCompatible>true</sourceCompatible>
+							</overrideCompatibilityChangeParameter>
+						</overrideCompatibilityChangeParameters>
+					</parameter>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>verify</phase>
+						<goals>
+							<goal>cmp</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin-->
 		</plugins>
 	</build>
 </project>
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
index 4946425..e5d5837 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.marshall.*;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
index 4428c6d..2246a93 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
@@ -26,11 +26,10 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.marshall.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.exception.*;
 import org.apache.juneau.rest.helper.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.MockRemoteResource;
 import org.apache.juneau.rest.response.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
@@ -207,7 +206,7 @@ public class EndToEndInterfaceTest {
 		@Override public UseProxy useProxy() { return UseProxy.INSTANCE; }
 	}
 
-	private static IC ic = RestClient.create().json().disableRedirectHandling().mockHttpConnection(MockRest.create(C.class).build()).build().getRemoteResource(IC.class);
+	private static IC ic = MockRestClient.create(C.class).json().disableRedirectHandling().build().getRemoteResource(IC.class);
 
 	@Test
 	public void c01_standardResponses_Ok() throws Exception {
@@ -1635,7 +1634,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static IH ih = RestClient.create().json().disableRedirectHandling().mockHttpConnection(MockRest.create(H.class).build()).build().getRemoteResource(IH.class);
+	private static IH ih = MockRestClient.create(H.class).json().disableRedirectHandling().build().getRemoteResource(IH.class);
 
 	@Test
 	public void h01_seeOtherRoot() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
index e131d74..159e65d 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
index 4fbc731..5ec37a3 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
@@ -25,7 +25,7 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
index 2fe42f2..9f878b7 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
@@ -25,7 +25,7 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
index 61697f4..56c686b 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
index ea44020..81f74d9 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
@@ -24,7 +24,7 @@ import org.apache.juneau.json.*;
 import org.apache.juneau.marshall.*;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
similarity index 92%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
index 8d0b2e7..0646468 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
@@ -16,8 +16,8 @@ import static org.junit.Assert.*;
 
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.client.mock.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
+import org.apache.juneau.rest.mock2.MockRemoteResource;
 import org.junit.*;
 import org.junit.runners.*;
 
@@ -50,7 +50,6 @@ public class RemoteResourceAnnotationTest {
 			return "foo";
 		}
 	}
-	private static MockRest a = MockRest.build(A.class, null);
 
 	@RemoteResource
 	public static interface A01a {
@@ -118,7 +117,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a02c_pathOnClient() throws Exception {
-		try (RestClient rc = RestClient.create().mockHttpConnection(a).rootUrl("http://localhost/A").build()) {
+		try (RestClient rc = MockRestClient.create(A.class, null).rootUrl("http://localhost/A").build()) {
 			A02c t = rc.getRemoteResource(A02c.class);
 			assertEquals("foo", t.a02());
 			assertEquals("foo", t.a02a());
@@ -174,7 +173,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a03c_partialPath() throws Exception {
-		try (RestClient rc = RestClient.create().mockHttpConnection(a).rootUrl("http://localhost/A").build()) {
+		try (RestClient rc = MockRestClient.create(A.class, null).rootUrl("http://localhost/A").build()) {
 			A03c t = rc.getRemoteResource(A03c.class);
 			assertEquals("foo", t.a03());
 			assertEquals("foo", t.a03a());
@@ -194,7 +193,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a03d_partialPathExtraSlashes() throws Exception {
-		try (RestClient rc = RestClient.create().mockHttpConnection(a).rootUrl("http://localhost/A/").build()) {
+		try (RestClient rc = MockRestClient.create(A.class, null).rootUrl("http://localhost/A/").build()) {
 			A03d t = rc.getRemoteResource(A03d.class);
 			assertEquals("foo", t.a03());
 			assertEquals("foo", t.a03a());
@@ -224,8 +223,7 @@ public class RemoteResourceAnnotationTest {
 			return "foo";
 		}
 	}
-	private static MockRest b = MockRest.build(B.class, null);
-	private static RestClient rb = RestClient.create().mockHttpConnection(b).rootUrl("http://localhost/B").build();
+	private static RestClient rb = MockRestClient.create(B.class, null).rootUrl("http://localhost/B").build();
 
 	@RemoteResource
 	public static interface B01 {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
index 3d83abe..a20b1b9 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
@@ -24,7 +24,7 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.testutils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
similarity index 98%
rename from juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
rename to juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
index 61b6dff..50561a9 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client-test/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
@@ -21,7 +21,7 @@ import org.apache.juneau.http.annotation.Response;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-client/.classpath b/juneau-rest/juneau-rest-client/.classpath
index 3759907..3ad59e4 100644
--- a/juneau-rest/juneau-rest-client/.classpath
+++ b/juneau-rest/juneau-rest-client/.classpath
@@ -1,11 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
-		<attributes>
-			<attribute name="optional" value="true"/>
-			<attribute name="maven.pomderived" value="true"/>
-		</attributes>
-	</classpathentry>
 	<classpathentry kind="src" output="target/classes" path="src/main/java">
 		<attributes>
 			<attribute name="optional" value="true"/>
diff --git a/juneau-rest/juneau-rest-client/.settings/org.eclipse.core.resources.prefs b/juneau-rest/juneau-rest-client/.settings/org.eclipse.core.resources.prefs
index f9fe345..e9441bb 100644
--- a/juneau-rest/juneau-rest-client/.settings/org.eclipse.core.resources.prefs
+++ b/juneau-rest/juneau-rest-client/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
-encoding//src/test/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 5ad6092..c18c58a 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -52,15 +52,14 @@ import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
+import org.apache.juneau.marshall.*;
 import org.apache.juneau.msgpack.*;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.plaintext.*;
-import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
-import org.apache.juneau.utils.*;
 import org.apache.juneau.xml.*;
 
 /**
@@ -583,10 +582,10 @@ public class RestClientBuilder extends BeanContextBuilder {
 	 * @param c The mock connection.
 	 * @return This object (for method chaining).
 	 */
-	public RestClientBuilder mockHttpConnection(MockHttpConnection c) {
-		rootUrl("http://localhost");
-		return httpClientConnectionManager(new MockHttpClientConnectionManager(c));
-	}
+//	public RestClientBuilder mockHttpConnection(MockHttpConnection c) {
+//		rootUrl("http://localhost");
+//		return httpClientConnectionManager(new MockHttpClientConnectionManager(c));
+//	}
 
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -1107,6 +1106,24 @@ public class RestClientBuilder extends BeanContextBuilder {
 	}
 
 	/**
+	 * Configuration property:  Marshall
+	 *
+	 * <p>
+	 * Shortcut for specifying the {@link RestClient#RESTCLIENT_serializer} and {@link RestClient#RESTCLIENT_parser}
+	 * using the serializer and parser defined in a marshall.
+	 *
+	 * @param value The values to add to this setting.
+	 * @return This object (for method chaining).
+	 */
+	public RestClientBuilder marshall(Marshall value) {
+		if (value == null)
+			serializer((Serializer)null).parser((Parser)null);
+		else
+			serializer(value.getSerializer()).parser(value.getParser());
+		return this;
+	}
+
+	/**
 	 * Configuration property:  Parser.
 	 *
 	 * <p>
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/package-info.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/package-info.java
deleted file mode 100644
index a991250..0000000
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/***************************************************************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations under the License.
- *
- ***************************************************************************************************************************/
-
-/**
- * REST Client Mock API
- */
-package org.apache.juneau.rest.client.mock;
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-client/.classpath b/juneau-rest/juneau-rest-mock/.classpath
similarity index 55%
copy from juneau-rest/juneau-rest-client/.classpath
copy to juneau-rest/juneau-rest-mock/.classpath
index 3759907..a47b97f 100644
--- a/juneau-rest/juneau-rest-client/.classpath
+++ b/juneau-rest/juneau-rest-mock/.classpath
@@ -1,14 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
-		<attributes>
-			<attribute name="optional" value="true"/>
-			<attribute name="maven.pomderived" value="true"/>
-		</attributes>
-	</classpathentry>
-	<classpathentry kind="src" output="target/classes" path="src/main/java">
+	<classpathentry kind="src" path="src/main/java"/>
+	<classpathentry kind="src" path="src/test/java"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
 		<attributes>
-			<attribute name="optional" value="true"/>
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
@@ -17,10 +12,5 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
-		<attributes>
-			<attribute name="maven.pomderived" value="true"/>
-		</attributes>
-	</classpathentry>
 	<classpathentry kind="output" path="target/classes"/>
 </classpath>
diff --git a/juneau-rest/juneau-rest-mock/.gitignore b/juneau-rest/juneau-rest-mock/.gitignore
new file mode 100644
index 0000000..ae3c172
--- /dev/null
+++ b/juneau-rest/juneau-rest-mock/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/juneau-rest/juneau-rest-mock/.project b/juneau-rest/juneau-rest-mock/.project
new file mode 100644
index 0000000..aee194a
--- /dev/null
+++ b/juneau-rest/juneau-rest-mock/.project
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>juneau-rest-mock</name>
+    <buildSpec>
+        <buildCommand>
+            <name>org.eclipse.jdt.core.javabuilder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+        <buildCommand>
+            <name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+        <buildCommand>
+            <name>org.eclipse.m2e.core.maven2Builder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+    </buildSpec>
+    <natures>
+        <nature>org.eclipse.m2e.core.maven2Nature</nature>
+        <nature>org.eclipse.jdt.core.javanature</nature>
+        <nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature>
+    </natures>
+</projectDescription>
diff --git a/juneau-rest/juneau-rest-mock/pom.xml b/juneau-rest/juneau-rest-mock/pom.xml
new file mode 100644
index 0000000..bac5215
--- /dev/null
+++ b/juneau-rest/juneau-rest-mock/pom.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+ * with the License.  You may obtain a copy of the License at                                                              *
+ *                                                                                                                         *
+ *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+ *                                                                                                                         *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+ * specific language governing permissions and limitations under the License.                                              *
+ ***************************************************************************************************************************
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.juneau</groupId>
+		<artifactId>juneau-rest</artifactId>
+		<version>8.0.1-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>juneau-rest-mock</artifactId>
+	<name>Apache Juneau REST Mock API</name>
+	<description>REST mock API</description>
+	<packaging>bundle</packaging>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-rest-server</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-rest-client</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>javax.activation</groupId>
+			<artifactId>javax.activation-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.sun.activation</groupId>
+			<artifactId>javax.activation</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-core-test</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>javax.servlet-api</artifactId>
+		</dependency>
+	</dependencies>
+
+	<properties>
+		<!-- Skip javadoc generation since we generate them in the aggregate pom -->
+		<maven.javadoc.skip>true</maven.javadoc.skip>
+		
+		<maven.compiler.source>1.8</maven.compiler.source>
+		<maven.compiler.target>1.8</maven.compiler.target>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>3.2.0</version>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Automatic-Module-Name>org.apache.juneau.rest.client</Automatic-Module-Name>
+					</instructions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-source-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>attach-sources</id>
+						<phase>verify</phase>
+						<goals>
+							<goal>jar-no-fork</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<includes>
+						<include>**/*Test.class</include>
+					</includes>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>test-jar</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<!--plugin>
+				<groupId>com.github.siom79.japicmp</groupId>
+				<artifactId>japicmp-maven-plugin</artifactId>
+				<version>0.13.0</version>
+				<configuration>
+					<oldVersion>
+						<dependency>
+							<groupId>org.apache.juneau</groupId>
+							<artifactId>${project.artifactId}</artifactId>
+							<version>${juneau.compare.version}</version>
+							<type>jar</type>
+						</dependency>
+					</oldVersion>
+					<newVersion>
+						<file>
+							<path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+						</file>
+					</newVersion>
+					<parameter>
+						<onlyModified>true</onlyModified>
+						<accessModifier>public</accessModifier>
+						<excludes>
+						</excludes>
+						<ignoreMissingClasses>true</ignoreMissingClasses>
+						<onlyBinaryIncompatible>true</onlyBinaryIncompatible>
+						<breakBuildOnBinaryIncompatibleModifications>true</breakBuildOnBinaryIncompatibleModifications>
+						<breakBuildIfCausedByExclusion>false</breakBuildIfCausedByExclusion>
+						<breakBuildBasedOnSemanticVersioning>true</breakBuildBasedOnSemanticVersioning>
+						<overrideCompatibilityChangeParameters>
+							<overrideCompatibilityChangeParameter>
+								<binaryCompatible>true</binaryCompatible>
+								<compatibilityChange>SUPERCLASS_REMOVED</compatibilityChange>
+								<sourceCompatible>true</sourceCompatible>
+							</overrideCompatibilityChangeParameter>
+							<overrideCompatibilityChangeParameter>
+								<binaryCompatible>true</binaryCompatible>
+								<compatibilityChange>FIELD_REMOVED_IN_SUPERCLASS</compatibilityChange>
+								<sourceCompatible>true</sourceCompatible>
+							</overrideCompatibilityChangeParameter>
+						</overrideCompatibilityChangeParameters>
+					</parameter>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>verify</phase>
+						<goals>
+							<goal>cmp</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin-->
+		</plugins>
+	</build>
+</project>
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnection.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpClientConnection.java
similarity index 99%
rename from juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnection.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpClientConnection.java
index f3ea773..1fa840f 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnection.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpClientConnection.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.client.mock;
+package org.apache.juneau.rest.mock2;
 
 import java.io.*;
 import java.util.*;
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnectionManager.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpClientConnectionManager.java
similarity index 98%
rename from juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnectionManager.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpClientConnectionManager.java
index 9c77433..99ce6ab 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnectionManager.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpClientConnectionManager.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.client.mock;
+package org.apache.juneau.rest.mock2;
 
 import java.io.*;
 import java.util.concurrent.*;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockHttpSession.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpSession.java
similarity index 98%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockHttpSession.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpSession.java
index edbfae3..27dee34 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockHttpSession.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockHttpSession.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.mock;
+package org.apache.juneau.rest.mock2;
 
 import java.util.*;
 
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockRemoteResource.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRemoteResource.java
similarity index 76%
rename from juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockRemoteResource.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRemoteResource.java
index 4ae5170..938b7c4 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockRemoteResource.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRemoteResource.java
@@ -10,15 +10,16 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.client.mock;
+package org.apache.juneau.rest.mock2;
 
 import java.util.*;
 
 import org.apache.juneau.json.*;
 import org.apache.juneau.marshall.*;
 import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.remote.*;
 import org.apache.juneau.serializer.*;
 
 /**
@@ -34,43 +35,59 @@ import org.apache.juneau.serializer.*;
  */
 public class MockRemoteResource<T> {
 
-	private MockRest.Builder mrb = MockRest.create();
+	private MockRest.Builder mrb;
+	private RestClientBuilder rcb = RestClient.create().json();
 	private final Class<T> intf;
-	private Serializer s = JsonSerializer.DEFAULT;
-	private Parser p = JsonParser.DEFAULT;
-	private boolean debug;
 
 	/**
 	 * Constructor.
 	 *
-	 * @param intf The remote interface.
-	 * @param impl The REST implementation class or bean.
+	 * @param intf
+	 * 	The remote interface annotated with {@link RemoteResource @RemoteResource}.
+	 * @param impl
+	 * 	The REST implementation bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
 	 */
 	protected MockRemoteResource(Class<T> intf, Object impl) {
 		this.intf = intf;
-		mrb.impl(impl);
+		mrb = MockRest.create(impl);
 	}
 
 	/**
-	 * Create a new builder using the specified remote resource interface and REST implementation class.
+	 * Create a new builder using the specified remote resource interface and REST implementation bean or bean class.
 	 *
-	 * @param intf The remote interface.
-	 * @param impl The REST implementation class.
+	 * <p>
+	 * Uses {@link JsonSerializer#DEFAULT} and {@link JsonParser#DEFAULT} for serializing and parsing by default.
+	 *
+	 *
+	 * @param intf
+	 * 	The remote interface annotated with {@link RemoteResource @RemoteResource}.
+	 * @param impl
+	 * 	The REST implementation bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
 	 * @return A new builder.
 	 */
-	public static <T> MockRemoteResource<T> create(Class<T> intf, Class<?> impl) {
+	public static <T> MockRemoteResource<T> create(Class<T> intf, Object impl) {
 		return new MockRemoteResource<>(intf, impl);
 	}
 
 	/**
-	 * Create a new builder using the specified remote resource interface and REST implementation bean.
+	 * Create a new builder using the specified remote resource interface and REST implementation bean or bean class.
 	 *
-	 * @param intf The remote interface.
-	 * @param impl The REST implementation bean.
+	 * <p>
+	 * Uses the serializer and parser defined on the specified marshall for serializing and parsing by default.
+	 *
+	 * @param intf
+	 * 	The remote interface annotated with {@link RemoteResource @RemoteResource}.
+	 * @param impl
+	 * 	The REST implementation bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @param m
+	 * 	The marshall to use for serializing and parsing the HTTP bodies.
 	 * @return A new builder.
 	 */
-	public static <T> MockRemoteResource<T> create(Class<T> intf, Object impl) {
-		return new MockRemoteResource<>(intf, impl);
+	public static <T> MockRemoteResource<T> create(Class<T> intf, Object impl, Marshall m) {
+		return new MockRemoteResource<>(intf, impl).marshall(m);
 	}
 
 	/**
@@ -80,26 +97,29 @@ public class MockRemoteResource<T> {
 	 */
 	public T build() {
 		MockRest mr = mrb.build();
-		return RestClient.create(s, p).debug(debug).mockHttpConnection(mr).headers(mr.getHeaders()).build().getRemoteResource(intf);
+		return rcb.httpClientConnectionManager(new MockHttpClientConnectionManager(mr)).rootUrl("http://localhost").headers(mr.getHeaders()).build().getRemoteResource(intf);
 	}
 
 	/**
 	 * Convenience method for getting a remote resource interface.
 	 *
 	 * <p>
+	 * Uses {@link JsonSerializer#DEFAULT} and {@link JsonParser#DEFAULT} for serializing and parsing by default.
+	 *
+	 * <p>
 	 * Equivalent to calling the following:
 	 * <p class='bcode w800'>
 	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).build();
 	 * </p>
 	 *
-	 * <p>
-	 * Uses JSON serialization and parsing.
-	 *
-	 * @param intf The remote proxy interface class.
-	 * @param impl The REST implementation class.
+	 * @param intf
+	 * 	The remote interface annotated with {@link RemoteResource @RemoteResource}.
+	 * @param impl
+	 * 	The REST implementation bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
 	 * @return A new proxy interface.
 	 */
-	public static <T> T build(Class<T> intf, Class<?> impl) {
+	public static <T> T build(Class<T> intf, Object impl) {
 		return create(intf, impl).build();
 	}
 
@@ -107,27 +127,7 @@ public class MockRemoteResource<T> {
 	 * Convenience method for getting a remote resource interface.
 	 *
 	 * <p>
-	 * Equivalent to calling the following:
-	 * <p class='bcode w800'>
-	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).serializer(s).parser(p).build();
-	 * </p>
-	 *
-	 * @param intf The remote proxy interface class.
-	 * @param impl The REST implementation class.
-	 * @param s
-	 * 	The serializer to use for serializing request bodies.
-	 * 	<br>Can be <jk>null</jk> to force no serializer to be used and no <code>Content-Type</code> header.
-	 * @param p
-	 * 	The parser to use for parsing response bodies.
-	 * 	<br>Can be <jk>null</jk> to force no parser to be used and no <code>Accept</code> header.
-	 * @return A new proxy interface.
-	 */
-	public static <T> T build(Class<T> intf, Class<?> impl, Serializer s, Parser p) {
-		return create(intf, impl).serializer(s).parser(p).build();
-	}
-
-	/**
-	 * Convenience method for getting a remote resource interface.
+	 * Uses the serializer and parser defined on the specified marshall for serializing and parsing by default.
 	 *
 	 * <p>
 	 * Equivalent to calling the following:
@@ -135,14 +135,17 @@ public class MockRemoteResource<T> {
 	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).marshall(m).build();
 	 * </p>
 	 *
-	 * @param intf The remote proxy interface class.
-	 * @param impl The REST implementation class.
+	 * @param intf
+	 * 	The remote interface annotated with {@link RemoteResource @RemoteResource}.
+	 * @param impl
+	 * 	The REST implementation bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
 	 * @param m
 	 * 	The marshall to use for serializing request bodies and parsing response bodies.
 	 * 	<br>Can be <jk>null</jk> to force no serializer or parser to be used and no <code>Accept</code> or <code>Content-Type</code> header.
 	 * @return A new proxy interface.
 	 */
-	public static <T> T build(Class<T> intf, Class<?> impl, Marshall m) {
+	public static <T> T build(Class<T> intf, Object impl, Marshall m) {
 		return create(intf, impl).marshall(m).build();
 	}
 
@@ -150,24 +153,7 @@ public class MockRemoteResource<T> {
 	 * Convenience method for getting a remote resource interface.
 	 *
 	 * <p>
-	 * Equivalent to calling the following:
-	 * <p class='bcode w800'>
-	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).build();
-	 * </p>
-	 *
-	 * <p>
-	 * Uses JSON serialization and parsing.
-	 *
-	 * @param intf The remote proxy interface class.
-	 * @param impl The REST implementation bean.
-	 * @return A new proxy interface.
-	 */
-	public static <T> T build(Class<T> intf, Object impl) {
-		return create(intf, impl).build();
-	}
-
-	/**
-	 * Convenience method for getting a remote resource interface.
+	 * Uses the specified serializer and parser for serializing and parsing by default.
 	 *
 	 * <p>
 	 * Equivalent to calling the following:
@@ -175,10 +161,17 @@ public class MockRemoteResource<T> {
 	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).serializer(s).parser(p).build();
 	 * </p>
 	 *
-	 * @param intf The remote proxy interface class.
-	 * @param impl The REST implementation object.
-	 * @param s The serializer to use for serializing request bodies.
-	 * @param p The parser to use for parsing response bodies.
+	 * @param intf
+	 * 	The remote interface annotated with {@link RemoteResource @RemoteResource}.
+	 * @param impl
+	 * 	The REST implementation bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @param s
+	 * 	The serializer to use for serializing request bodies.
+	 * 	<br>Can be <jk>null</jk> to force no serializer to be used and no <code>Content-Type</code> header.
+	 * @param p
+	 * 	The parser to use for parsing response bodies.
+	 * 	<br>Can be <jk>null</jk> to force no parser to be used and no <code>Accept</code> header.
 	 * @return A new proxy interface.
 	 */
 	public static <T> T build(Class<T> intf, Object impl, Serializer s, Parser p) {
@@ -186,31 +179,13 @@ public class MockRemoteResource<T> {
 	}
 
 	/**
-	 * Convenience method for getting a remote resource interface.
-	 *
-	 * <p>
-	 * Equivalent to calling the following:
-	 * <p class='bcode w800'>
-	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).marshall(m).build();
-	 * </p>
-	 *
-	 * @param intf The remote proxy interface class.
-	 * @param impl The REST implementation object.
-	 * @param m The marshall to use for serializing request bodies and parsing response bodies.
-	 * @return A new proxy interface.
-	 */
-	public static <T> T build(Class<T> intf, Object impl, Marshall m) {
-		return create(intf, impl).marshall(m).build();
-	}
-
-	/**
 	 * Enable debug mode.
 	 *
 	 * @return This object (for method chaining).
 	 */
 	public MockRemoteResource<T> debug() {
 		mrb.debug();
-		this.debug = true;
+		rcb.debug();
 		return this;
 	}
 
@@ -225,6 +200,7 @@ public class MockRemoteResource<T> {
 	 */
 	public MockRemoteResource<T> header(String name, Object value) {
 		mrb.header(name, value);
+		rcb.header(name, value);
 		return this;
 	}
 
@@ -239,6 +215,7 @@ public class MockRemoteResource<T> {
 	 */
 	public MockRemoteResource<T> headers(Map<String,Object> value) {
 		mrb.headers(value);
+		rcb.headers(value);
 		return this;
 	}
 
@@ -250,6 +227,7 @@ public class MockRemoteResource<T> {
 	 */
 	public MockRemoteResource<T> accept(String value) {
 		mrb.accept(value);
+		rcb.accept(value);
 		return this;
 	}
 
@@ -261,6 +239,7 @@ public class MockRemoteResource<T> {
 	 */
 	public MockRemoteResource<T> contentType(String value) {
 		mrb.contentType(value);
+		rcb.contentType(value);
 		return this;
 	}
 
@@ -383,7 +362,7 @@ public class MockRemoteResource<T> {
 	 * @return This object (for method chaining).
 	 */
 	public MockRemoteResource<T> serializer(Serializer value) {
-		this.s = value;
+		rcb.serializer(value);
 		contentType(value == null ? null : value.getPrimaryMediaType().toString());
 		return this;
 	}
@@ -397,7 +376,7 @@ public class MockRemoteResource<T> {
 	 * @return This object (for method chaining).
 	 */
 	public MockRemoteResource<T> parser(Parser value) {
-		this.p = value;
+		rcb.parser(value);
 		accept(value == null ? null : value.getPrimaryMediaType().toString());
 		return this;
 	}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRest.java
similarity index 68%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRest.java
index 698caba..8a03e2b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRest.java
@@ -10,15 +10,18 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.mock;
+package org.apache.juneau.rest.mock2;
 
 import java.io.*;
 import java.util.*;
 import java.util.concurrent.*;
 
 import org.apache.juneau.marshall.*;
+import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.util.*;
+import org.apache.juneau.serializer.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -77,12 +80,10 @@ public class MockRest implements MockHttpConnection {
 	protected MockRest(Builder b) {
 		try {
 			debug = b.debug;
-			Class<?> c = b.implClass;
-			Object o = b.implObject;
+			Class<?> c = b.impl instanceof Class ? (Class<?>)b.impl : b.impl.getClass();
 			Map<Class<?>,RestContext> contexts = debug ? CONTEXTS_DEBUG : CONTEXTS_NORMAL;
 			if (! contexts.containsKey(c)) {
-				if (o == null)
-					o = c.newInstance();
+				Object o = b.impl instanceof Class ? ((Class<?>)b.impl).newInstance() : b.impl;
 				RestContext rc = RestContext.create(o).logger(b.debug ? BasicRestLogger.class : NoOpRestLogger.class).build();
 				if (o instanceof RestServlet) {
 					((RestServlet)o).setContext(rc);
@@ -100,45 +101,26 @@ public class MockRest implements MockHttpConnection {
 	}
 
 	/**
-	 * Creates a new builder with no REST implementation.
-	 *
-	 * @return A new builder.
-	 */
-	public static Builder create() {
-		return new Builder();
-	}
-
-	/**
-	 * Creates a new builder with the specified REST implementation class.
+	 * Creates a new builder with the specified REST implementation bean or bean class.
 	 *
 	 * <p>
-	 * Uses Simple-JSON as the protocol by default.
+	 * No <code>Accept</code> or <code>Content-Type</code> header is specified by default.
 	 *
 	 * @param impl
-	 * 	The REST bean class.
-	 * 	<br>Class must have a no-arg constructor.
-	 * 	<br>Use {@link #create(Object)} for already-instantiated REST classes.
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
 	 * @return A new builder.
 	 */
-	public static Builder create(Class<?> impl) {
-		return create().impl(impl);
+	public static Builder create(Object impl) {
+		return new Builder(impl);
 	}
 
 	/**
-	 * Creates a new builder with the specified REST implementation class.
+	 * Convenience method for creating a MockRest over the specified REST implementation bean or bean class.
 	 *
 	 * <p>
-	 * Uses Simple-JSON as the protocol by default.
-	 *
-	 * @param impl The REST bean.
-	 * @return A new builder.
-	 */
-	public static Builder create(Object impl) {
-		return create().impl(impl);
-	}
-
-	/**
-	 * Convenience method for creating a MockRest over the specified REST implementation.
+	 * <code>Accept</code> header is set to <code>"application/json+simple"</code> by default.
+	 * <code>Content-Type</code> header is set to <code>"application/json"</code> by default.
 	 *
 	 * <p>
 	 * Equivalent to calling:
@@ -146,107 +128,82 @@ public class MockRest implements MockHttpConnection {
 	 * 	MockRest.create(impl, SimpleJson.<jsf>DEFAULT</jsf>).build();
 	 * </p>
 	 *
-	 * @param impl The REST bean class.
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
 	 * @return A new {@link MockRest} object.
 	 */
-	public static MockRest build(Class<?> impl) {
+	public static MockRest build(Object impl) {
 		return build(impl, SimpleJson.DEFAULT);
 	}
 
 	/**
-	 * Convenience method for creating a MockRest over the specified REST implementation.
+	 * Convenience method for creating a MockRest over the specified REST implementation bean or bean class.
+	 *
+	 * <p>
+	 * <code>Accept</code> and <code>Content-Type</code> headers are set to the primary media types on the specified marshall.
+	 *
+	 * <p>
+	 * Note that the marshall itself is not involved in any serialization or parsing.
 	 *
 	 * <p>
 	 * Equivalent to calling:
 	 * <p class='bpcode w800'>
-	 * 	MockRest.create(impl, SimpleJson.<jsf>DEFAULT</jsf>).build();
+	 * 	MockRest.create(impl, SimpleJson.<jsf>DEFAULT</jsf>).marshall(m).build();
 	 * </p>
 	 *
-	 * @param impl The REST bean.
-	 * @return A new {@link MockRest} object.
-	 */
-	public static MockRest build(Object impl) {
-		return build(impl, SimpleJson.DEFAULT);
-	}
-
-	/**
-	 * Convenience method for creating a MockRest over the specified REST implementation.
-	 *
-	 * @param impl The REST bean class.
-	 * @param m
-	 * 	The marshall to use for serializing and parsing HTTP bodies.
-	 * 	<br>Can be <jk>null</jk>.
-	 * @return A new {@link MockRest} object.
-	 */
-	public static MockRest build(Class<?> impl, Marshall m) {
-		Builder b = create().impl(impl);
-		if (m != null)
-			b.accept(m.getParser().getPrimaryMediaType().toString()).contentType(m.getSerializer().getPrimaryMediaType().toString());
-		return b.build();
-	}
-
-	/**
-	 * Convenience method for creating a MockRest over the specified REST implementation.
-	 *
-	 * @param impl The REST bean object.
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
 	 * @param m
-	 * 	The marshall to use for serializing and parsing HTTP bodies.
-	 * 	<br>Can be <jk>null</jk>.
+	 * 	The marshall to use for specifying the <code>Accept</code> and <code>Content-Type</code> headers.
+	 * 	<br>If <jk>null</jk>, headers will be reset.
 	 * @return A new {@link MockRest} object.
 	 */
 	public static MockRest build(Object impl, Marshall m) {
-		Builder b = create().impl(impl);
-		if (m != null)
-			b.accept(m.getParser().getPrimaryMediaType().toString()).contentType(m.getSerializer().getPrimaryMediaType().toString());
-		return b.build();
+		return create(impl).marshall(m).build();
 	}
 
 	/**
-	 * Returns the headers that were defined in this class.
+	 * Convenience method for creating a MockRest over the specified REST implementation bean or bean class.
+	 *
+	 * <p>
+	 * <code>Accept</code> and <code>Content-Type</code> headers are set to the primary media types on the specified serializer and parser.
+	 *
+	 * <p>
+	 * Note that the marshall itself is not involved in any serialization or parsing.
+	 *
+	 * <p>
+	 * Equivalent to calling:
+	 * <p class='bpcode w800'>
+	 * 	MockRest.create(impl, SimpleJson.<jsf>DEFAULT</jsf>).serializer(s).parser(p).build();
+	 * </p>
 	 *
-	 * @return The headers that were defined in this class.  Never <jk>null</jk>.
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @param s
+	 * 	The serializer to use for specifying the <code>Content-Type</code> header.
+	 * 	<br>If <jk>null</jk>, header will be reset.
+	 * @param p
+	 * 	The parser to use for specifying the <code>Accept</code> header.
+	 * 	<br>If <jk>null</jk>, header will be reset.
+	 * @return A new {@link MockRest} object.
 	 */
-	public Map<String,Object> getHeaders() {
-		return headers;
+	public static MockRest build(Object impl, Serializer s, Parser p) {
+		return create(impl).serializer(s).parser(p).build();
 	}
 
 	/**
 	 * Builder class.
 	 */
 	public static class Builder {
-		Class<?> implClass;
-		Object implObject;
+		Object impl;
 		boolean debug;
 		Map<String,Object> headers = new LinkedHashMap<>();
 
-		/**
-		 * Specifies the REST implementation class.
-		 *
-		 * @param value
-		 * 	The REST implementation class.
-		 * 	<br>Class must have a no-arg constructor.
-		 * @return This object (for method chaining).
-		 */
-		public Builder impl(Class<?> value) {
-			this.implClass = value;
-			return this;
-		}
-
-		/**
-		 * Specifies the REST implementation bean.
-		 *
-		 * @param value
-		 * 	The REST implementation bean.
-		 * @return This object (for method chaining).
-		 */
-		public Builder impl(Object value) {
-			if (value instanceof Class) {
-				this.implClass = (Class<?>)value;
-			} else {
-				this.implObject = value;
-				this.implClass = value.getClass();
-			}
-			return this;
+		Builder(Object impl) {
+			this.impl = impl;
 		}
 
 		/**
@@ -291,7 +248,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Adds an <code>Accept</code> header to every request.
+		 * Specifies the <code>Accept</code> header to every request.
 		 *
 		 * @param value The <code>Accept/code> header value.
 		 * @return This object (for method chaining).
@@ -301,7 +258,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Adds a <code>Content-Type</code> header to every request.
+		 * Specifies the  <code>Content-Type</code> header to every request.
 		 *
 		 * @param value The <code>Content-Type</code> header value.
 		 * @return This object (for method chaining).
@@ -311,7 +268,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -320,7 +277,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json+simple"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json+simple"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -329,7 +286,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/xml"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/xml"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -338,7 +295,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/html"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/html"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -347,7 +304,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/plain"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/plain"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -356,7 +313,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"octal/msgpack"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"octal/msgpack"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -365,7 +322,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/uon"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/uon"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -374,7 +331,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/x-www-form-urlencoded"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/x-www-form-urlencoded"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -383,7 +340,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/yaml"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/yaml"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -392,7 +349,7 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
-		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/openapi"</js>.
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/openapi"</js>.
 		 *
 		 * @return This object (for method chaining).
 		 */
@@ -401,6 +358,44 @@ public class MockRest implements MockHttpConnection {
 		}
 
 		/**
+		 * Convenience method for setting the <code>Content-Type</code> header to the primary media type on the specified serializer.
+		 *
+		 * @param value
+		 * 	The serializer to get the media type from.
+		 * 	<br>If <jk>null</jk>, header will be reset.
+		 * @return This object (for method chaining).
+		 */
+		public Builder serializer(Serializer value) {
+			return contentType(value == null ? null : value.getPrimaryMediaType().toString());
+		}
+
+		/**
+		 * Convenience method for setting the <code>Accept</code> header to the primary media type on the specified parser.
+		 *
+		 * @param value
+		 * 	The parser to get the media type from.
+		 * 	<br>If <jk>null</jk>, header will be reset.
+		 * @return This object (for method chaining).
+		 */
+		public Builder parser(Parser value) {
+			return accept(value == null ? null : value.getPrimaryMediaType().toString());
+		}
+
+		/**
+		 * Convenience method for setting the <code>Accept</code> and <code>Content-Type</code> headers to the primary media types on the specified marshall.
+		 *
+		 * @param value
+		 * 	The marshall to get the media types from.
+		 * 	<br>If <jk>null</jk>, headers will be reset.
+		 * @return This object (for method chaining).
+		 */
+		public Builder marshall(Marshall value) {
+			contentType(value == null ? null : value.getSerializer().getPrimaryMediaType().toString());
+			accept(value == null ? null : value.getParser().getPrimaryMediaType().toString());
+			return this;
+		}
+
+		/**
 		 * Create a new {@link MockRest} object based on the settings on this builder.
 		 *
 		 * @return A new {@link MockRest} object.
@@ -408,7 +403,6 @@ public class MockRest implements MockHttpConnection {
 		public MockRest build() {
 			return new MockRest(this);
 		}
-
 	}
 
 	/**
@@ -529,4 +523,16 @@ public class MockRest implements MockHttpConnection {
 	public MockServletRequest patch(String path, Object body) throws Exception {
 		return request("PATCH", path, null, body);
 	}
+
+	/**
+	 * Returns the headers that were defined in this class.
+	 *
+	 * @return
+	 * 	The headers that were defined in this class.
+	 * 	<br>Never <jk>null</jk>.
+	 */
+	public Map<String,Object> getHeaders() {
+		return headers;
+	}
+
 }
diff --git a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
new file mode 100644
index 0000000..7ebf139
--- /dev/null
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
@@ -0,0 +1,268 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.mock2;
+
+import org.apache.juneau.marshall.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.client.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * TODO
+ */
+public class MockRestClient extends RestClientBuilder {
+
+	private MockRest.Builder mrb;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 */
+	protected MockRestClient(Object impl) {
+		super(null, null);
+		mrb = MockRest.create(impl);
+		rootUrl("http://localhost");
+	}
+
+	/**
+	 * Creates a new RestClient builder configured with the specified REST implementation bean or bean class.
+	 *
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @return A new builder.
+	 */
+	public static MockRestClient create(Object impl) {
+		return new MockRestClient(impl);
+	}
+
+	/**
+	 * Creates a new RestClient builder configured with the specified REST implementation bean or bean class.
+	 *
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @param m
+	 * 	The marshall to use for serializing and parsing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remove the existing serializer/parser).
+	 * @return A new builder.
+	 */
+	public static MockRestClient create(Object impl, Marshall m) {
+		return create(impl).marshall(m);
+	}
+
+	/**
+	 * Creates a new RestClient builder configured with the specified REST implementation bean or bean class.
+	 *
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @param s
+	 * 	The serializer to use for serializing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remove the existing serializer).
+	 * @param p
+	 * 	The parser to use for parsing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remove the existing parser).
+	 * @return A new builder.
+	 */
+	public static MockRestClient create(Object impl, Serializer s, Parser p) {
+		return create(impl).serializer(s).parser(p);
+	}
+
+	/**
+	 * Convenience method for creating a Restclient over the specified REST implementation bean or bean class.
+	 *
+	 * <p>
+	 * Equivalent to calling:
+	 * <p class='bpcode w800'>
+	 * 	MockRestClient.create(impl, m).build();
+	 * </p>
+	 *
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @param m
+	 * 	The marshall to use for specifying the <code>Accept</code> and <code>Content-Type</code> headers.
+	 * 	<br>If <jk>null</jk>, headers will be reset.
+	 * @return A new {@link MockRest} object.
+	 */
+	public static RestClient build(Object impl, Marshall m) {
+		return create(impl, m).build();
+	}
+
+	/**
+	 * Convenience method for creating a Restclient over the specified REST implementation bean or bean class.
+	 *
+	 * <p>
+	 * Equivalent to calling:
+	 * <p class='bpcode w800'>
+	 * 	MockRestClient.create(impl, s, p).build();
+	 * </p>
+	 *
+	 * @param impl
+	 * 	The REST bean or bean class annotated with {@link RestResource @RestResource}.
+	 * 	<br>If a class, it must have a no-arg constructor.
+	 * @param s
+	 * 	The serializer to use for serializing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remove the existing serializer).
+	 * @param p
+	 * 	The parser to use for parsing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remove the existing parser).
+	 * @return A new {@link MockRest} object.
+	 */
+	public static RestClient build(Object impl, Serializer s, Parser p) {
+		return create(impl, s, p).build();
+	}
+
+	@Override
+	public RestClient build() {
+		httpClientConnectionManager(new MockHttpClientConnectionManager(mrb.build()));
+		return super.build();
+	}
+
+	/**
+	 * Enable debug mode.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient debug() {
+		mrb.debug();
+		debug();
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient json() {
+		marshall(Json.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json+simple"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient simpleJson() {
+		marshall(SimpleJson.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/xml"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient xml() {
+		marshall(Xml.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/html"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient html() {
+		marshall(Html.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/plain"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient plainText() {
+		marshall(PlainText.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"octal/msgpack"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient msgpack() {
+		marshall(MsgPack.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/uon"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient uon() {
+		marshall(Uon.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/x-www-form-urlencoded"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient urlEnc() {
+		marshall(UrlEncoding.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/openapi"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public MockRestClient openapi() {
+		marshall(OpenApi.DEFAULT);
+		return this;
+	}
+
+	@Override
+	public MockRestClient marshall(Marshall value) {
+		super.marshall(value);
+		mrb.marshall(value);
+		return this;
+	}
+
+	@Override
+	public MockRestClient serializer(Serializer value) {
+		super.serializer(value);
+		mrb.serializer(value);
+		return this;
+	}
+
+	@Override
+	public MockRestClient parser(Parser value) {
+		super.parser(value);
+		mrb.parser(value);
+		return this;
+	}
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletRequest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletRequest.java
index 5a9b1fd..ffe98d7 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletRequest.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.mock;
+package org.apache.juneau.rest.mock2;
 
 import static org.apache.juneau.internal.StringUtils.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletResponse.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletResponse.java
index 2418911..93b0858 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockServletResponse.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.mock;
+package org.apache.juneau.rest.mock2;
 
 import static org.apache.juneau.internal.StringUtils.*;
 
@@ -252,7 +252,7 @@ public class MockServletResponse implements HttpServletResponse, MockHttpRespons
 	@Override /* HttpServletResponse */
 	public Collection<String> getHeaders(String name) {
 		String[] s = headerMap.get(name);
-		return s == null ? Collections.EMPTY_LIST : Arrays.asList(s);
+		return s == null ? Collections.emptyList() : Arrays.asList(s);
 	}
 
 	@Override /* HttpServletResponse */
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/package-info.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/package-info.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/package-info.java
rename to juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/package-info.java
index ba27d99..11d7e56 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/package-info.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/package-info.java
@@ -15,4 +15,4 @@
 /**
  * REST Server Mock API
  */
-package org.apache.juneau.rest.mock;
\ No newline at end of file
+package org.apache.juneau.rest.mock2;
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/ABean.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/ABean.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/ABean.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/ABean.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/Constants.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/Constants.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/Constants.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/Constants.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/DTOs.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/DTOs.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/DTOs.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/DTOs.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
index 377c3c8..14b4040 100755
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
+++ b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
@@ -20,7 +20,7 @@ import java.util.zip.*;
 
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 
 @SuppressWarnings({"javadoc"})
 public class TestUtils extends org.apache.juneau.testutils.TestUtils {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java b/juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java
rename to juneau-rest/juneau-rest-mock/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java
diff --git a/juneau-rest/juneau-rest-server/.classpath b/juneau-rest/juneau-rest-server-test/.classpath
similarity index 86%
copy from juneau-rest/juneau-rest-server/.classpath
copy to juneau-rest/juneau-rest-server-test/.classpath
index e4980db..64866cc 100644
--- a/juneau-rest/juneau-rest-server/.classpath
+++ b/juneau-rest/juneau-rest-server-test/.classpath
@@ -12,11 +12,6 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
-		<attributes>
-			<attribute name="maven.pomderived" value="true"/>
-		</attributes>
-	</classpathentry>
 	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
diff --git a/juneau-rest/juneau-rest-server-test/.gitignore b/juneau-rest/juneau-rest-server-test/.gitignore
new file mode 100644
index 0000000..22d1e37
--- /dev/null
+++ b/juneau-rest/juneau-rest-server-test/.gitignore
@@ -0,0 +1,2 @@
+/target/
+**/.DS_Store
diff --git a/juneau-rest/juneau-rest-server-test/.project b/juneau-rest/juneau-rest-server-test/.project
new file mode 100644
index 0000000..f0b1d1a
--- /dev/null
+++ b/juneau-rest/juneau-rest-server-test/.project
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>juneau-rest-server</name>
+    <buildSpec>
+        <buildCommand>
+            <name>org.eclipse.jdt.core.javabuilder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+        <buildCommand>
+            <name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+        <buildCommand>
+            <name>org.eclipse.m2e.core.maven2Builder</name>
+            <arguments>
+            </arguments>
+        </buildCommand>
+    </buildSpec>
+    <natures>
+        <nature>org.eclipse.m2e.core.maven2Nature</nature>
+        <nature>org.eclipse.jdt.core.javanature</nature>
+        <nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature>
+    </natures>
+</projectDescription>
diff --git a/juneau-rest/juneau-rest-server-test/pom.xml b/juneau-rest/juneau-rest-server-test/pom.xml
new file mode 100644
index 0000000..b99c1f6
--- /dev/null
+++ b/juneau-rest/juneau-rest-server-test/pom.xml
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+ * with the License.  You may obtain a copy of the License at                                                              *
+ *                                                                                                                         *
+ *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+ *                                                                                                                         *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+ * specific language governing permissions and limitations under the License.                                              *
+ ***************************************************************************************************************************
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.juneau</groupId>
+		<artifactId>juneau-rest</artifactId>
+		<version>8.0.1-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>juneau-rest-server-test</artifactId>
+	<name>Apache Juneau REST Servlet API - Tests</name>
+	<description>REST servlet API - Tests</description>
+	<packaging>bundle</packaging>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-rest-mock</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>javax.servlet-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>javax.xml.bind</groupId>
+			<artifactId>jaxb-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>javax.activation</groupId>
+			<artifactId>javax.activation-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.sun.activation</groupId>
+			<artifactId>javax.activation</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-core-test</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.juneau</groupId>
+			<artifactId>juneau-rest-mock</artifactId>
+			<version>${project.version}</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+
+	<properties>
+		<!-- Skip javadoc generation since we generate them in the aggregate pom -->
+		<maven.javadoc.skip>true</maven.javadoc.skip>
+		
+		<maven.compiler.source>1.8</maven.compiler.source>
+		<maven.compiler.target>1.8</maven.compiler.target>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-source-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>attach-sources</id>
+						<phase>verify</phase>
+						<goals>
+							<goal>jar-no-fork</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>3.2.0</version>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Automatic-Module-Name>org.apache.juneau.rest.server</Automatic-Module-Name>
+					</instructions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<includes>
+						<include>**/*Test.class</include>
+					</includes>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>test-jar</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<!--plugin>
+				<groupId>com.github.siom79.japicmp</groupId>
+				<artifactId>japicmp-maven-plugin</artifactId>
+				<version>0.13.0</version>
+				<configuration>
+					<skip>false</skip>
+					<oldVersion>
+						<dependency>
+							<groupId>org.apache.juneau</groupId>
+							<artifactId>${project.artifactId}</artifactId>
+							<version>${juneau.compare.version}</version>
+							<type>jar</type>
+						</dependency>
+					</oldVersion>
+					<newVersion>
+						<file>
+							<path>${project.build.directory}/${project.artifactId}-${project.version}.jar</path>
+						</file>
+					</newVersion>
+					<parameter>
+						<onlyModified>true</onlyModified>
+						<accessModifier>public</accessModifier>
+						<excludes>
+							<exclude>org.apache.juneau.rest.response.DefaultHandler</exclude>
+							<exclude>org.apache.juneau.rest.response.InputStreamHandler</exclude>
+							<exclude>org.apache.juneau.rest.response.ReaderHandler</exclude>
+							<exclude>org.apache.juneau.rest.response.RedirectHandler</exclude>
+							<exclude>org.apache.juneau.rest.response.StreamableHandler</exclude>
+							<exclude>org.apache.juneau.rest.response.WritableHandler</exclude>
+							<exclude>org.apache.juneau.rest.response.ZipFileListFileHandler</exclude>
+							<exclude>org.apache.juneau.rest.ResponseHandler</exclude>
+							<exclude>org.apache.juneau.rest.RestCallHandler</exclude>
+							<exclude>org.apache.juneau.rest.RestException</exclude>
+						</excludes>
+						<ignoreMissingClasses>true</ignoreMissingClasses>
+						<onlyBinaryIncompatible>true</onlyBinaryIncompatible>
+						<breakBuildOnBinaryIncompatibleModifications>true</breakBuildOnBinaryIncompatibleModifications>
+						<breakBuildIfCausedByExclusion>false</breakBuildIfCausedByExclusion>
+						<breakBuildBasedOnSemanticVersioning>true</breakBuildBasedOnSemanticVersioning>
+						<overrideCompatibilityChangeParameters>
+							<overrideCompatibilityChangeParameter>
+								<binaryCompatible>true</binaryCompatible>
+								<compatibilityChange>SUPERCLASS_REMOVED</compatibilityChange>
+								<sourceCompatible>true</sourceCompatible>
+							</overrideCompatibilityChangeParameter>
+							<overrideCompatibilityChangeParameter>
+								<binaryCompatible>true</binaryCompatible>
+								<compatibilityChange>FIELD_REMOVED_IN_SUPERCLASS</compatibilityChange>
+								<sourceCompatible>true</sourceCompatible>
+							</overrideCompatibilityChangeParameter>
+							<overrideCompatibilityChangeParameter>
+								<binaryCompatible>true</binaryCompatible>
+								<compatibilityChange>METHOD_RETURN_TYPE_CHANGED</compatibilityChange>
+								<sourceCompatible>true</sourceCompatible>
+							</overrideCompatibilityChangeParameter>
+						</overrideCompatibilityChangeParameters>
+					</parameter>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>verify</phase>
+						<goals>
+							<goal>cmp</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin-->
+		</plugins>
+	</build>
+</project>
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
index 2db59fc..10ed8ca 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
@@ -21,7 +21,7 @@ import org.apache.juneau.http.ReaderResource;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.helper.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
index 38ad4af..01891f1 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
@@ -20,7 +20,7 @@ import org.apache.juneau.http.*;
 import org.apache.juneau.http.StreamResource;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
index c028638..65a804a 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
@@ -35,7 +35,7 @@ import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.http.annotation.Response;
 import org.apache.juneau.http.annotation.Tag;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
index 44b7bc1..ed99c60 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
@@ -21,7 +21,7 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.transforms.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/NlsTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/NlsTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/NlsTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/NlsTest.java
index c18aa55..23cd257 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/NlsTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/NlsTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest;
 import org.apache.juneau.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/PathsTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/PathsTest.java
index 69342e4..d4bc57b 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/PathsTest.java
@@ -17,7 +17,7 @@ import static org.apache.juneau.http.HttpMethodName.*;
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/RestParamsTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/RestParamsTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/RestParamsTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/RestParamsTest.java
index cecf860..3b02931 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/RestParamsTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/RestParamsTest.java
@@ -26,7 +26,7 @@ import org.apache.juneau.http.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/StatusCodesTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
index cc76593..d326837 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
@@ -22,7 +22,7 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.json.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
index bf66e81..29f4a3b 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest;
 import static org.junit.Assert.*;
 
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
index 4656c75..62735f9 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
index bd58daf..9a56fe8 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
index a3beaf8..593bc7b 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
index 63ae137..60c3611 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
index 36d8df6..68a4572 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
@@ -14,7 +14,7 @@ package org.apache.juneau.rest.annotation;
 
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
index 7922f1a..1cd1e05 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
index df8826d..3ef9c34 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
index 64a7655..54ab805 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
@@ -18,7 +18,7 @@ import static org.junit.Assert.*;
 import org.apache.juneau.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
similarity index 98%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
index 9d76202..f1b4fee 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
@@ -14,7 +14,7 @@ package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
index 4039a32..2d669a4 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
@@ -14,7 +14,7 @@ package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
index 52a452d..89456eb 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
index 8a1efef..d1a386e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest.annotation;
 import static org.apache.juneau.http.HttpMethodName.*;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
index 7a676e1..836e95e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
@@ -14,7 +14,7 @@ package org.apache.juneau.rest.annotation;
 
 import static org.apache.juneau.http.HttpMethodName.*;
 
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
index c184b05..591c113 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest.annotation;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
index 8268242..4f6928f 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest.annotation;
 import static org.apache.juneau.http.HttpMethodName.*;
 
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
index a85d8ab..a698488 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
@@ -17,7 +17,7 @@ import static org.apache.juneau.http.HttpMethodName.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
index ee08149..bf49439 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
@@ -14,7 +14,7 @@ package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.*;
 import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
index 95aa27e..cc34d43 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
@@ -12,7 +12,7 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.rest.annotation;
 
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
similarity index 98%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
index 17ecb93..4f2ad49 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
@@ -19,7 +19,7 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.json.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
index e1cbb2c..8bbc08d 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.rest.testutils.DTOs;
 import org.apache.juneau.uon.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
index 9189877..9b7a3c1 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
@@ -23,7 +23,7 @@ import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.annotation.FormData;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.urlencoding.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
similarity index 98%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
index 54df9aa..7285972 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest.annotation2;
 import org.apache.juneau.http.annotation.HasFormData;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
index 497d2d2..ddd12a0 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
@@ -17,7 +17,7 @@ import static org.apache.juneau.http.HttpMethodName.*;
 import org.apache.juneau.http.annotation.HasQuery;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
index f9bea60..cd6b057 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
@@ -23,7 +23,7 @@ import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
similarity index 98%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
index b3887f9..9f6463d 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
@@ -16,7 +16,7 @@ import static org.apache.juneau.http.HttpMethodName.*;
 
 import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
index 4da3c27..504dcce 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
@@ -25,7 +25,7 @@ import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.annotation.Items;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
index 7cd9519..b34962c 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
@@ -26,7 +26,7 @@ import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.annotation.Schema;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
index 1e8cb9c..4fe88bb 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
@@ -26,7 +26,7 @@ import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
index 002b04d..d031828 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
@@ -21,7 +21,7 @@ import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.transform.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
index 6074e0d..1ac2f61 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
@@ -20,7 +20,7 @@ import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
index b292c5e..ec4c6c4 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
@@ -20,7 +20,7 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.transform.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/exception/BasicTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
index 902612e..da03dcc 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
@@ -18,7 +18,7 @@ import static org.apache.juneau.rest.testutils.TestUtils.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
index b5cbcef..3605f0e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
@@ -21,7 +21,7 @@ import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.plaintext.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
index 09ad69e..69fe8ee 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
@@ -20,7 +20,7 @@ import java.io.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
index 0bb6fca..6d43320 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
@@ -18,7 +18,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.apache.juneau.serializer.*;
 import org.junit.*;
 import org.junit.runners.*;
@@ -98,7 +98,7 @@ public class AcceptTest {
 			return in;
 		}
 	}
-	private static MockRest b = MockRest.create().impl(B.class).build();
+	private static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_restMethodWithParsersSerializers_valid() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
index 028baf9..f575b07 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest.headers;
 import static org.apache.juneau.http.HttpMethodName.*;
 
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
index 928ba50..751bdc9 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
@@ -18,7 +18,7 @@ import static org.apache.juneau.rest.testutils.TestUtils.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
index c6a6b6b..f73d9fe 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
@@ -19,7 +19,7 @@ import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
index 939d2b5..f15a46c 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
@@ -22,7 +22,7 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.plaintext.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/mock/MockServletRequestTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/mock/MockServletRequestTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/mock/MockServletRequestTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/mock/MockServletRequestTest.java
index 3dfd36c..6a0f310 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/mock/MockServletRequestTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/mock/MockServletRequestTest.java
@@ -15,6 +15,7 @@ package org.apache.juneau.rest.mock;
 import static org.apache.juneau.rest.testutils.TestUtils.*;
 import static org.junit.Assert.*;
 
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/response/BasicTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/response/BasicTest.java
similarity index 99%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/response/BasicTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/response/BasicTest.java
index 40df96e..3507b21 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/response/BasicTest.java
+++ b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/response/BasicTest.java
@@ -21,7 +21,7 @@ import java.net.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.mock2.*;
 import org.junit.*;
 import org.junit.runners.*;
 
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/UrlPathPatternTest.java b/juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/util/UrlPathPatternTest.java
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/UrlPathPatternTest.java
rename to juneau-rest/juneau-rest-server-test/src/test/java/org/apache/juneau/rest/util/UrlPathPatternTest.java
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest.properties b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest.properties
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest.properties
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest.properties
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/BasicRestInfoProviderTest_swagger.json
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/NlsTest.properties b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/NlsTest.properties
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/NlsTest.properties
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/NlsTest.properties
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/RestParamsTest.properties b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/RestParamsTest.properties
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/RestParamsTest.properties
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/RestParamsTest.properties
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/RestParamsTest_ja_JP.properties b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/RestParamsTest_ja_JP.properties
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/RestParamsTest_ja_JP.properties
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/RestParamsTest_ja_JP.properties
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/xdocs/test.txt b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/xdocs/test.txt
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/xdocs/test.txt
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/xdocs/test.txt
diff --git a/juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/xdocs/xsubdocs/test.txt b/juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/xdocs/xsubdocs/test.txt
similarity index 100%
rename from juneau-rest/juneau-rest-server/src/test/resources/org/apache/juneau/rest/annotation/xdocs/xsubdocs/test.txt
rename to juneau-rest/juneau-rest-server-test/src/test/resources/org/apache/juneau/rest/annotation/xdocs/xsubdocs/test.txt
diff --git a/juneau-rest/juneau-rest-server/.classpath b/juneau-rest/juneau-rest-server/.classpath
index e4980db..c696e8f 100644
--- a/juneau-rest/juneau-rest-server/.classpath
+++ b/juneau-rest/juneau-rest-server/.classpath
@@ -1,11 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
-		<attributes>
-			<attribute name="optional" value="true"/>
-			<attribute name="maven.pomderived" value="true"/>
-		</attributes>
-	</classpathentry>
 	<classpathentry kind="src" output="target/classes" path="src/main/java">
 		<attributes>
 			<attribute name="optional" value="true"/>
@@ -17,11 +11,6 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
-		<attributes>
-			<attribute name="maven.pomderived" value="true"/>
-		</attributes>
-	</classpathentry>
 	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
diff --git a/juneau-rest/juneau-rest-server/.settings/org.eclipse.core.resources.prefs b/juneau-rest/juneau-rest-server/.settings/org.eclipse.core.resources.prefs
index 29abf99..abdea9a 100644
--- a/juneau-rest/juneau-rest-server/.settings/org.eclipse.core.resources.prefs
+++ b/juneau-rest/juneau-rest-server/.settings/org.eclipse.core.resources.prefs
@@ -1,6 +1,4 @@
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
-encoding//src/test/java=UTF-8
-encoding//src/test/resources=UTF-8
 encoding/<project>=UTF-8
diff --git a/juneau-rest/pom.xml b/juneau-rest/pom.xml
index f6a2533..edabeee 100644
--- a/juneau-rest/pom.xml
+++ b/juneau-rest/pom.xml
@@ -34,6 +34,9 @@
 		<module>juneau-rest-server-rdf</module>
 		<module>juneau-rest-server-springboot</module>
 		<module>juneau-rest-client</module>
+		<module>juneau-rest-mock</module>
+		<module>juneau-rest-server-test</module>
+		<module>juneau-rest-client-test</module>
 	</modules>
 
 </project>


[juneau] 05/09: Add RestResponse access to HTML widgets.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit f6e2dc415d8ef486d451e5007b8214cd0637a891
Author: JamesBognar <ja...@apache.org>
AuthorDate: Mon Feb 18 10:39:20 2019 -0500

    Add RestResponse access to HTML widgets.
---
 .../java/org/apache/juneau/config/ConfigTest.java  |    2 +-
 .../apache/juneau/pojotools/PojoSearcherTest.java  | 1056 ++++++++++++++++++++
 .../apache/juneau/pojotools/PojoSorterTest.java    |  265 +++++
 .../apache/juneau/pojotools/PojoViewerTest.java    |  349 +++++++
 .../apache/juneau/internal/DelegateBeanMap.java    |    8 +-
 .../org/apache/juneau/internal/DelegateMap.java    |   19 +-
 .../org/apache/juneau/internal/ObjectUtils.java    |   28 +
 .../apache/juneau/internal/StateMachineState.java  |   31 +-
 .../org/apache/juneau/internal/StringUtils.java    |   76 +-
 .../java/org/apache/juneau/pojotools/Equality.java |   33 +-
 .../java/org/apache/juneau/pojotools/Matcher.java  |   30 +-
 .../apache/juneau/pojotools/MatcherFactory.java    |   35 +-
 .../juneau/pojotools/NumberMatcherFactory.java     |  291 ++++++
 .../apache/juneau/pojotools/PatternException.java  |   29 +-
 .../org/apache/juneau/pojotools/PojoPaginator.java |   71 ++
 .../org/apache/juneau/pojotools/PojoSearcher.java  |  185 ++++
 .../org/apache/juneau/pojotools/PojoSorter.java    |  110 ++
 .../java/org/apache/juneau/pojotools/PojoTool.java |   31 +-
 .../org/apache/juneau/pojotools/PojoViewer.java    |   80 ++
 .../{utils/ASet.java => pojotools/SearchArgs.java} |   73 +-
 .../DelegateMap.java => pojotools/SortArgs.java}   |  138 +--
 .../juneau/pojotools/StringMatcherFactory.java     |  145 +++
 .../juneau/pojotools/TimeMatcherFactory.java       |  463 +++++++++
 .../java/org/apache/juneau/pojotools/ViewArgs.java |   59 +-
 .../main/java/org/apache/juneau/utils/ASet.java    |    1 +
 .../java/org/apache/juneau/utils/PojoQuery.java    |    2 +-
 juneau-doc/docs/ReleaseNotes/8.0.1.html            |    2 +
 .../rest/petstore/rest/AddOrderMenuItem.java       |    6 +-
 .../rest/petstore/rest/AddPetMenuItem.java         |    4 +-
 .../rest/petstore/rest/UploadPhotoMenuItem.java    |    4 +-
 .../apache/juneau/rest/BasicRestCallHandler.java   |    3 +-
 .../org/apache/juneau/rest/RestCallHandler.java    |    3 +-
 .../java/org/apache/juneau/rest/RestContext.java   |    6 +-
 .../java/org/apache/juneau/rest/RestRequest.java   |    3 +-
 .../org/apache/juneau/rest/annotation/HtmlDoc.java |    6 +-
 .../org/apache/juneau/rest/vars/RequestVar.java    |    5 +
 .../org/apache/juneau/rest/vars/WidgetVar.java     |    8 +-
 .../juneau/rest/widget/ContentTypeMenuItem.java    |    4 +-
 .../apache/juneau/rest/widget/MenuItemWidget.java  |   32 +-
 .../apache/juneau/rest/widget/PoweredByApache.java |    2 +-
 .../apache/juneau/rest/widget/PoweredByJuneau.java |    2 +-
 .../apache/juneau/rest/widget/QueryMenuItem.java   |    8 +-
 .../apache/juneau/rest/widget/ThemeMenuItem.java   |    4 +-
 .../java/org/apache/juneau/rest/widget/Widget.java |   18 +-
 44 files changed, 3414 insertions(+), 316 deletions(-)

diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java
index 9555f64..a0d0ed8 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigTest.java
@@ -1742,7 +1742,7 @@ public class ConfigTest {
 		assertObjectEquals("['foo.txt']", Config.getCandidateSystemDefaultConfigNames());
 
 		System.clearProperty("juneau.configFile");
-		assertObjectEquals("['test.cfg','juneau.cfg','default.cfg']", Config.getCandidateSystemDefaultConfigNames());
+		assertObjectEquals("['test.cfg','juneau.cfg','default.cfg','application.cfg','app.cfg','settings.cfg']", Config.getCandidateSystemDefaultConfigNames());
 	}
 
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSearcherTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSearcherTest.java
new file mode 100755
index 0000000..8374d58
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSearcherTest.java
@@ -0,0 +1,1056 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transforms.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+
+/**
+ * Tests the PojoSearcher class.
+ */
+public class PojoSearcherTest {
+
+	private static BeanSession bs = BeanContext.DEFAULT.createSession();
+	private static PojoSearcher ps = PojoSearcher.DEFAULT;
+	private static WriterSerializer ws = JsonSerializer.create().ssq().pojoSwaps(CalendarSwap.DateTimeSimple.class).build();
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Utility
+	//-----------------------------------------------------------------------------------------------------------------
+
+	static SearchArgs[] create(String...search) {
+		SearchArgs[] sa = new SearchArgs[search.length];
+		for (int i = 0; i < search.length; i++)
+			sa[i] = new SearchArgs(search[i]);
+		return sa;
+	}
+
+	static SearchArgs create(String search) {
+		return new SearchArgs(search);
+	}
+
+	static Object run(Object in, String search) {
+		return ps.run(bs, in, create(search));
+	}
+
+	static Object run(Object in, SearchArgs sa) {
+		return ps.run(bs, in, sa);
+	}
+
+	static String[] a(String...s) {
+		return s;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// String search
+	//-----------------------------------------------------------------------------------------------------------------
+
+	public static class A {
+		public String f;
+
+		public static A create(String f) {
+			A a = new A();
+			a.f = f;
+			return a;
+		}
+	}
+
+	public static List<A> A_LIST = AList.create(A.create("foo"), A.create("bar"), A.create("baz"), A.create("q ux"), A.create("qu'ux"), null, A.create(null));
+	public static Set<A> A_SET = ASet.create(A.create("foo"), A.create("bar"), A.create("baz"), A.create("q ux"), A.create("qu'ux"), null, A.create(null));
+	public static A[] A_ARRAY = new A[]{A.create("foo"), A.create("bar"), A.create("baz"), A.create("q ux"), A.create("qu'ux"), null, A.create(null)};
+
+	@Test
+	public void stringSearch_singleWord() throws Exception {
+		assertObjectEquals("[{f:'foo'}]", run(A_LIST, "f=foo"));
+		assertObjectEquals("[{f:'foo'}]", run(A_SET, "f=foo"));
+		assertObjectEquals("[{f:'foo'}]", run(A_ARRAY, "f=foo"));
+	}
+
+	@Test
+	public void stringSearch_pattern1() throws Exception {
+		assertObjectEquals("[{f:'foo'}]", run(A_LIST, "f=fo*"));
+		assertObjectEquals("[{f:'foo'}]", run(A_SET, "f=fo*"));
+		assertObjectEquals("[{f:'foo'}]", run(A_ARRAY, "f=fo*"));
+	}
+
+	@Test
+	public void stringSearch_pattern2() throws Exception {
+		assertObjectEquals("[{f:'bar'}]", run(A_LIST, "f=*ar"));
+		assertObjectEquals("[{f:'bar'}]", run(A_SET, "f=*ar"));
+		assertObjectEquals("[{f:'bar'}]", run(A_ARRAY, "f=*ar"));
+	}
+
+	@Test
+	public void stringSearch_pattern3() throws Exception {
+		assertObjectEquals("[{f:'bar'}]", run(A_LIST, "f=?ar"));
+		assertObjectEquals("[{f:'bar'}]", run(A_SET, "f=?ar"));
+		assertObjectEquals("[{f:'bar'}]", run(A_ARRAY, "f=?ar"));
+	}
+
+	@Test
+	public void stringSearch_multiple() throws Exception {
+		assertObjectEquals("[{f:'foo'},{f:'bar'}]", run(A_LIST, "f=foo bar q ux"));
+		assertObjectEquals("[{f:'foo'},{f:'bar'}]", run(A_SET, "f=foo bar q ux"));
+		assertObjectEquals("[{f:'foo'},{f:'bar'}]", run(A_ARRAY, "f=foo bar q ux"));
+	}
+
+	@Test
+	public void stringSearch_quoted() throws Exception {
+		assertObjectEquals("[{f:'q ux'}]", run(A_LIST, "f='q ux'"));
+		assertObjectEquals("[{f:'q ux'}]", run(A_SET, "f='q ux'"));
+		assertObjectEquals("[{f:'q ux'}]", run(A_ARRAY, "f='q ux'"));
+	}
+
+	@Test
+	public void stringSearch_quotedWithPattern() throws Exception {
+		assertObjectEquals("[{f:'q ux'}]", run(A_LIST, "f='q *x'"));
+		assertObjectEquals("[{f:'q ux'}]", run(A_SET, "f='q *x'"));
+		assertObjectEquals("[{f:'q ux'}]", run(A_ARRAY, "f='q *x'"));
+	}
+
+	@Test
+	public void stringSearch_unquotedContainingQuote() throws Exception {
+		assertObjectEquals("[{f:'qu\\'ux'}]", run(A_LIST, "f=qu'ux"));
+		assertObjectEquals("[{f:'qu\\'ux'}]", run(A_SET, "f=qu'ux"));
+		assertObjectEquals("[{f:'qu\\'ux'}]", run(A_ARRAY, "f=qu'ux"));
+	}
+
+	@Test
+	public void stringSearch_quotedContainingQuote() throws Exception {
+		assertObjectEquals("[{f:'qu\\'ux'}]", run(A_LIST, "f='qu\\'ux'"));
+		assertObjectEquals("[{f:'qu\\'ux'}]", run(A_SET, "f='qu\\'ux'"));
+		assertObjectEquals("[{f:'qu\\'ux'}]", run(A_ARRAY, "f='qu\\'ux'"));
+	}
+
+	@Test
+	public void stringSearch_regExp() throws Exception {
+		assertObjectEquals("[{f:'q ux'}]", run(A_LIST, "f=/q\\sux/"));
+		assertObjectEquals("[{f:'q ux'}]", run(A_SET, "f=/q\\sux/"));
+		assertObjectEquals("[{f:'q ux'}]", run(A_ARRAY, "f=/q\\sux/"));
+	}
+
+	@Test
+	public void stringSearch_regExp_noEndSlash() throws Exception {
+		Object in = AList.create(A.create("/foo"), A.create("bar"));
+		for (String s : a("f=/foo","f='/foo'")) // Not a regex.
+			assertObjectEquals("[{f:'/foo'}]", run(in, s));
+	}
+
+	@Test
+	public void stringSearch_regExp_onlySlash() throws Exception {
+		Object in = AList.create(A.create("/"), A.create("bar"));
+		for (String s : a("f=/", "f='/'")) // Not a regex.
+			assertObjectEquals("[{f:'/'}]", run(in, s));
+	}
+
+	@Test
+	public void stringSearch_or_pattern() throws Exception {
+		Object in = AList.create(A.create("foo"), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[{f:'foo'},{f:'bar'}]", run(in, "f=f* *r"));
+		assertObjectEquals("[]", run(in, "f='f* *r'"));
+		assertObjectEquals("[{f:'foo'}]", run(in, "f='f*oo'"));
+	}
+
+	@Test
+	public void stringSearch_explicit_or_pattern() throws Exception {
+		Object in = AList.create(A.create("foo"), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[{f:'foo'},{f:'bar'}]", run(in, "f=^f* ^*r"));
+		assertObjectEquals("[]", run(in, "f=^'f* *r'"));
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=^'f*oo'"));
+	}
+
+	@Test
+	public void stringSearch_and_pattern() throws Exception {
+		Object in = AList.create(A.create("foo"), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[{f:'bar'}]", run(in, "f=+b* +*r"));
+		assertObjectEquals("[{f:'bar'}]", run(in, "f=+'b*' +'*r'"));
+	}
+
+	@Test
+	public void stringSearch_not_pattern() throws Exception {
+		Object in = AList.create(A.create("foo"), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[{f:'baz'}]", run(in, "f=b* -*r"));
+		assertObjectEquals("[{f:'baz'}]", run(in, "f=+'b*' -'*r'"));
+	}
+
+	@Test
+	public void stringSearch_caseSensitive() throws Exception {
+		Object in = AList.create(A.create("foo"), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[]", run(in, "f=F*"));
+		assertObjectEquals("[]", run(in, "f=\"F*\""));
+		assertObjectEquals("[{f:'foo'}]", run(in, "f='F*'"));
+	}
+
+	@Test
+	public void stringSearch_malformedQuotes() throws Exception {
+		Object in = AList.create(A.create("'foo"), A.create("\"bar"), A.create("baz"));
+
+		try {
+			run(in, "f='*");
+			fail();
+		} catch (Exception e) {
+			assertTrue(e.getLocalizedMessage().contains("Unmatched string quotes"));
+		}
+
+		try {
+			run(in, "f=\"*");
+			fail();
+		} catch (Exception e) {
+			assertTrue(e.getLocalizedMessage().contains("Unmatched string quotes"));
+		}
+
+		assertObjectEquals("[{f:'\\'foo'}]", run(in, "f='\\'*'"));
+		assertObjectEquals("[{f:'\"bar'}]", run(in, "f='\"*'"));
+		assertObjectEquals("[{f:'\"bar'}]", run(in, "f=\"\\\"*\""));
+	}
+
+	@Test
+	public void stringSearch_regexChars() throws Exception {
+		Object in = AList.create(A.create("+\\[]{}()^$."), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[{f:'+\\\\[]{}()^$.'}]", run(in, "f=*+*"));
+		assertObjectEquals("[{f:'+\\\\[]{}()^$.'}]", run(in, "f='+\\\\[]{}()^$.'"));
+		assertObjectEquals("[{f:'+\\\\[]{}()^$.'}]", run(in, "f=++\\\\[]{}()^$."));
+	}
+
+	@Test
+	public void stringSearch_metaChars() throws Exception {
+		Object in = AList.create(A.create("*?\\'\""), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[{f:'*?\\\\\\'\"'}]", run(in, "f='\\*\\?\\\\\\'\"'"));
+	}
+
+	@Test
+	public void stringSearch_metaChars_escapedQuotes() throws Exception {
+		Object in = AList.create(A.create("'"), A.create("\""), A.create("baz"));
+		assertObjectEquals("[{f:'\\''}]", run(in, "f=\\'"));
+		assertObjectEquals("[{f:'\"'}]", run(in, "f=\\\""));
+	}
+
+	@Test
+	public void stringSearch_metaChars_falseEscape() throws Exception {
+		Object in = AList.create(A.create("foo"), A.create("bar"), A.create("baz"));
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=\\f\\o\\o"));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Number search
+	//-----------------------------------------------------------------------------------------------------------------
+
+	public static class C {
+		public int f;
+
+		static C create(int f) {
+			C c = new C();
+			c.f = f;
+			return c;
+		}
+	}
+
+	C[] INT_BEAN_ARRAY = new C[]{C.create(-2), C.create(-1), C.create(0), C.create(1), C.create(2), C.create(3)};
+
+	@Test
+	public void intSearch_oneNumber() throws Exception {
+		for (String s : a("f=1", "f = 1"))
+			assertObjectEquals("[{f:1}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_twoNumbers() throws Exception {
+		for (String s : a("f=1 2", "f = 1  2 "))
+			assertObjectEquals("[{f:1},{f:2}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_oneNegativeNumber() throws Exception {
+		for (String s : a("f=-1", "f = -1 "))
+			assertObjectEquals("[{f:-1}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_twoNegativeNumbers() throws Exception {
+		assertObjectEquals("[{f:-2},{f:-1}]", run(INT_BEAN_ARRAY, "f=-1 -2"));
+	}
+
+	@Test
+	public void intSearch_simpleRange() throws Exception {
+		for (String s : a("f=1-2", "f = 1 - 2 ", "f = 1- 2 "))
+			assertObjectEquals("[{f:1},{f:2}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_simpleRange_invalid() throws Exception {
+		assertObjectEquals("[]", run(INT_BEAN_ARRAY, "f=2-1"));
+	}
+
+	@Test
+	public void intSearch_twoNumbersThatLookLikeRange() throws Exception {
+		assertObjectEquals("[{f:-2},{f:1}]", run(INT_BEAN_ARRAY, "f = 1 -2 "));
+	}
+
+	@Test
+	public void intSearch_rangeWithNegativeNumbers() throws Exception {
+		assertObjectEquals("[{f:-2},{f:-1}]", run(INT_BEAN_ARRAY, "f = -2--1 "));
+	}
+
+	@Test
+	public void intSearch_rangeWithNegativeNumbers_invalidRange() throws Exception {
+		assertObjectEquals("[]", run(INT_BEAN_ARRAY, "f = -1--2 "));
+	}
+
+	@Test
+	public void intSearch_multipleRanges() throws Exception {
+		assertObjectEquals("[{f:0},{f:1},{f:3}]", run(INT_BEAN_ARRAY, "f = 0-1 3-4"));
+	}
+
+	@Test
+	public void intSearch_overlappingRanges() throws Exception {
+		assertObjectEquals("[{f:0},{f:2}]", run(INT_BEAN_ARRAY, "f = 0-0 2-2"));
+	}
+
+	@Test
+	public void intSearch_LT() throws Exception {
+		for (String s : a("f = <0", "f<0", "f = < 0 ", "f < 0 "))
+			assertObjectEquals("[{f:-2},{f:-1}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_LT_negativeNumber() throws Exception {
+		for (String s : a("f = <-1", "f<-1", "f = < -1 ", "f < -1 "))
+			assertObjectEquals("[{f:-2}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_GT() throws Exception {
+		for (String s : a("f = >1", "f>1", "f = > 1 ", "f > 1 "))
+			assertObjectEquals("[{f:2},{f:3}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_GT_negativeNumber() throws Exception {
+		for (String s : a("f = >-1", "f>-1", "f = > -1 ", "f > -1 ", "f =  >  -1  ", "f >  -1  "))
+			assertObjectEquals("[{f:0},{f:1},{f:2},{f:3}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_LTE() throws Exception {
+		for (String s : a("f = <=0", "f<=0", "f = <= 0 ", "f <= 0 ", "f =  <=  0  "))
+			assertObjectEquals("[{f:-2},{f:-1},{f:0}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_LTE_negativeNumber() throws Exception {
+		for (String s : a("f = <=-1", "f <=-1", "f = <= -1 ", "f =  <=  -1  ", "f <=  -1  "))
+			assertObjectEquals("[{f:-2},{f:-1}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_GTE() throws Exception {
+		for (String s : a("f = >=1", "f >=1", "f = >= 1 ", "f >= 1 ", "f =  >=  1  "))
+			assertObjectEquals("[{f:1},{f:2},{f:3}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_GTE_negativeNumber() throws Exception {
+		for (String s : a("f = >=-1", "f >=-1", "f = >= -1 ", "f >= -1 ", "f =  >=  -1  "))
+			assertObjectEquals("[{f:-1},{f:0},{f:1},{f:2},{f:3}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_not_singleNumber() throws Exception {
+		for (String s : a("f = !1", "f = ! 1 ", "f =  !  1  "))
+			assertObjectEquals("[{f:-2},{f:-1},{f:0},{f:2},{f:3}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_not_range() throws Exception {
+		assertObjectEquals("[{f:-2},{f:-1},{f:0},{f:3}]", run(INT_BEAN_ARRAY, "f = !1-2"));
+	}
+
+	@Test
+	public void intSearch_not_range_negativeNumbers() throws Exception {
+		for (String s : a("f = !-2--1", "f = ! -2 - -1", "f =  !  -2  -  -1 "))
+			assertObjectEquals("[{f:0},{f:1},{f:2},{f:3}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_not_looksLikeRange() throws Exception {
+		assertObjectEquals("[{f:-2},{f:-1},{f:0},{f:1},{f:2},{f:3}]", run(INT_BEAN_ARRAY, "f = ! -2 -2"));
+	}
+
+	@Test
+	public void intSearch_empty() throws Exception {
+		for (String s : a("f=", "f = ", "f =  "))
+			assertObjectEquals("[{f:-2},{f:-1},{f:0},{f:1},{f:2},{f:3}]", run(INT_BEAN_ARRAY, s));
+	}
+
+	@Test
+	public void intSearch_badSearches() throws Exception {
+		String[] ss = new String[] {
+			"f=x","(S01)",
+			"f=>x","(S02)",
+			"f=<x","(S03)",
+			"f=>=x","(S04)",
+			"f=>= x","(S05)",
+			"f=1x","(S06)",
+			"f=1 x","(S07)",
+			"f=1-x","(S08)",
+			"f=1 -x","(S09)",
+			"f=1 - x","(S10)",
+			"f=1 - 1x","(S11)",
+			"f=>","(ES02)",
+			"f=<","(ES03)",
+			"f=>=","(ES04)",
+			"f=123-","(ES08)",
+			"f=123 -","(ES09)",
+		};
+
+		for (int i = 0; i < ss.length; i+=2) {
+			try {
+				run(INT_BEAN_ARRAY, ss[i]);
+				fail("i=" + i);
+			} catch (PatternException e) {
+				assertTrue(e.getLocalizedMessage().contains(ss[i+1]));
+			}
+		}
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Date search
+	//-----------------------------------------------------------------------------------------------------------------
+
+	public static class B {
+		public Calendar f;
+
+		static B[] create(String...dates) {
+			B[] bb = new B[dates.length];
+			for (int i = 0; i < dates.length; i++) {
+				bb[i] = new B();
+				bb[i].f = DateUtils.parseISO8601Calendar(dates[i]);
+			}
+			return bb;
+		}
+	}
+
+	@Test
+	public void dateSearch_singleDate_y() throws Exception {
+		B[] in = B.create("2010-01-01", "2011-01-01", "2011-01-31", "2012-01-01");
+		for (String s : a(
+				"f=2011",
+				"f = 2011 ",
+				"f = '2011' ",
+				"f = \"2011\" "
+			))
+			assertObjectEquals("[{f:'2011/01/01 00:00:00'},{f:'2011/01/31 00:00:00'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_singleDate_ym() throws Exception {
+		B[] in = B.create("2010-01-01", "2011-01-01", "2011-01-31", "2012-01-01");
+		for (String s : a(
+				"f=2011-01",
+				"f = 2011-01 ",
+				"f='2011-01'",
+				"f=\"2011-01\""
+			))
+			assertObjectEquals("[{f:'2011/01/01 00:00:00'},{f:'2011/01/31 00:00:00'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_singleDate_ymd() throws Exception {
+		B[] in = B.create("2010-01-01", "2011-01-01", "2011-01-31", "2012-01-01");
+		assertObjectEquals("[{f:'2011/01/01 00:00:00'}]", run(in, "f=2011-01-01"), ws);
+	}
+
+
+	@Test
+	public void dateSearch_singleDate_ymdh() throws Exception {
+		B[] in = B.create("2011-01-01T11:15:59", "2011-01-01T12:00:00", "2011-01-01T12:59:59", "2011-01-01T13:00:00");
+		assertObjectEquals("[{f:'2011/01/01 12:00:00'},{f:'2011/01/01 12:59:59'}]", run(in, "f=2011-01-01T12"), ws);
+	}
+
+	@Test
+	public void dateSearch_singleDate_ymdhm() throws Exception {
+		B[] in = B.create("2011-01-01T12:29:59", "2011-01-01T12:30:00", "2011-01-01T12:30:59", "2011-01-01T12:31:00");
+		assertObjectEquals("[{f:'2011/01/01 12:30:00'},{f:'2011/01/01 12:30:59'}]", run(in, "f=2011-01-01T12:30"), ws);
+	}
+
+	@Test
+	public void dateSearch_singleDate_ymdhms() throws Exception {
+		B[] in = B.create("2011-01-01T12:30:29", "2011-01-01T12:30:30", "2011-01-01T12:30:31");
+		assertObjectEquals("[{f:'2011/01/01 12:30:30'}]", run(in, "f=2011-01-01T12:30:30"), ws);
+	}
+
+	@Test
+	public void dateSearch_openEndedRanges_y() throws Exception {
+		B[] in = B.create("2000-12-31", "2001-01-01");
+		for (String s : a(
+				"f>2000",
+				"f > 2000 ",
+				"f>'2000'",
+				"f > '2000' ",
+				"f>\"2000\"",
+				"f > \"2000\" ",
+				"f>=2001",
+				"f >= 2001 ",
+				"f>='2001'",
+				"f >= '2001' ",
+				"f>=\"2001\"",
+				"f >= \"2001\" "
+			))
+			assertObjectEquals("[{f:'2001/01/01 00:00:00'}]", run(in, s), ws);
+		for (String s : a(
+				"f<2001",
+				"f < 2001 ",
+				"f<'2001'",
+				"f < '2001'",
+				"f<\"2001\"",
+				"f < \"2001\" ",
+				"f<=2000",
+				"f <= 2000 ",
+				"f<='2000'",
+				"f <= '2000'",
+				"f<=\"2000\"",
+				"f <= \"2000\" "
+			))
+			assertObjectEquals("[{f:'2000/12/31 00:00:00'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_openEndedRanges_toMinute() throws Exception {
+		B[] in = B.create("2011-01-01T12:29:59", "2011-01-01T12:30:00");
+		assertObjectEquals("[{f:'2011/01/01 12:30:00'}]", run(in, "f>=2011-01-01T12:30"), ws);
+		assertObjectEquals("[{f:'2011/01/01 12:29:59'}]", run(in, "f<2011-01-01T12:30"), ws);
+	}
+
+	@Test
+	public void dateSearch_openEndedRanges_toSecond() throws Exception {
+		B[] in = B.create("2011-01-01T12:30:59", "2011-01-01T12:31:00");
+		assertObjectEquals("[{f:'2011/01/01 12:31:00'}]", run(in, "f>2011-01-01T12:30"), ws);
+		assertObjectEquals("[{f:'2011/01/01 12:30:59'}]", run(in, "f<=2011-01-01T12:30"), ws);
+	}
+
+	@Test
+	public void dateSearch_closedRanges() throws Exception {
+		B[] in = B.create("2000-12-31T23:59:59", "2001-01-01T00:00:00", "2003-06-30T23:59:59", "2003-07-01T00:00:00");
+
+		for (String s : a(
+				"f= 2001 - 2003-06-30 ",
+				"f= 2001 - 2003-06-30",
+				"f='2001'-'2003-06-30'",
+				"f= '2001' - '2003-06-30' ",
+				"f=\"2001\"-\"2003-06-30\"",
+				"f= \"2001\" - \"2003-06-30\" ",
+				"f=2001 -'2003-06-30'",
+				"f= 2001 - '2003-06-30' ",
+				"f=2001 -\"2003-06-30\"",
+				"f= 2001 - \"2003-06-30\" "
+			))
+			assertObjectEquals("[{f:'2001/01/01 00:00:00'},{f:'2003/06/30 23:59:59'}]", run(in, s), ws);
+
+		for (String s : a(
+			"f= 2001 - 2003-06-30 2000",
+			"f= 2001 - 2003-06-30 '2000'",
+			"f= 2001 - 2003-06-30 \"2000\"",
+			"f='2001'-'2003-06-30' 2000",
+			"f='2001'-'2003-06-30' '2000'",
+			"f='2001'-'2003-06-30' \"2000\"",
+			"f= '2001' - '2003-06-30'  2000",
+			"f= '2001' - '2003-06-30'  '2000'",
+			"f= '2001' - '2003-06-30'  \"2000\"",
+			"f=\"2001\"-\"2003-06-30\" 2000",
+			"f=\"2001\"-\"2003-06-30\" '2000'",
+			"f=\"2001\"-\"2003-06-30\" \"2000\"",
+			"f= \"2001\" - \"2003-06-30\"  2000",
+			"f= \"2001\" - \"2003-06-30\"  '2000'",
+			"f= \"2001\" - \"2003-06-30\"  \"2000\"",
+			"f= 2001 - '2003-06-30'  2000",
+			"f= 2001 - '2003-06-30'  '2000'",
+			"f= 2001 - '2003-06-30'  \"2000\"",
+			"f= 2001 - \"2003-06-30\"  2000",
+			"f= 2001 - \"2003-06-30\"  '2000'",
+			"f= 2001 - \"2003-06-30\"  \"2000\""
+		))
+		assertObjectEquals("[{f:'2000/12/31 23:59:59'},{f:'2001/01/01 00:00:00'},{f:'2003/06/30 23:59:59'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_or1() throws Exception {
+		B[] in = B.create("2000-12-31", "2001-01-01", "2001-12-31", "2002-01-01");
+		for (String s : a(
+				"f=2001 2003 2005",
+				"f= 2001  2003  2005 ",
+				"f='2001' '2003' '2005'",
+				"f= '2001'  '2003'  '2005' ",
+				"f=\"2001\" \"2003\" \"2005\"",
+				"f= \"2001\"  \"2003\"  \"2005\" "
+			))
+			assertObjectEquals("[{f:'2001/01/01 00:00:00'},{f:'2001/12/31 00:00:00'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_or2() throws Exception {
+		B[] in = B.create("2002-12-31", "2003-01-01", "2003-12-31", "2004-01-01");
+		for (String s : a(
+				"f=2001 2003 2005",
+				"f= 2001  2003  2005 ",
+				"f='2001' '2003' '2005'",
+				"f= '2001'  '2003'  '2005' ",
+				"f=\"2001\" \"2003\" \"2005\"",
+				"f= \"2001\"  \"2003\"  \"2005\" "
+			))
+			assertObjectEquals("[{f:'2003/01/01 00:00:00'},{f:'2003/12/31 00:00:00'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_or3() throws Exception {
+		B[] in = B.create("2004-12-31", "2005-01-01", "2005-12-31", "2006-01-01");
+		for (String s : a(
+				"f=2001 2003 2005",
+				"f= 2001  2003  2005 ",
+				"f='2001' '2003' '2005'",
+				"f= '2001'  '2003'  '2005' ",
+				"f=\"2001\" \"2003\" \"2005\"",
+				"f= \"2001\"  \"2003\"  \"2005\" "
+			))
+			assertObjectEquals("[{f:'2005/01/01 00:00:00'},{f:'2005/12/31 00:00:00'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_or_singleAndRange() throws Exception {
+		B[] in = B.create("2000-12-31", "2001-01-01", "2002-12-31", "2003-01-01");
+		for (String s : a(
+				"f=2001 >2002",
+				"f= 2001   >2002 ",
+				"f='2001' >'2002'",
+				"f= '2001'  >'2002' ",
+				"f=\"2001\" >\"2002\"",
+				"f= \"2001\"  >\"2002\" ",
+				"f=>2002 2001",
+				"f= >2002  2001 ",
+				"f=>'2002' '2001'",
+				"f= >'2002'  '2001' ",
+				"f=>\"2002\" \"2001\"",
+				"f= >\"2002\"  \"2001\" ",
+				"f=2001 >=2003",
+				"f= 2001  >=2003 ",
+				"f='2001' >='2003'",
+				"f= '2001'  >='2003' ",
+				"f=\"2001\" >=\"2003\"",
+				"f= \"2001\"  >=\"2003\" ",
+				"f=>=2003 2001",
+				"f= >=2003  2001 ",
+				"f=>='2003' '2001'",
+				"f= >='2003'  '2001' ",
+				"f=>=\"2003\" \"2001\"",
+				"f= >=\"2003\"  \"2001\" "
+			))
+			assertObjectEquals("[{f:'2001/01/01 00:00:00'},{f:'2003/01/01 00:00:00'}]", run(in, s), ws);
+		for (String s : a(
+				"f=<2001 2003",
+				"f= <2001  2003 ",
+				"f=<'2001' '2003'",
+				"f= <'2001'  '2003' ",
+				"f=<\"2001\" \"2003\"",
+				"f= <\"2001\"  \"2003\" ",
+				"f=2003 <2001",
+				"f= 2003  <2001 ",
+				"f='2003' <'2001'",
+				"f= '2003'  <'2001' ",
+				"f=\"2003\" <\"2001\"",
+				"f= \"2003\"  <\"2001\" ",
+				"f=<=2000 2003",
+				"f= <=2000  2003 ",
+				"f=<='2000' '2003'",
+				"f= <='2000'  '2003' ",
+				"f=<=\"2000\" \"2003\"",
+				"f= <=\"2000\"  \"2003\" ",
+				"f=2003 <=2000",
+				"f= 2003  <=2000 ",
+				"f='2003' <='2000'",
+				"f= '2003'  <='2000' ",
+				"f=\"2003\" <=\"2000\"",
+				"f= \"2003\"  <=\"2000\" "
+			))
+			assertObjectEquals("[{f:'2000/12/31 00:00:00'},{f:'2003/01/01 00:00:00'}]", run(in, s), ws);
+	}
+
+	@Test
+	public void dateSearch_badSearches() throws Exception {
+		B[] in = B.create("2000-12-31");
+		String[] ss = new String[] {
+			"f=X","(S01)",
+			"f=>X","(S02)",
+			"f=<X","(S03)",
+			"f=>=X","(S04)",
+			"f='1'X","(S07)",
+			"f=2000 X","(S09)",
+			"f=2000-X","(S10)",
+			"f=>","(ES02)",
+			"f=<","(ES03)",
+			"f=>=","(ES04)",
+			"f='","(ES05)",
+			"f=\"","(ES06)",
+			"f=2000-","(ES10)",
+			"f=2000-'","(ES11)",
+			"f=2000-\"","(ES12)"
+		};
+
+		for (int i = 0; i < ss.length; i+=2) {
+			try {
+				run(in, ss[i]);
+			} catch (PatternException e) {
+				assertTrue("["+e.getLocalizedMessage()+"]!=["+ss[i]+"]", e.getLocalizedMessage().contains(ss[i+1]));
+			}
+		}
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other data structures.
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void d2ListOfMaps() throws Exception {
+		List<Map<?,?>> in = AList.create(
+			AMap.create("f","foo"),
+			AMap.create("f","bar"),
+			null,
+			AMap.create(null,"qux"),
+			AMap.create("quux",null),
+			AMap.create(null,null)
+		);
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2SetOfMaps() throws Exception {
+		Set<Map<?,?>> in = ASet.create(
+			AMap.create("f","foo"),
+			AMap.create("f","bar"),
+			null,
+			AMap.create(null,"qux"),
+			AMap.create("quux",null),
+			AMap.create(null,null)
+		);
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=foo"));
+	}
+
+
+	@Test
+	public void d2ArrayOfMaps() throws Exception {
+		Map<?,?>[] in = new Map[]{
+			AMap.create("f","foo"),
+			AMap.create("f","bar"),
+			null,
+			AMap.create(null,"qux"),
+			AMap.create("quux",null),
+			AMap.create(null,null)
+		};
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2ListOfObjects() throws Exception {
+		List<Object> in = AList.create(
+			AMap.create("f","foo"),
+			AMap.create("f","bar"),
+			null,
+			AMap.create(null,"qux"),
+			AMap.create("quux",null),
+			AMap.create(null,null),
+			"xxx",
+			123
+		);
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2SetOfObjects() throws Exception {
+		Set<Object> in = ASet.create(
+			AMap.create("f","foo"),
+			AMap.create("f","bar"),
+			null,
+			AMap.create(null,"qux"),
+			AMap.create("quux",null),
+			AMap.create(null,null),
+			"xxx",
+			123
+		);
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2ArrayOfObjects() throws Exception {
+		Object[] in = new Object[]{
+			AMap.create("f","foo"),
+			AMap.create("f","bar"),
+			null,
+			AMap.create(null,"qux"),
+			AMap.create("quux",null),
+			AMap.create(null,null),
+			"xxx",
+			123
+		};
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2ListOfMapsWithLists() throws Exception {
+		List<Map<?,?>> in = AList.create(
+			AMap.create("f",AList.create("foo")),
+			AMap.create("f",AList.create("bar")),
+			null,
+			AMap.create(null,AList.create("qux")),
+			AMap.create("quux",AList.create((Object)null)),
+			AMap.create(null,AList.create((Object)null))
+		);
+		assertObjectEquals("[{f:['foo']}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2SetOfMapsWithSets() throws Exception {
+		Set<Map<?,?>> in = ASet.create(
+			AMap.create("f",ASet.create("foo")),
+			AMap.create("f",ASet.create("bar")),
+			null,
+			AMap.create(null,ASet.create("qux")),
+			AMap.create("quux",ASet.create((Object)null)),
+			AMap.create(null,ASet.create((Object)null))
+		);
+		assertObjectEquals("[{f:['foo']}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2ArrayOfMapsWithArrays() throws Exception {
+		Map<?,?>[] in = new Map[]{
+			AMap.create("f",new Object[]{"foo"}),
+			AMap.create("f",new Object[]{"bar"}),
+			null,
+			AMap.create(null,new Object[]{"qux"}),
+			AMap.create("quux",new Object[]{null}),
+			AMap.create(null,new Object[]{null})
+		};
+		assertObjectEquals("[{f:['foo']}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d2ListOfBeans() throws Exception {
+		List<A> in = AList.create(
+			A.create("foo"),
+			A.create("bar"),
+			null,
+			A.create(null)
+		);
+		assertObjectEquals("[{f:'foo'}]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3ListOfListOfMaps() throws Exception {
+		List<List<Map<?,?>>> in = AList.create(
+			AList.create(AMap.create("f","foo")),
+			AList.create(AMap.create("f","bar")),
+			AList.create((Map<?,?>)null),
+			AList.create(AMap.create(null,"qux")),
+			AList.create(AMap.create("quux",null)),
+			AList.create(AMap.create(null,null)),
+			null
+		);
+		assertObjectEquals("[[{f:'foo'}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3SetOfSetOfMaps() throws Exception {
+		Set<Set<Map<?,?>>> in = ASet.create(
+			ASet.create(AMap.create("f","foo")),
+			ASet.create(AMap.create("f","bar")),
+			ASet.create(AMap.create("f","baz")),
+			ASet.create((Map<?,?>)null),
+			ASet.create(AMap.create(null,"qux")),
+			ASet.create(AMap.create("quux",null)),
+			ASet.create(AMap.create(null,null)),
+			null
+		);
+		assertObjectEquals("[[{f:'foo'}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3ArrayOfArrayOfMaps() throws Exception {
+		Map<?,?>[][] in = new Map[][]{
+			new Map[]{AMap.create("f","foo")},
+			new Map[]{AMap.create("f","bar")},
+			new Map[]{AMap.create("f","baz")},
+			new Map[]{null},
+			new Map[]{AMap.create(null,"qux")},
+			new Map[]{AMap.create("quux",null)},
+			new Map[]{AMap.create(null,null)},
+			null
+		};
+		assertObjectEquals("[[{f:'foo'}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3ListOfListOfObjects() throws Exception {
+		List<List<Object>> in = AList.create(
+			AList.create(AMap.create("f","foo")),
+			AList.create(AMap.create("f","bar")),
+			AList.create((Object)null),
+			AList.create(AMap.create(null,"qux")),
+			AList.create(AMap.create("quux",null)),
+			AList.create(AMap.create(null,null)),
+			AList.create("xxx"),
+			AList.create(123),
+			null
+		);
+		assertObjectEquals("[[{f:'foo'}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3SetOfSetOfObjects() throws Exception {
+		Set<Set<Object>> in = ASet.create(
+			ASet.create(AMap.create("f","foo")),
+			ASet.create(AMap.create("f","bar")),
+			ASet.create((Map<?,?>)null),
+			ASet.create(AMap.create(null,"qux")),
+			ASet.create(AMap.create("quux",null)),
+			ASet.create(AMap.create(null,null)),
+			ASet.create("xxx"),
+			ASet.create(123),
+			null
+		);
+		assertObjectEquals("[[{f:'foo'}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3ArrayOfArrayOfObjects() throws Exception {
+		Object[][] in = new Object[][]{
+			new Object[]{AMap.create("f","foo")},
+			new Object[]{AMap.create("f","bar")},
+			new Object[]{null},
+			new Object[]{AMap.create(null,"qux")},
+			new Object[]{AMap.create("quux",null)},
+			new Object[]{AMap.create(null,null)},
+			new Object[]{"xxx"},
+			new Object[]{123},
+			null
+		};
+		assertObjectEquals("[[{f:'foo'}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3ListOfListOfMapsWithCollections() throws Exception {
+		List<List<Map<?,?>>> in = AList.create(
+			AList.create(AMap.create("f",AList.create("foo"))),
+			AList.create(AMap.create("f",AList.create("bar"))),
+			AList.create((Map<?,?>)null),
+			AList.create(AMap.create(null,AList.create("qux"))),
+			AList.create(AMap.create("quux",AList.create((Object)null))),
+			AList.create(AMap.create(null,AList.create((Object)null))),
+			null
+		);
+		assertObjectEquals("[[{f:['foo']}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3SetOfSetOfMapsWithCollections() throws Exception {
+		Set<Set<Map<?,?>>> in = ASet.create(
+			ASet.create(AMap.create("f",ASet.create("foo"))),
+			ASet.create(AMap.create("f",ASet.create("bar"))),
+			ASet.create((Map<?,?>)null),
+			ASet.create(AMap.create(null,ASet.create("qux"))),
+			ASet.create(AMap.create("quux",ASet.create((Object)null))),
+			ASet.create(AMap.create(null,ASet.create((Object)null))),
+			null
+		);
+		assertObjectEquals("[[{f:['foo']}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3ArrayOfArrayOfMapsWithCollections() throws Exception {
+		Map<?,?>[][] in = new Map[][]{
+			new Map[]{AMap.create("f",new Object[]{"foo"})},
+			new Map[]{AMap.create("f",new Object[]{"bar"})},
+			new Map[]{null},
+			new Map[]{AMap.create(null,new Object[]{"qux"})},
+			new Map[]{AMap.create("quux",new Object[]{null})},
+			new Map[]{AMap.create(null,new Object[]{null})},
+			null
+		};
+		assertObjectEquals("[[{f:['foo']}]]", run(in, "f=foo"));
+	}
+
+	@Test
+	public void d3ArrayOfArrayOfBeans() throws Exception {
+		A[][] in = new A[][]{
+			new A[]{A.create("foo")},
+			new A[]{A.create("bar")},
+			new A[]{null},
+			new A[]{A.create(null)},
+			null
+		};
+		assertObjectEquals("[[{f:'foo'}]]", run(in, "f=foo"));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other tests
+	//-----------------------------------------------------------------------------------------------------------------
+
+//	@Test
+//	public void noSearchArgs() {
+//		SearchArgs sa = new SearchArgs();
+//		assertObjectEquals("'foo'", run("foo", sa));
+//	}
+//
+//	@Test
+//	public void invalidSearchArgs() {
+//		for (String s : a("", "x")) {
+//			try {
+//				run("foo", s);
+//				fail();
+//			} catch (PatternException e) {
+//				assertTrue(e.getLocalizedMessage().contains("Invalid search terms"));
+//			}
+//		}
+//		SearchArgs sa = new SearchArgs();
+//		assertObjectEquals("'foo'", run("foo", sa));
+//	}
+//
+//	@Test
+//	public void not2dPojo() {
+//		assertObjectEquals("'foo'", run("foo", "x=y"));
+//	}
+//
+//	@Test
+//	public void nullInput() {
+//		assertObjectEquals("null", run(null, "x=y"));
+//	}
+//
+//	@Test
+//	public void searchArgsEmptyKey() {
+//		SearchArgs sa = new SearchArgs().append(null, "foo");
+//		assertObjectEquals("'foo'", run("foo", sa));
+//	}
+//
+//	@Test
+//	public void searchArgsEmptyValue() {
+//		SearchArgs sa = new SearchArgs().append("foo", null);
+//		assertObjectEquals("'foo'", run("foo", sa));
+//	}
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSorterTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSorterTest.java
new file mode 100644
index 0000000..c164fc3
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoSorterTest.java
@@ -0,0 +1,265 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+
+/**
+ * Tests the PojoPaginator class.
+ */
+public class PojoSorterTest {
+
+	PojoSorter p = new PojoSorter();
+	BeanSession bs = BeanContext.DEFAULT.createBeanSession();
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Null input
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void nullInput() {
+		assertNull(p.run(bs, null, null));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Arrays
+	//-----------------------------------------------------------------------------------------------------------------
+
+	public static class A {
+		public String f;
+
+		public static A create(String f) {
+			A a = new A();
+			a.f = f;
+			return a;
+		}
+	}
+
+	@Test
+	public void beanArray() {
+		Object in = new A[]{A.create("c"),A.create("a"),A.create("b"),A.create("e"),A.create("d")};
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[{f:'a'},{f:'b'},{f:'c'},{f:'d'},{f:'e'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArray_reverse() {
+		Object in = new A[]{A.create("c"),A.create("a"),A.create("b"),A.create("e"),A.create("d")};
+		SortArgs sa = new SortArgs("f-");
+		assertObjectEquals("[{f:'e'},{f:'d'},{f:'c'},{f:'b'},{f:'a'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArrayContainingNulls() {
+		Object in = new A[]{A.create("c"),A.create("a"),null,null,A.create("b")};;
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[null,null,{f:'a'},{f:'b'},{f:'c'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArrayContainingDups() {
+		Object in = new A[]{A.create("c"),A.create("a"),null,A.create("a"),A.create("b")};
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[null,{f:'a'},{f:'a'},{f:'b'},{f:'c'}]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Lists
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void beanList() {
+		Object in = AList.create(A.create("c"),A.create("a"),A.create("b"),A.create("e"),A.create("d"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[{f:'a'},{f:'b'},{f:'c'},{f:'d'},{f:'e'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanList_reverse() {
+		Object in = AList.create(A.create("c"),A.create("a"),A.create("b"),A.create("e"),A.create("d"));
+		SortArgs sa = new SortArgs("f-");
+		assertObjectEquals("[{f:'e'},{f:'d'},{f:'c'},{f:'b'},{f:'a'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanListContainingNull() {
+		Object in = AList.create(A.create("c"),A.create("a"),null,null,A.create("b"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[null,null,{f:'a'},{f:'b'},{f:'c'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanListContainingDups() {
+		Object in = AList.create(A.create("c"),A.create("a"),null,A.create("a"),A.create("b"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[null,{f:'a'},{f:'a'},{f:'b'},{f:'c'}]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Sets
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void beanSet() {
+		Object in = ASet.create(A.create("c"),A.create("a"),A.create("b"),A.create("e"),A.create("d"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[{f:'a'},{f:'b'},{f:'c'},{f:'d'},{f:'e'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void betSet_reverse() {
+		Object in = ASet.create(A.create("c"),A.create("a"),A.create("b"),A.create("e"),A.create("d"));
+		SortArgs sa = new SortArgs("f-");
+		assertObjectEquals("[{f:'e'},{f:'d'},{f:'c'},{f:'b'},{f:'a'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSetContainingNull() {
+		Object in = ASet.create(A.create("c"),A.create("a"),null,null,A.create("b"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[null,{f:'a'},{f:'b'},{f:'c'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSetContainingDups() {
+		Object in = ASet.create(A.create("c"),A.create("a"),null,A.create("a"),A.create("b"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[null,{f:'a'},{f:'a'},{f:'b'},{f:'c'}]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void emptySort() {
+		Object in = ASet.create(A.create("c"),A.create("a"),A.create("b"));
+		SortArgs sa = new SortArgs();
+		assertObjectEquals("[{f:'c'},{f:'a'},{f:'b'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void invalidDataType() {
+		Object in = AMap.create("a","b");
+		SortArgs sa = new SortArgs("x");
+		in = p.run(bs, in, sa);
+		assertObjectEquals("{a:'b'}", in);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Lists of Maps
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void listOfMaps() {
+		Object in = AList.create(AMap.create("f","c"),AMap.create("f","a"),AMap.create("f","b"),AMap.create("f","e"),AMap.create("f","d"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[{f:'a'},{f:'b'},{f:'c'},{f:'d'},{f:'e'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void listOfMaps_reverse() {
+		Object in = AList.create(AMap.create("f","c"),AMap.create("f","a"),AMap.create("f","b"),AMap.create("f","e"),AMap.create("f","d"));
+		SortArgs sa = new SortArgs("f-");
+		assertObjectEquals("[{f:'e'},{f:'d'},{f:'c'},{f:'b'},{f:'a'}]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Lists of Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void listOfOther() {
+		Object in = AList.create(AList.create("c"),AList.create("a"),AList.create("b"));
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[['c'],['a'],['b']]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void listOfOther_reverse() {
+		Object in = AList.create(AList.create("c"),AList.create("a"),AList.create("b"));
+		SortArgs sa = new SortArgs("f-");
+		assertObjectEquals("[['c'],['a'],['b']]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void nonExistentField() {
+		Object in = new A[]{A.create("c"),A.create("a"),A.create("b"),A.create("e"),A.create("d")};
+		SortArgs sa = new SortArgs("fx");
+		assertObjectEquals("[{f:'c'},{f:'a'},{f:'b'},{f:'e'},{f:'d'}]", p.run(bs, in, sa));
+	}
+
+	public static class B {
+		public Object f;
+
+		public static B create(Object f) {
+			B b = new B();
+			b.f = f;
+			return b;
+		}
+	}
+
+	// Should gracefully handle different sorting data types.
+	@Test
+	public void mixtureOfTypes() {
+		Object in = new B[]{B.create(1),B.create(true),B.create("a")};
+		SortArgs sa = new SortArgs("f");
+		assertObjectEquals("[{f:1},{f:true},{f:'a'}]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Sort by multiple columns.
+	//-----------------------------------------------------------------------------------------------------------------
+
+	public static class C {
+		public int f1;
+		public float f2;
+
+		public static C create(int f1, float f2) {
+			C c = new C();
+			c.f1 = f1;
+			c.f2 = f2;
+			return c;
+		}
+	}
+
+	@Test
+	public void sortMultipleColumns() {
+		Object in = new C[]{C.create(1,1),C.create(3,2),C.create(3,1),C.create(2,1),C.create(2,2)};
+		SortArgs sa = new SortArgs("f1","f2");
+		assertObjectEquals("[{f1:1,f2:1.0},{f1:2,f2:1.0},{f1:2,f2:2.0},{f1:3,f2:1.0},{f1:3,f2:2.0}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void sortMultipleColumns_descending() {
+		Object in = new C[]{C.create(1,1),C.create(3,2),C.create(3,1),C.create(2,1),C.create(2,2)};
+		SortArgs sa = new SortArgs("f1-","f2-");
+		assertObjectEquals("[{f1:3,f2:2.0},{f1:3,f2:1.0},{f1:2,f2:2.0},{f1:2,f2:1.0},{f1:1,f2:1.0}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void sortMultipleColumns_ascendingAndDescending() {
+		Object in = new C[]{C.create(1,1),C.create(3,2),C.create(3,1),C.create(2,1),C.create(2,2)};
+		SortArgs sa = new SortArgs("f1-","f2+");
+		assertObjectEquals("[{f1:3,f2:1.0},{f1:3,f2:2.0},{f1:2,f2:1.0},{f1:2,f2:2.0},{f1:1,f2:1.0}]", p.run(bs, in, sa));
+	}
+}
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoViewerTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoViewerTest.java
new file mode 100644
index 0000000..f4e3875
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/pojotools/PojoViewerTest.java
@@ -0,0 +1,349 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+
+/**
+ * Tests the PojoPaginator class.
+ */
+public class PojoViewerTest {
+
+	PojoViewer p = new PojoViewer();
+	BeanSession bs = BeanContext.DEFAULT.createBeanSession();
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Null input
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void nullInput() {
+		assertNull(p.run(bs, null, null));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Simple bean
+	//-----------------------------------------------------------------------------------------------------------------
+
+	public static class A {
+		public String f1,f2;
+
+		public static A create(String f1, String f2) {
+			A a = new A();
+			a.f1 = f1;
+			a.f2 = f2;
+			return a;
+		}
+	}
+
+	@Test
+	public void simpleBean() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = A.create("x1","x2");
+		assertObjectEquals("{f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleBean_reverseColumns() {
+		ViewArgs sa = new ViewArgs("f2","f1");
+		Object in = A.create("x1","x2");
+		assertObjectEquals("{f2:'x2',f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleBean_dupColumns() {
+		ViewArgs sa = new ViewArgs("f1","f1");
+		Object in = A.create("x1","x2");
+		assertObjectEquals("{f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleBean_nonExistentColumns() {
+		ViewArgs sa = new ViewArgs("fx");
+		Object in = A.create("x1","x2");
+		assertObjectEquals("{}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleBean_nullColumn() {
+		ViewArgs sa = new ViewArgs("f1",null);
+		Object in = A.create("x1","x2");
+		assertObjectEquals("{f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleBean_emptyArgs() {
+		ViewArgs sa = new ViewArgs();
+		Object in = A.create("x1","x2");
+		assertObjectEquals("{}", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Simple BeanMap
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void simpleBeanMap() {
+		ViewArgs sa = new ViewArgs("f1");
+		Object in = bs.toBeanMap(A.create("x1","x2"));
+		assertObjectEquals("{f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Simple map
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void simpleMap() {
+		ViewArgs sa = new ViewArgs("f1");
+		Object in = AMap.create().append("f1","x1").append("f2","x2");
+		assertObjectEquals("{f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleMap_reverseColumns() {
+		ViewArgs sa = new ViewArgs("f2","f1");
+		Object in = AMap.create().append("f1","x1").append("f2","x2");
+		assertObjectEquals("{f2:'x2',f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleMap_nonExistentColumns() {
+		ViewArgs sa = new ViewArgs("fx");
+		Object in = AMap.create().append("f1","x1").append("f2","x2");
+		assertObjectEquals("{}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleMap_nullColumn() {
+		ViewArgs sa = new ViewArgs("f1",null);
+		Object in = AMap.create().append("f1","x1").append("f2","x2");
+		assertObjectEquals("{f1:'x1'}", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void simpleMap_emptyView() {
+		ViewArgs sa = new ViewArgs();
+		Object in = AMap.create().append("f1","x1").append("f2","x2");
+		assertObjectEquals("{}", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean array
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void beanArray() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = new A[]{A.create("x1","x2")};
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArray_reverseColumns() {
+		ViewArgs sa = new ViewArgs("f2","f1");
+		Object in = new A[]{A.create("x1","x2")};
+		assertObjectEquals("[{f2:'x2',f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArray_dupColumns() {
+		ViewArgs sa = new ViewArgs("f1","f1");
+		Object in = new A[]{A.create("x1","x2")};
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArray_nonExistentColumns() {
+		ViewArgs sa = new ViewArgs("fx");
+		Object in = new A[]{A.create("x1","x2")};
+		assertObjectEquals("[{}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArray_nullColumn() {
+		ViewArgs sa = new ViewArgs("f1",null);
+		Object in = new A[]{A.create("x1","x2")};
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArray_emptyArgs() {
+		ViewArgs sa = new ViewArgs();
+		Object in = new A[]{A.create("x1","x2")};
+		assertObjectEquals("[{}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanArray_withNull() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = new A[]{A.create("x1","x2"),null};
+		assertObjectEquals("[{f1:'x1'},null]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean list
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void beanList() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = AList.create(A.create("x1","x2"));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanList_reverseColumns() {
+		ViewArgs sa = new ViewArgs("f2","f1");
+		Object in = AList.create(A.create("x1","x2"));
+		assertObjectEquals("[{f2:'x2',f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanList_dupColumns() {
+		ViewArgs sa = new ViewArgs("f1","f1");
+		Object in = AList.create(A.create("x1","x2"));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanList_nonExistentColumns() {
+		ViewArgs sa = new ViewArgs("fx");
+		Object in = AList.create(A.create("x1","x2"));
+		assertObjectEquals("[{}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanList_nullColumn() {
+		ViewArgs sa = new ViewArgs("f1",null);
+		Object in = AList.create(A.create("x1","x2"));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanList_emptyArgs() {
+		ViewArgs sa = new ViewArgs();
+		Object in = AList.create(A.create("x1","x2"));
+		assertObjectEquals("[{}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanList_withNull() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = AList.create(A.create("x1","x2"),null);
+		assertObjectEquals("[{f1:'x1'},null]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Bean set
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void beanSet() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = ASet.create(A.create("x1","x2"));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSet_reverseColumns() {
+		ViewArgs sa = new ViewArgs("f2","f1");
+		Object in = ASet.create(A.create("x1","x2"));
+		assertObjectEquals("[{f2:'x2',f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSet_dupColumns() {
+		ViewArgs sa = new ViewArgs("f1","f1");
+		Object in = ASet.create(A.create("x1","x2"));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSet_nonExistentColumns() {
+		ViewArgs sa = new ViewArgs("fx");
+		Object in = ASet.create(A.create("x1","x2"));
+		assertObjectEquals("[{}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSet_nullColumn() {
+		ViewArgs sa = new ViewArgs("f1",null);
+		Object in = ASet.create(A.create("x1","x2"));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSet_emptyArgs() {
+		ViewArgs sa = new ViewArgs();
+		Object in = ASet.create(A.create("x1","x2"));
+		assertObjectEquals("[{}]", p.run(bs, in, sa));
+	}
+
+	@Test
+	public void beanSet_withNull() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = ASet.create(A.create("x1","x2"),null);
+		assertObjectEquals("[{f1:'x1'},null]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other object
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void otherObject() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = "foobar";
+		assertObjectEquals("'foobar'", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Map list
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void mapList() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = AList.create(AMap.create().append("f1","x1").append("f2","x2"));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// BeanMap list
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void beanMapList() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = AList.create(bs.toBeanMap(A.create("x1","x2")));
+		assertObjectEquals("[{f1:'x1'}]", p.run(bs, in, sa));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other object list
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void otherObjectList() {
+		ViewArgs sa = new ViewArgs("f1");;
+		Object in = AList.create("foobar");
+		assertObjectEquals("['foobar']", p.run(bs, in, sa));
+	}
+
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java
index 1af9076..4b8a8b3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java
@@ -28,7 +28,7 @@ import org.apache.juneau.*;
  */
 public class DelegateBeanMap<T> extends BeanMap<T> {
 
-	private Set<String> keys = Collections.newSetFromMap(new LinkedHashMap<String,Boolean>());
+	private Set<String> keys = new LinkedHashSet<>();
 	private ObjectMap overrideValues = new ObjectMap();
 
 	/**
@@ -78,10 +78,12 @@ public class DelegateBeanMap<T> extends BeanMap<T> {
 	 * This does not affect the underlying bean.
 	 *
 	 * @param keys The remaining keys in the bean map (in the specified order).
+	 * @return This object (for method chaining).
 	 */
-	public void filterKeys(List<String> keys) {
+	public DelegateBeanMap<T> filterKeys(List<String> keys) {
 		this.keys.clear();
 		this.keys.addAll(keys);
+		return this;
 	}
 
 	@Override /* Map */
@@ -119,7 +121,7 @@ public class DelegateBeanMap<T> extends BeanMap<T> {
 			if (overrideValues.containsKey(key))
 				p = BeanPropertyMeta.builder(this.meta, key).overrideValue(overrideValues.get(key)).delegateFor(p).build();
 			if (p == null)
-				throw new BeanRuntimeException(super.getClassMeta().getInnerClass(), "Property ''{0}'' not found on class.", key);
+				p = BeanPropertyMeta.builder(this.meta, key).overrideValue(null).delegateFor(p).build();
 			l.add(p);
 		}
 		return l;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateMap.java
index 83d7440..daaf02c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateMap.java
@@ -21,7 +21,8 @@ import org.apache.juneau.*;
  *
  * @param <T> The class type of the wrapped bean.
  */
-public class DelegateMap<T> extends ObjectMap implements Delegate<T> {
+@SuppressWarnings("rawtypes")
+public class DelegateMap<T extends Map> extends ObjectMap implements Delegate<T> {
 	private static final long serialVersionUID = 1L;
 
 	private transient ClassMeta<T> classMeta;
@@ -29,10 +30,13 @@ public class DelegateMap<T> extends ObjectMap implements Delegate<T> {
 	/**
 	 * Constructor.
 	 *
-	 * @param classMeta The metadata object that created this delegate object.
+	 * @param m The metadata object that created this delegate object.
+	 * @param session
 	 */
-	public DelegateMap(ClassMeta<T> classMeta) {
-		this.classMeta = classMeta;
+	public DelegateMap(T m, BeanSession session) {
+		this.classMeta = session.getClassMetaForObject(m);
+		for (Map.Entry e : (Set<Map.Entry>)m.entrySet())
+			put(StringUtils.asString(e.getKey()), e.getValue());
 	}
 
 	@Override /* Delegate */
@@ -47,12 +51,15 @@ public class DelegateMap<T> extends ObjectMap implements Delegate<T> {
 	 * This does not affect the underlying map.
 	 *
 	 * @param keys The remaining keys in the map (in the specified order).
+	 * @return This object (for method chaining).
 	 */
-	public void filterKeys(List<String> keys) {
+	public DelegateMap<T> filterKeys(List<String> keys) {
 		ObjectMap m2 = new ObjectMap();
 		for (String k : keys)
-			m2.put(k, get(k));
+			if (containsKey(k))
+				m2.put(k, get(k));
 		this.clear();
 		this.putAll(m2);
+		return this;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
index 25f225d..aa6d54f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
@@ -350,4 +350,32 @@ public final class ObjectUtils {
 				return oo;
 		return null;
 	}
+
+	/**
+	 * Compares two objects for equality.
+	 *
+	 * <p>
+	 * Nulls are always considered less-than unless both are null.
+	 *
+	 * @param o1 Object 1.
+	 * @param o2 Object 2.
+	 * @return
+	 * 	<code>-1</code>, <code>0</code>, or <code>1</code> if <code>o1</code> is less-than, equal, or greater-than <code>o2</code>.
+	 *	<br><code>0</code> if objects are not of the same type or do not implement the {@link Comparable} interface.
+	 */
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public static int compare(Object o1, Object o2) {
+		if (o1 == null) {
+			if (o2 == null)
+				return 0;
+			return -1;
+		} else if (o2 == null) {
+			return 1;
+		}
+
+		if (o1.getClass() == o2.getClass() && o1 instanceof Comparable)
+			return ((Comparable)o1).compareTo(o2);
+
+		return 0;
+	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StateMachineState.java
similarity index 65%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StateMachineState.java
index 5231a47..9232bff 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StateMachineState.java
@@ -10,33 +10,12 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.widget;
-
-import org.apache.juneau.*;
-import org.apache.juneau.rest.*;
+package org.apache.juneau.internal;
 
 /**
- * Widget that places a powered-by-Juneau message on the page.
- *
- * <p>
- * The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets}
- * </ul>
+ * Enums for state-machine states.
  */
-public class PoweredByJuneau extends Widget {
-
-
-	/**
-	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
-	 */
-	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
-		UriResolver r = req.getUriResolver();
-		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
-	}
+@SuppressWarnings("javadoc")
+public enum StateMachineState {
+	S01, S02, S03, S04, S05, S06, S07, S08, S09, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20;
 }
-
-
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
index fa8568e..c166d25 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -772,6 +772,19 @@ public final class StringUtils {
 	 * 	<br>An empty string results in an empty array.
 	 */
 	public static String[] splitQuoted(String s) {
+		return splitQuoted(s, false);
+	}
+
+	/**
+	 * Same as {@link #splitQuoted(String)} but allows you to optionally keep the quote characters.
+	 *
+	 * @param s The input string.
+	 * @param keepQuotes If <jk>true</jk>, quote characters are kept on the tokens.
+	 * @return
+	 * 	The results, or <jk>null</jk> if the input was <jk>null</jk>.
+	 * 	<br>An empty string results in an empty array.
+	 */
+	public static String[] splitQuoted(String s, boolean keepQuotes) {
 
 		if (s == null)
 			return null;
@@ -802,10 +815,10 @@ public final class StringUtils {
 			if (state == S1) {
 				if (c == '\'') {
 					state = S2;
-					mark = i+1;
+					mark = keepQuotes ? i : i+1;
 				} else if (c == '"') {
 					state = S3;
-					mark = i+1;
+					mark = keepQuotes ? i : i+1;
 				} else if (c != ' ' && c != '\t') {
 					state = S4;
 					mark = i;
@@ -813,10 +826,10 @@ public final class StringUtils {
 			} else if (state == S2 || state == S3) {
 				if (c == '\\') {
 					isInEscape = ! isInEscape;
-					needsUnescape = true;
+					needsUnescape = ! keepQuotes;
 				} else if (! isInEscape) {
 					if (c == (state == S2 ? '\'' : '"')) {
-						String s2 = s.substring(mark, i);
+						String s2 = s.substring(mark, keepQuotes ? i+1 : i);
 						if (needsUnescape)
 							s2 = unEscapeChars(s2, QUOTE_ESCAPE_SET);
 						l.add(s2);
@@ -1285,6 +1298,18 @@ public final class StringUtils {
 	}
 
 	/**
+	 * Strips the first and last character from a string.
+	 *
+	 * @param s The string to strip.
+	 * @return The striped string, or the same string if the input was <jk>null</jk> or less than length 2.
+	 */
+	public static String strip(String s) {
+		if (s == null || s.length() <= 1)
+			return s;
+		return s.substring(1, s.length()-1);
+	}
+
+	/**
 	 * Parses an ISO8601 string into a date.
 	 *
 	 * <p>
@@ -2584,4 +2609,47 @@ public final class StringUtils {
 		}
 		return l;
 	}
+
+	/**
+	 * Replaces tokens in a string with a different token.
+	 *
+	 * <p>
+	 * replace("A and B and C", "and", "or") -> "A or B or C"
+	 * replace("andandand", "and", "or") -> "ororor"
+	 * replace(null, "and", "or") -> null
+	 * replace("andandand", null, "or") -> "andandand"
+	 * replace("andandand", "", "or") -> "andandand"
+	 * replace("A and B and C", "and", null) -> "A  B  C"
+	 *
+	 * @param s The string to replace characters in.
+	 * @param from The character to replace.
+	 * @param to The character to replace with.
+	 * @param ignoreEscapedChars Specify 'true' if escaped 'from' characters should be ignored.
+	 * @return The string with characters replaced.
+	 */
+	public static String replaceChars(String s, char from, char to, boolean ignoreEscapedChars) {
+		if (s == null)
+			return null;
+
+		if (s.indexOf(from) == -1)
+			return s;
+
+		char[] sArray = s.toCharArray();
+
+		int escapeCount = 0;
+		int singleQuoteCount = 0;
+		int doubleQuoteCount = 0;
+		for (int i = 0; i < sArray.length; i++) {
+			char c = sArray[i];
+			if (c == '\\' && ignoreEscapedChars)
+				escapeCount++;
+			else if (escapeCount % 2 == 0) {
+				if (c == from && singleQuoteCount % 2 == 0 && doubleQuoteCount % 2 == 0)
+				sArray[i] = to;
+			}
+			if (sArray[i] != '\\') escapeCount = 0;
+		}
+		return new String(sArray);
+	}
+
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Equality.java
similarity index 65%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Equality.java
index 5231a47..b567988 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Equality.java
@@ -10,33 +10,12 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.widget;
-
-import org.apache.juneau.*;
-import org.apache.juneau.rest.*;
+package org.apache.juneau.pojotools;
 
 /**
- * Widget that places a powered-by-Juneau message on the page.
- *
- * <p>
- * The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets}
- * </ul>
+ * TODO
  */
-public class PoweredByJuneau extends Widget {
-
-
-	/**
-	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
-	 */
-	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
-		UriResolver r = req.getUriResolver();
-		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
-	}
-}
-
-
+@SuppressWarnings("javadoc")
+public enum Equality {
+	GT, GTE, LT, LTE, NONE
+}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Matcher.java
similarity index 67%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Matcher.java
index 5231a47..34c125f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/Matcher.java
@@ -10,33 +10,21 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.widget;
+package org.apache.juneau.pojotools;
 
 import org.apache.juneau.*;
-import org.apache.juneau.rest.*;
 
 /**
- * Widget that places a powered-by-Juneau message on the page.
- *
- * <p>
- * The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets}
- * </ul>
+ * Common interface for matchers used by the {@link PojoSearcher} class.
  */
-public class PoweredByJuneau extends Widget {
-
+public abstract class Matcher {
 
 	/**
-	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
+	 * Returns <jk>true</jk> if this matcher matches the specified object..
+	 *
+	 * @param cm The class type of the object being matched.  Never <jk>null</jk>.
+	 * @param o The object being matched.  Never <jk>null</jk>.
+	 * @return <jk>true</jk> if the specified object matches the specified pattern.
 	 */
-	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
-		UriResolver r = req.getUriResolver();
-		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
-	}
+	public abstract boolean matches(ClassMeta<?> cm, Object o);
 }
-
-
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/MatcherFactory.java
similarity index 67%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/MatcherFactory.java
index 5231a47..511b76d 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/MatcherFactory.java
@@ -10,33 +10,28 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.widget;
+package org.apache.juneau.pojotools;
 
 import org.apache.juneau.*;
-import org.apache.juneau.rest.*;
 
 /**
- * Widget that places a powered-by-Juneau message on the page.
- *
- * <p>
- * The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets}
- * </ul>
+ * Common interface for matchers used by the {@link PojoSearcher} class.
  */
-public class PoweredByJuneau extends Widget {
+public abstract class MatcherFactory {
 
+	/**
+	 * Returns <jk>true</jk> if this matcher can be used on the specified object.
+	 *
+	 * @param cm The class type of the object being matched.  Never <jk>null</jk>.
+	 * @return <jk>true</jk> if this matcher can be used on the specified object.
+	 */
+	public abstract boolean canMatch(ClassMeta<?> cm);
 
 	/**
-	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
+	 * Instantiates a matcher for the specified pattern.
+	 *
+	 * @param pattern The pattern string.
+	 * @return A matcher for the specified pattern.
 	 */
-	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
-		UriResolver r = req.getUriResolver();
-		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
-	}
+	public abstract Matcher create(String pattern);
 }
-
-
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/NumberMatcherFactory.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/NumberMatcherFactory.java
new file mode 100644
index 0000000..0600397
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/NumberMatcherFactory.java
@@ -0,0 +1,291 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static org.apache.juneau.internal.StateMachineState.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * TODO
+ *
+ */
+public class NumberMatcherFactory extends MatcherFactory {
+
+	/**
+	 * Default reusable matcher.
+	 */
+	public static final NumberMatcherFactory DEFAULT = new NumberMatcherFactory();
+
+	@Override
+	public boolean canMatch(ClassMeta<?> cm) {
+		return cm.isNumber();
+	}
+
+	@Override
+	public Matcher create(String pattern) {
+		return new NumberMatcher(pattern);
+	}
+
+	/**
+	 * A construct representing a single search pattern.
+	 */
+	private static class NumberMatcher extends Matcher {
+		NumberRange[] numberRanges;
+		private static final AsciiSet
+			SNUM = AsciiSet.create("-0123456789."),
+			NUM = AsciiSet.create("0123456789."),
+			WS = AsciiSet.create(" \t");
+
+		public NumberMatcher(String s) {
+
+			s = s.trim();
+
+			List<NumberRange> l = new LinkedList<>();
+
+			// Possible patterns:
+			// 123, >123, <123, >=123, <=123, >-123, >=-123, 123-456, -123--456, !123, !123-456, 123 - 456 (one token), 123 -456 (two separate tokens)
+
+			// Possible states:
+			// S01 = Looking for start (WS=S01, [!]=S01, [>]=S02, [<]=S03, SNUM=S06)
+			// S02 = Found [>], looking for [=]/SNUM ([=]=S04, WS=S05, SNUM=S06)
+			// S03 = Found [<], looking for [=]/SNUM ([=]=S05, WS=S05, SNUM=S06)
+			// S04 = Found [=], looking for SNUN (WS=S05, SNUM=S06)
+			// S05 = Found [... ], looking for SNUM (SNUM=S06)
+			// S06 = Found [1], looking for [-]/WS (WS=S07, [-]=S08)
+			// S07 = Found [123 ], looking for [-]/SNUM (if -, could be 123 - 456 or 123 -456) ([-]=S09, SNUM=S07)
+			// S08 = Found [123-], looking for SNUM (Could be 123- 456 or 123-456) (SNUM=S11)
+			// S09 = Found [123 -], looking for WS/SNUM (If WS, then it's 123 - 456, otherwise 123 -456) (WS=S10, SNUM=S06)
+			// S10 = Found [123 - ], looking for SNUM (SNUM=S12)
+			// S11 = Found [123 - 4], looking for WS (WS=S01)
+
+			StateMachineState state = S01;
+			int mark = 0;
+			boolean isNot = false;
+			Equality eq = Equality.NONE;
+			Integer n1 = null, n2 = null;
+
+			int i;
+			for (i = 0; i < s.length(); i++) {
+				char c = s.charAt(i);
+				if (state == S01) {
+					if (c == '!') {
+						isNot = true;
+					} else if (WS.contains(c)) {
+						state = S01;
+					} else if (c == '>') {
+						state = S02;
+						eq = Equality.GT;
+					} else if (c == '<') {
+						state = S03;
+						eq = Equality.LT;
+					} else if (SNUM.contains(c)) {
+						state = S06;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S02) {
+					if (c == '=') {
+						state = S04;
+						eq = Equality.GTE;
+					} else if (WS.contains(c)) {
+						state = S05;
+					} else if (SNUM.contains(c)) {
+						state = S06;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S03) {
+					if (c == '=') {
+						state = S04;
+						eq = Equality.LTE;
+					} else if (WS.contains(c)) {
+						state = S05;
+					} else if (SNUM.contains(c)) {
+						state = S06;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S04) {
+					if (WS.contains(c)) {
+						state = S05;
+					} else if (SNUM.contains(c)) {
+						mark = i;
+						state = S06;
+					} else {
+						break;
+					}
+				} else if (state == S05) {
+					if (WS.contains(c)) {
+						state = S05;
+					} else if (SNUM.contains(c)) {
+						state = S06;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S06) {
+					if (NUM.contains(c)) {
+						state = S06;
+					} else if (WS.contains(c)) {
+						state = S07;
+						n1 = Integer.parseInt(s.substring(mark, i));
+					} else if (c == '-') {
+						state = S08;
+						n1 = Integer.parseInt(s.substring(mark, i));
+					} else {
+						break;
+					}
+				} else if (state == S07) {
+					if (WS.contains(c)) {
+						state = S07;
+					} else if (c == '-') {
+						state = S09;
+					} else if (SNUM.contains(c)) {
+						state = S06;
+						l.add(new NumberRange(eq, n1, isNot));
+						eq = Equality.NONE;
+						n1 = null;
+						isNot = false;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S08) {
+					if (WS.contains(c)) {
+						state = S08;
+					} else if (SNUM.contains(c)) {
+						state = S11;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S09)  {
+					if (WS.contains(c)) {
+						state = S10;
+					} else if (NUM.contains(c)) {
+						state = S06;
+						l.add(new NumberRange(eq, n1, isNot));
+						eq = Equality.NONE;
+						n1 = null;
+						isNot = false;
+						mark = i-1;
+					} else {
+						break;
+					}
+				} else if (state == S10) {
+					if (WS.contains(c)) {
+						state = S10;
+					} else if (SNUM.contains(c)) {
+						state = S11;
+						mark = i;
+					} else {
+						break;
+					}
+				} else /* (state == S11) */ {
+					if (SNUM.contains(c)) {
+						state = S11;
+					} else if (WS.contains(c)) {
+						state = S01;
+						n2 = Integer.parseInt(s.substring(mark, i));
+						l.add(new NumberRange(eq, n1, n2, isNot));
+						eq = Equality.NONE;
+						n1 = n2 = null;
+						isNot = false;
+					} else {
+						break;
+					}
+				}
+			}
+
+			if (i != s.length())
+				throw new PatternException("Invalid range pattern ({0}): {1}", state, s);
+
+			if (state == S01) {
+				// No tokens found.
+			} else if (state == S02 || state == S03 || state == S04 || state == S08 || state == S09) {
+				throw new PatternException("Invalid range pattern (E{0}): {1}", state, s);
+			} else if (state == S06) {
+				n1 = Integer.parseInt(s.substring(mark).trim());
+				l.add(new NumberRange(eq, n1, isNot));
+			} else /* (state == S11) */ {
+				n2 = Integer.parseInt(s.substring(mark).trim());
+				l.add(new NumberRange(eq, n1, n2, isNot));
+			}
+
+			numberRanges = l.toArray(new NumberRange[l.size()]);
+		}
+
+		@Override /* Matcher */
+		public boolean matches(ClassMeta<?> cm, Object o) {
+			Number n = (Number)o;
+			if (numberRanges.length == 0) return true;
+			for (int i = 0; i < numberRanges.length; i++)
+				if (numberRanges[i].matches(n))
+					return true;
+			return false;
+		}
+	}
+
+	/**
+	 * A construct representing a single search range in a single search pattern.
+	 * All possible forms of search patterns are boiled down to these number ranges.
+	 */
+	private static class NumberRange {
+		int start;
+		int end;
+		boolean isNot;
+
+		public NumberRange(Equality eq, Integer num, boolean isNot) {
+			this(eq, num, null, isNot);
+		}
+
+		public NumberRange(Equality eq, Integer start, Integer end, boolean isNot) {
+			this.isNot = isNot;
+
+			// 123, >123, <123, >=123, <=123, >-123, >=-123, 123-456, -123--456
+			if (eq == Equality.NONE && end == null) { // 123
+				this.start = start;
+				this.end = this.start;
+			} else if (eq == Equality.GT) {
+				this.start = start+1;
+				this.end = Integer.MAX_VALUE;
+			} else if (eq == Equality.GTE) {
+				this.start = start;
+				this.end = Integer.MAX_VALUE;
+			} else if (eq == Equality.LT) {
+				this.start = Integer.MIN_VALUE;
+				this.end = start-1;
+			} else if (eq == Equality.LTE) {
+				this.start = Integer.MIN_VALUE;
+				this.end = start;
+			} else {
+				this.start = start;
+				this.end = end;
+			}
+		}
+
+		public boolean matches(Number n) {
+			long i = n.longValue();
+			boolean b = (i>=start && i<=end);
+			if (isNot) b = !b;
+			return b;
+		}
+	}
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PatternException.java
similarity index 67%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PatternException.java
index 5231a47..e6bfb4e 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PatternException.java
@@ -10,33 +10,24 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.widget;
+package org.apache.juneau.pojotools;
 
 import org.apache.juneau.*;
-import org.apache.juneau.rest.*;
 
 /**
- * Widget that places a powered-by-Juneau message on the page.
- *
- * <p>
- * The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets}
- * </ul>
+ * Indicates an invalid search pattern was specified.
  */
-public class PoweredByJuneau extends Widget {
+public class PatternException extends FormattedRuntimeException {
 
+	private static final long serialVersionUID = 1L;
 
 	/**
-	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
+	 * Constructor.
+	 *
+	 * @param message Message.
+	 * @param args Message arguments.
 	 */
-	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
-		UriResolver r = req.getUriResolver();
-		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
+	public PatternException(String message, Object...args) {
+		super(message, args);
 	}
 }
-
-
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoPaginator.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoPaginator.java
new file mode 100644
index 0000000..465bcd8
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoPaginator.java
@@ -0,0 +1,71 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import org.apache.juneau.*;
+
+/**
+ * Designed to provide paging on POJOs consisting of arrays and collections.
+ *
+ * <p>
+ * Allows you to quickly return subsets of arrays and collections based on position/limit arguments.
+ */
+public final class PojoPaginator implements PojoTool<Object> {
+
+	@Override /* PojoTool */
+	public Object run(BeanSession session, Object input, Object args) {
+
+//		if (input == null)
+//			return null;
+//
+//		ClassMeta type = session.getClassMetaForObject(input);
+//
+//		if (! type.isCollectionOrArray())
+//			return input;
+//
+//		int pos = args.getPosition();
+//		int limit = args.getLimit();
+//
+//		if (type.isArray()) {
+//			int size = Array.getLength(input);
+//			int end = (limit+pos >= size) ? size : limit + pos;
+//			pos = Math.min(pos, size);
+//			ClassMeta<?> et = type.getElementType();
+// 			if (! et.isPrimitive())
+//				return copyOfRange((Object[])input, pos, end);
+//			if (et.isType(boolean.class))
+//				return copyOfRange((boolean[])input, pos, end);
+//			if (et.isType(byte.class))
+//				return copyOfRange((byte[])input, pos, end);
+//			if (et.isType(char.class))
+//				return copyOfRange((char[])input, pos, end);
+//			if (et.isType(double.class))
+//				return copyOfRange((double[])input, pos, end);
+//			if (et.isType(float.class))
+//				return copyOfRange((float[])input, pos, end);
+//			if (et.isType(int.class))
+//				return copyOfRange((int[])input, pos, end);
+//			if (et.isType(long.class))
+//				return copyOfRange((long[])input, pos, end);
+//			if (et.isType(short.class))
+//				return copyOfRange((short[])input, pos, end);
+//			return null;
+//		}
+//
+//		List l = type.isList() ? (List)input : new ArrayList((Collection)input);
+//		int end = (limit+pos >= l.size()) ? l.size() : limit + pos;
+//		pos = Math.min(pos, l.size());
+//		return l.subList(pos, end);
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSearcher.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSearcher.java
new file mode 100644
index 0000000..1abeffe
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSearcher.java
@@ -0,0 +1,185 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+
+/**
+ * Designed to provide paging on POJOs consisting of arrays and collections.
+ *
+ * <p>
+ * Allows you to quickly return subsets of arrays and collections based on position/limit arguments.
+ */
+@SuppressWarnings({"rawtypes"})
+public final class PojoSearcher implements PojoTool<SearchArgs> {
+
+	/**
+	 * Default reusable searcher.
+	 */
+	public static final PojoSearcher DEFAULT = new PojoSearcher();
+
+	final MatcherFactory[] factories;
+
+	/**
+	 * TODO
+	 *
+	 * @param factories
+	 */
+	public PojoSearcher(MatcherFactory...factories) {
+		this.factories = factories;
+	}
+
+	/**
+	 * TODO
+	 *
+	 */
+	public PojoSearcher() {
+		this(NumberMatcherFactory.DEFAULT, TimeMatcherFactory.DEFAULT, StringMatcherFactory.DEFAULT);
+	}
+
+	@Override /* PojoTool */
+	public Object run(BeanSession session, Object input, SearchArgs args) {
+
+		ClassMeta<?> type = session.getClassMetaForObject(input);
+		Map<String,String> search = args.getSearch();
+
+		if (search.isEmpty() || type == null || ! type.isCollectionOrArray())
+			return input;
+
+		List<Object> l = null;
+		RowMatcher rowMatcher = new RowMatcher(session, search);
+
+		if (type.isCollection()) {
+			Collection c = (Collection)input;
+			l = new ArrayList<>(c.size());
+			for (Object o : c) {
+				if (rowMatcher.matches(o))
+					l.add(o);
+			}
+
+		} else /* isArray */ {
+			int size = Array.getLength(input);
+			l = new ArrayList<>(size);
+			for (int i = 0; i < size; i++) {
+				Object o = Array.get(input, i);
+				if (rowMatcher.matches(o))
+					l.add(o);
+			}
+		}
+
+		return l;
+	}
+
+	//====================================================================================================
+	// MapMatcher
+	//====================================================================================================
+	/*
+	 * Matches on a Map only if all specified entry matchers match.
+	 */
+	private class RowMatcher {
+
+		Map<String,ColumnMatcher> entryMatchers = new HashMap<>();
+		BeanSession bs;
+
+		RowMatcher(BeanSession bs, Map query) {
+			this.bs = bs;
+			for (Map.Entry e : (Set<Map.Entry>)query.entrySet())
+				entryMatchers.put(asString(e.getKey()), new ColumnMatcher(bs, asString(e.getValue())));
+		}
+
+		boolean matches(Object o) {
+			if (o == null)
+				return false;
+			ClassMeta<?> cm = bs.getClassMetaForObject(o);
+			if (cm.isMapOrBean()) {
+				Map m = cm.isMap() ? (Map)o : bs.toBeanMap(o);
+				for (Map.Entry<String,ColumnMatcher> e : entryMatchers.entrySet()) {
+					String key = e.getKey();
+					Object val = null;
+					if (m instanceof BeanMap) {
+						val = ((BeanMap)m).getRaw(key);
+					} else {
+						val = m.get(key);
+					}
+					if (! e.getValue().matches(val))
+						return false;
+				}
+				return true;
+			}
+			if (cm.isCollection()) {
+				for (Object o2 : (Collection)o)
+					if (! matches(o2))
+						return false;
+				return true;
+			}
+			if (cm.isArray()) {
+				for (int i = 0; i < Array.getLength(o); i++)
+					if (! matches(Array.get(o, i)))
+						return false;
+				return true;
+			}
+			return false;
+		}
+	}
+
+	//====================================================================================================
+	// ObjectMatcher
+	//====================================================================================================
+	/*
+	 * Matcher that uses the correct matcher based on object type.
+	 * Used for objects when we can't determine the object type beforehand.
+	 */
+	private class ColumnMatcher {
+
+		String searchPattern;
+		Matcher[] matchers;
+		BeanSession bs;
+
+		ColumnMatcher(BeanSession bs, String searchPattern) {
+			this.bs = bs;
+			this.searchPattern = searchPattern;
+			this.matchers = new Matcher[factories.length];
+		}
+
+		boolean matches(Object o) {
+			ClassMeta<?> cm = bs.getClassMetaForObject(o);
+			if (cm == null)
+				return false;
+			if (cm.isCollection()) {
+				for (Object o2 : (Collection)o)
+					if (matches(o2))
+						return true;
+				return false;
+			}
+			if (cm.isArray()) {
+				for (int i = 0; i < Array.getLength(o); i++)
+					if (matches(Array.get(o, i)))
+						return true;
+				return false;
+			}
+			for (int i = 0; i < factories.length; i++) {
+				if (factories[i].canMatch(cm)) {
+					if (matchers[i] == null)
+						matchers[i] = factories[i].create(searchPattern);
+					return matchers[i].matches(cm, o);
+				}
+			}
+			return false;
+		}
+	}
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSorter.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSorter.java
new file mode 100644
index 0000000..67ac4e6
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoSorter.java
@@ -0,0 +1,110 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Sorts arrays and collections of maps and beans.
+ */
+@SuppressWarnings({"unchecked","rawtypes"})
+public final class PojoSorter implements PojoTool<SortArgs> {
+
+	@Override /* PojoTool */
+	public Object run(BeanSession session, Object input, SortArgs args) {
+		if (input == null)
+			return null;
+
+		// If sort or view isn't empty, then we need to make sure that all entries in the
+		// list are maps.
+		Map<String,Boolean> sort = args.getSort();
+
+		if (sort.isEmpty())
+			return input;
+
+		ClassMeta type = session.getClassMetaForObject(input);
+
+		if (! type.isCollectionOrArray())
+			return input;
+
+		ArrayList<SortEntry> l = null;
+
+		if (type.isArray()) {
+			int size = Array.getLength(input);
+			l = new ArrayList<>(size);
+			for (int i = 0; i < size; i++)
+				l.add(new SortEntry(session, Array.get(input, i)));
+		} else /* isCollection() */ {
+			Collection c = (Collection)input;
+			l = new ArrayList<>(c.size());
+			for (Object o : c)
+				l.add(new SortEntry(session, o));
+		}
+
+		// We reverse the list and sort last to first.
+		List<String> columns = new ArrayList<>(sort.keySet());
+		Collections.reverse(columns);
+
+		for (final String c : columns) {
+			final boolean isDesc = sort.get(c);
+			for (SortEntry se : l)
+				se.setSort(c, isDesc);
+			Collections.sort(l);
+		}
+
+		ArrayList<Object> l2 = new ArrayList<>(l.size());
+		for (SortEntry se : l)
+			l2.add(se.o);
+
+		return l2;
+	}
+
+	private static class SortEntry implements Comparable {
+		Object o;
+		ClassMeta<?> cm;
+		BeanSession bs;
+
+		Object sortVal;
+		boolean isDesc;
+
+		SortEntry(BeanSession bs, Object o) {
+			this.o = o;
+			this.bs = bs;
+			this.cm = bs.getClassMetaForObject(o);
+		}
+
+		void setSort(String sortCol, boolean isDesc) {
+			this.isDesc = isDesc;
+
+			if (cm == null)
+				sortVal = null;
+			else if (cm.isMap())
+				sortVal = ((Map)o).get(sortCol);
+			else if (cm.isBean())
+				sortVal = bs.toBeanMap(o).get(sortCol);
+			else
+				sortVal = null;
+		}
+
+		@Override
+		public int compareTo(Object o) {
+			if (isDesc)
+				return ObjectUtils.compare(((SortEntry)o).sortVal, this.sortVal);
+			return ObjectUtils.compare(this.sortVal, ((SortEntry)o).sortVal);
+		}
+	}
+}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoTool.java
similarity index 67%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoTool.java
index 5231a47..ead70f8 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoTool.java
@@ -10,33 +10,24 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.widget;
+package org.apache.juneau.pojotools;
 
 import org.apache.juneau.*;
-import org.apache.juneau.rest.*;
 
 /**
- * Widget that places a powered-by-Juneau message on the page.
+ * Interface for classes that convert POJOs in some way using some predefined arguments object.
  *
- * <p>
- * The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets}
- * </ul>
+ * @param <T> The argument object type.
  */
-public class PoweredByJuneau extends Widget {
-
+public interface PojoTool<T> {
 
 	/**
-	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
+	 * Converts the specified input to some other output.
+	 *
+	 * @param session The current bean session.
+	 * @param input The input POJO.
+	 * @param args The arguments.
+	 * @return The output POJO.
 	 */
-	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
-		UriResolver r = req.getUriResolver();
-		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
-	}
+	public Object run(BeanSession session, Object input, T args);
 }
-
-
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoViewer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoViewer.java
new file mode 100644
index 0000000..b2bd530
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/PojoViewer.java
@@ -0,0 +1,80 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Designed to provide paging on POJOs consisting of arrays and collections.
+ *
+ * <p>
+ * Allows you to quickly return subsets of arrays and collections based on position/limit arguments.
+ */
+@SuppressWarnings({"unchecked","rawtypes"})
+public final class PojoViewer implements PojoTool<ViewArgs> {
+
+	@Override /* PojoTool */
+	public Object run(BeanSession session, Object input, ViewArgs args) {
+
+		if (input == null)
+			return null;
+
+		List<String> view = args.getView();
+		ClassMeta type = session.getClassMetaForObject(input);
+
+		if (type.isBeanMap())
+			return new DelegateBeanMap(((BeanMap)input).getBean(), session).filterKeys(view);
+		if (type.isMap())
+			return new DelegateMap((Map)input, session).filterKeys(view);
+		if (type.isBean())
+			return new DelegateBeanMap(input, session).filterKeys(view);
+
+		ArrayList<Object> l = null;
+
+		if (type.isArray()) {
+			int size = Array.getLength(input);
+			l = new ArrayList<>(size);
+			for (int i = 0; i < size; i++)
+				l.add(Array.get(input, i));
+		} else if (type.isCollection()) {
+			Collection c = (Collection)input;
+			l = new ArrayList<>(c.size());
+			for (Object o : c)
+				l.add(o);
+		} else {
+			return input;
+		}
+
+		for (ListIterator li = l.listIterator(); li.hasNext();) {
+			Object o = li.next();
+			ClassMeta cm2 = session.getClassMetaForObject(o);
+
+			if (cm2 == null)
+				o = null;
+			else if (cm2.isBeanMap())
+				o = new DelegateBeanMap(((BeanMap)o).getBean(), session).filterKeys(view);
+			else if (cm2.isMap())
+				o = new DelegateMap((Map)o, session).filterKeys(view);
+			else if (cm2.isBean())
+				o = new DelegateBeanMap(o, session).filterKeys(view);
+
+			li.set(o);
+		}
+
+		return l;
+	}
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ASet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/SearchArgs.java
similarity index 55%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ASet.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/SearchArgs.java
index 4d8c46d..54fc752 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ASet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/SearchArgs.java
@@ -10,69 +10,68 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.utils;
+package org.apache.juneau.pojotools;
 
 import java.util.*;
 
+import org.apache.juneau.internal.*;
+
 /**
- * An extension of {@link LinkedHashSet} with a convenience {@link #append(Object)} method.
- *
- * <p>
- * Primarily used for testing purposes for quickly creating populated sets.
- * <p class='bcode w800'>
- * 	<jc>// Example:</jc>
- * 	Set&lt;String&gt; s = <jk>new</jk> ASet&lt;String&gt;().append(<js>"foo"</js>).append(<js>"bar"</js>);
- * </p>
- *
- * @param <T> The entry type.
+ * Encapsulates arguments for the {@link PojoSorter} class.
  */
-@SuppressWarnings({"unchecked"})
-public final class ASet<T> extends LinkedHashSet<T> {
+public class SearchArgs {
+
+	private final Map<String,String> search = new LinkedHashMap<>();
 
-	private static final long serialVersionUID = 1L;
 
 	/**
-	 * Convenience method for creating a list of objects.
+	 * Constructor.
 	 *
-	 * @param t The initial values.
-	 * @return A new list.
+	 * @param searchArgs Search arguments.
 	 */
-	public static <T> ASet<T> create(T...t) {
-		return new ASet<T>().appendAll(t);
+	public SearchArgs(String searchArgs) {
+		this(Arrays.asList(StringUtils.split(searchArgs, ',')));
 	}
 
 	/**
-	 * Adds an entry to this set.
+	 * Constructor.
 	 *
-	 * @param t The entry to add to this set.
-	 * @return This object (for method chaining).
+	 * @param searchArgs Search arguments.
 	 */
-	public ASet<T> append(T t) {
-		add(t);
-		return this;
+	public SearchArgs(List<String> searchArgs) {
+		for (String s : searchArgs) {
+			int i = StringUtils.indexOf(s, '=', '>', '<');
+			if (i == -1)
+				throw new PatternException("Invalid search terms: ''{0}''", searchArgs);
+			char c = s.charAt(i);
+			append(s.substring(0, i).trim(), s.substring(c == '=' ? i+1 : i).trim());
+		}
 	}
 
 	/**
-	 * Adds multiple entries to this set.
+	 * Appends the specified search argument.
 	 *
-	 * @param t The entries to add to this set.
+	 * @param column The column name to search.
+	 * @param searchTerm The search term.
 	 * @return This object (for method chaining).
 	 */
-	public ASet<T> appendAll(T...t) {
-		addAll(Arrays.asList(t));
+	public SearchArgs append(String column, String searchTerm) {
+		this.search.put(column, searchTerm);
 		return this;
 	}
 
 	/**
-	 * Adds a value to this set if the boolean value is <jk>true</jk>
+	 * The query search terms.
 	 *
-	 * @param b The boolean value.
-	 * @param t The value to add.
-	 * @return This object (for method chaining).
+	 * <p>
+	 * The search terms are key/value pairs consisting of column-names and search tokens.
+	 *
+	 * <p>
+	 * It's up to implementers to decide the syntax and meaning of the search term.
+	 *
+	 * @return An unmodifiable map of query search terms.
 	 */
-	public ASet<T> appendIf(boolean b, T t) {
-		if (b)
-			append(t);
-		return this;
+	public Map<String,String> getSearch() {
+		return search;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/SortArgs.java
similarity index 51%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateMap.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/SortArgs.java
index 83d7440..45d9652 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/DelegateMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/SortArgs.java
@@ -1,58 +1,80 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.internal;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-
-/**
- * Represents a wrapped {@link Map} where entries in the map can be removed without affecting the underlying map.
- *
- * @param <T> The class type of the wrapped bean.
- */
-public class DelegateMap<T> extends ObjectMap implements Delegate<T> {
-	private static final long serialVersionUID = 1L;
-
-	private transient ClassMeta<T> classMeta;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param classMeta The metadata object that created this delegate object.
-	 */
-	public DelegateMap(ClassMeta<T> classMeta) {
-		this.classMeta = classMeta;
-	}
-
-	@Override /* Delegate */
-	public ClassMeta<T> getClassMeta() {
-		return classMeta;
-	}
-
-	/**
-	 * Remove all but the specified keys from this map.
-	 *
-	 * <p>
-	 * This does not affect the underlying map.
-	 *
-	 * @param keys The remaining keys in the map (in the specified order).
-	 */
-	public void filterKeys(List<String> keys) {
-		ObjectMap m2 = new ObjectMap();
-		for (String k : keys)
-			m2.put(k, get(k));
-		this.clear();
-		this.putAll(m2);
-	}
-}
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static java.util.Collections.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.util.*;
+
+/**
+ * Encapsulates arguments for the {@link PojoSorter} class.
+ */
+public class SortArgs {
+
+	private final Map<String,Boolean> sort;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param sortArgs
+	 * 	Sort arguments.
+	 * 	<br>Values are of the following forms:
+	 * 	<ul>
+	 * 		<li><js>"column"</js> - Sort column ascending.
+	 * 		<li><js>"column+"</js> - Sort column ascending.
+	 * 		<li><js>"column-"</js> - Sort column descending.
+	 * 	</ul>
+	 */
+	public SortArgs(String...sortArgs) {
+		this(Arrays.asList(sortArgs));
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param sortArgs
+	 * 	Sort arguments.
+	 * 	<br>Values are of the following forms:
+	 * 	<ul>
+	 * 		<li><js>"column"</js> - Sort column ascending.
+	 * 		<li><js>"column+"</js> - Sort column ascending.
+	 * 		<li><js>"column-"</js> - Sort column descending.
+	 * 	</ul>
+	 */
+	public SortArgs(Collection<String> sortArgs) {
+		Map<String,Boolean> sort = new LinkedHashMap<>();
+		for (String s : sortArgs) {
+			boolean isDesc = false;
+			if (endsWith(s, '-', '+')) {
+				isDesc = endsWith(s, '-');
+				s = s.substring(0, s.length()-1);
+			}
+			sort.put(s, isDesc);
+		}
+		this.sort = unmodifiableMap(sort);
+	}
+
+	/**
+	 * The sort columns.
+	 *
+	 * <p>
+	 * The sort columns are key/value pairs consisting of column-names and direction flags
+	 * (<jk>false</jk> = ascending, <jk>true</jk> = descending).
+	 *
+	 * @return An unmodifiable ordered map of sort columns and directions.
+	 */
+	public Map<String,Boolean> getSort() {
+		return sort;
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/StringMatcherFactory.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/StringMatcherFactory.java
new file mode 100644
index 0000000..2e63d6f
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/StringMatcherFactory.java
@@ -0,0 +1,145 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.util.*;
+import java.util.regex.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * TODO
+ *
+ */
+public class StringMatcherFactory extends MatcherFactory {
+
+	/**
+	 * Default reusable matcher.
+	 */
+	public static final StringMatcherFactory DEFAULT = new StringMatcherFactory();
+
+	@Override
+	public boolean canMatch(ClassMeta<?> cm) {
+		return true;
+	}
+
+	@Override
+	public Matcher create(String pattern) {
+		return new StringMatcher(pattern);
+	}
+
+	/**
+	 * A construct representing a single search pattern.
+	 */
+	private static class StringMatcher extends Matcher {
+		private static final AsciiSet
+			META_CHARS = AsciiSet.create("*?'\""),
+			SQ_CHAR = AsciiSet.create("'"),
+			DQ_CHAR = AsciiSet.create("\""),
+			REGEX_CHARS = AsciiSet.create("+\\[]{}()^$.");
+
+		Pattern[] orPatterns, andPatterns, notPatterns;
+
+		public StringMatcher(String searchPattern) {
+
+			List<Pattern> ors = new LinkedList<>();
+			List<Pattern> ands = new LinkedList<>();
+			List<Pattern> nots = new LinkedList<>();
+
+			for (String s : splitQuoted(searchPattern, true)) {
+				char c0 = s.charAt(0), c9 = s.charAt(s.length()-1);
+
+				if (c0 == '/' && c9 == '/' && s.length() > 1) {
+					ands.add(Pattern.compile(strip(s)));
+				} else {
+					char prefix = '^';
+					boolean ignoreCase = false;
+					if (s.length() > 1 && (c0 == '^' || c0 == '+' || c0 == '-')) {
+						prefix = c0;
+						s = s.substring(1);
+						c0 = s.charAt(0);
+					}
+
+					if (c0 == '\'') {
+						s = unEscapeChars(strip(s), SQ_CHAR);
+						ignoreCase = true;
+					} else if (c0 == '"') {
+						s = unEscapeChars(strip(s), DQ_CHAR);
+					}
+
+					if (REGEX_CHARS.contains(s) || META_CHARS.contains(s)) {
+						StringBuilder sb = new StringBuilder();
+						boolean isInEscape = false;
+						for (int i = 0; i < s.length(); i++) {
+							char c = s.charAt(i);
+							if (isInEscape) {
+								if (c == '?' || c == '*' || c == '\\')
+									sb.append('\\').append(c);
+								else
+									sb.append(c);
+								isInEscape = false;
+							} else {
+								if (c == '\\')
+									isInEscape = true;
+								else if (c == '?')
+									sb.append(".?");
+								else if (c == '*')
+									sb.append(".*");
+								else if (REGEX_CHARS.contains(c))
+									sb.append("\\").append(c);
+								else
+									sb.append(c);
+							}
+						}
+						s = sb.toString();
+					}
+
+
+					int flags = Pattern.DOTALL;
+					if (ignoreCase)
+						flags |= Pattern.CASE_INSENSITIVE;
+
+					Pattern p = Pattern.compile(s, flags);
+
+					if (prefix == '-')
+						nots.add(p);
+					else if (prefix == '+')
+						ands.add(p);
+					else
+						ors.add(p);
+				}
+			}
+			orPatterns = ors.toArray(new Pattern[ors.size()]);
+			andPatterns = ands.toArray(new Pattern[ands.size()]);
+			notPatterns = nots.toArray(new Pattern[nots.size()]);
+		}
+
+		@Override
+		public boolean matches(ClassMeta<?> cm, Object o) {
+			String s = (String)o;
+			for (int i = 0; i < andPatterns.length; i++)
+				if (! andPatterns[i].matcher(s).matches())
+					return false;
+			for (int i = 0; i < notPatterns.length; i++)
+				if (notPatterns[i].matcher(s).matches())
+					return false;
+			for (int i = 0; i < orPatterns.length; i++)
+				if (orPatterns[i].matcher(s).matches())
+					return true;
+			return orPatterns.length == 0;
+		}
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java
new file mode 100644
index 0000000..b27ea5b
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java
@@ -0,0 +1,463 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.pojotools;
+
+import static java.util.Calendar.*;
+import static org.apache.juneau.internal.StateMachineState.*;
+
+import java.text.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * TODO
+ */
+public class TimeMatcherFactory extends MatcherFactory {
+
+	/**
+	 * Default reusable matcher.
+	 */
+	public static final TimeMatcherFactory DEFAULT = new TimeMatcherFactory();
+
+	private final SimpleDateFormat[] formats;
+
+	/**
+	 * Constructor.
+	 */
+	protected TimeMatcherFactory() {
+		this.formats = getTimestampFormats();
+	}
+
+	/**
+	 * TODO
+	 *
+	 * @return TODO
+	 */
+	protected SimpleDateFormat[] getTimestampFormats() {
+		String[] s = getTimestampFormatStrings();
+		SimpleDateFormat[] a = new SimpleDateFormat[s.length];
+		for (int i = 0; i < s.length; i++)
+			a[i] = new SimpleDateFormat(s[i]);
+		return a;
+	}
+
+	/**
+	 * TODO
+	 *
+	 * @return TODO
+	 */
+	protected String[] getTimestampFormatStrings() {
+		return new String[]{
+			"yyyy-MM-dd'T'HH:mm:ss",
+			"yyyy-MM-dd'T'HH:mm",
+			"yyyy-MM-dd'T'HH",
+			"yyyy-MM-dd",
+			"yyyy-MM",
+			"yyyy"
+		};
+	}
+
+	@Override
+	public boolean canMatch(ClassMeta<?> cm) {
+		return cm.isDateOrCalendar();
+	}
+
+	@Override
+	public Matcher create(String pattern) {
+		return new TimeMatcher(formats, pattern);
+	}
+
+	/**
+	 * A construct representing a single search pattern.
+	 */
+	private static class TimeMatcher extends Matcher {
+
+		private static final AsciiSet
+			DT = AsciiSet.create("0123456789-:T./"),
+			WS = AsciiSet.create(" \t");
+
+		TimestampRange[] ranges;
+		List<TimestampRange> l = new LinkedList<>();
+
+		public TimeMatcher(SimpleDateFormat[] f, String s) {
+
+			// Possible patterns:
+			// >2000, <2000, >=2000, <=2000, > 2000, 2000 - 2001, '2000', >'2000', '2000'-'2001', '2000' - '2001'
+
+			// Possible states:
+			// S01 = Looking for [<]/[>]/quote/NUM ([>]=S02, [<]=S03, [']=S05, ["]=S06, NUM=S08)
+			// S02 = Found [>], looking for [=]/quote/NUM ([=]=S04, [']=S05, ["]=S06, NUM=S08)
+			// S03 = Found [<], looking for [=]/quote/NUM ([=]=S04, [']=S05, ["]=S06, NUM=S08)
+			// S04 = Found [>=] or [<=], looking for quote/NUM ([']=S05, ["]=S06, NUM=S08)
+			// S05 = Found ['], looking for ['] ([']=S01)
+			// S06 = Found ["], looking for ["] (["]=S01)
+			// S07 = Found [123"] or [123'], looking for WS (WS=S09)
+			// S08 = Found [2], looking for WS (WS=S09)
+			// S09 = Found [2000 ], looking for [-]/quote/NUM ([-]=S10, [']=S11, ["]=S12, NUM=S13)
+			// S10 = Found [2000 -], looking for quote/NUM ([']=S11, ["]=S12, NUM=S13)
+			// S11 = Found [2000 - '], looking for ['] ([']=S01)
+			// S12 = Found [2000 - "], looking for ["] (["]=S01)
+			// S13 = Found [2000 - 2], looking for WS (WS=S01)
+
+			StateMachineState state = S01;
+			int mark = 0;
+			Equality eq = Equality.NONE;
+			String s1 = null, s2 = null;
+
+			int i;
+			char c = 0;
+			for (i = 0; i < s.trim().length(); i++) {
+				c = s.charAt(i);
+				if (state == S01) {
+					// S01 = Looking for [>]/[<]/quote/NUM ([>]=S02, [<]=S03, [']=S05, ["]=S06, NUM=S08)
+					if (WS.contains(c)) {
+						state = S01;
+					} else if (c == '>') {
+						state = S02;
+						eq = Equality.GT;
+					} else if (c == '<') {
+						state = S03;
+						eq = Equality.LT;
+					} else if (c == '\'') {
+						state = S05;
+						mark = i+1;
+					} else if (c == '"') {
+						state = S06;
+						mark = i+1;
+					} else if (DT.contains(c)) {
+						state = S08;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S02) {
+					// S02 = Found [>], looking for [=]/quote/NUM ([=]=S04, [']=S05, ["]=S06, NUM=S08)
+					if (WS.contains(c)) {
+						state = S02;
+					} else if (c == '=') {
+						state = S04;
+						eq = Equality.GTE;
+					} else if (c == '\'') {
+						state = S05;
+						mark = i+1;
+					} else if (c == '"') {
+						state = S06;
+						mark = i+1;
+					} else if (DT.contains(c)) {
+						state = S08;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S03) {
+					// S03 = Found [<], looking for [=]/quote/NUM ([=]=S04, [']=S05, ["]=S06, NUM=S08)
+					if (WS.contains(c)) {
+						state = S03;
+					} else if (c == '=') {
+						state = S04;
+						eq = Equality.LTE;
+					} else if (c == '\'') {
+						state = S05;
+						mark = i+1;
+					} else if (c == '"') {
+						state = S06;
+						mark = i+1;
+					} else if (DT.contains(c)) {
+						state = S08;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S04) {
+					// S04 = Found [>=] or [<=], looking for quote/NUM ([']=S05, ["]=S06, NUM=S08)
+					if (WS.contains(c)) {
+						state = S04;
+					} else if (c == '\'') {
+						state = S05;
+						mark = i+1;
+					} else if (c == '"') {
+						state = S06;
+						mark = i+1;
+					} else if (DT.contains(c)) {
+						state = S08;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S05) {
+					// S05 = Found ['], looking for ['] ([']=S07)
+					if (c == '\'') {
+						state = S07;
+						s1 = s.substring(mark, i);
+					}
+				} else if (state == S06) {
+					// S06 = Found ["], looking for ["] (["]=S07)
+					if (c == '"') {
+						state = S07;
+						s1 = s.substring(mark, i);
+					}
+				} else if (state == S07) {
+					// S07 = Found [123"] or [123'], looking for WS (WS=S09)
+					if (WS.contains(c)) {
+						state = S09;
+					} else if (c == '-') {
+						state = S10;
+					} else {
+						break;
+					}
+				} else if (state == S08) {
+					// S08 = Found [1], looking for WS (WS=S09)
+					if (WS.contains(c)) {
+						state = S09;
+						s1 = s.substring(mark, i);
+					}
+				} else if (state == S09) {
+					// S09 = Found [2000 ], looking for [-]/[>]/[<]/quote/NUM ([-]=S10, [>]=S02, [<]=S03, [']=S05, ["]=S06, NUM=S08)
+					if (WS.contains(c)) {
+						state = S09;
+					} else if (c == '-') {
+						state = S10;
+					} else if (c == '>') {
+						state = S02;
+						l.add(new TimestampRange(f, eq, s1));
+						eq = Equality.GT;
+						s1 = null;
+					} else if (c == '<') {
+						state = S03;
+						l.add(new TimestampRange(f, eq, s1));
+						eq = Equality.LT;
+						s1 = null;
+					} else if (c == '\'') {
+						state = S05;
+						l.add(new TimestampRange(f, eq, s1));
+						mark = i+1;
+						eq = null;
+						s1 = null;
+					} else if (c == '"') {
+						state = S06;
+						l.add(new TimestampRange(f, eq, s1));
+						mark = i+1;
+						eq = null;
+						s1 = null;
+					} else if (DT.contains(c)) {
+						state = S08;
+						l.add(new TimestampRange(f, eq, s1));
+						eq = null;
+						s1 = null;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S10) {
+					// S10 = Found [2000 -], looking for quote/NUM ([']=S11, ["]=S12, NUM=S13)
+					if (WS.contains(c)) {
+						state = S10;
+					} else if (c == '\'') {
+						state = S11;
+						mark = i+1;
+					} else if (c == '"') {
+						state = S12;
+						mark = i+1;
+					} else if (DT.contains(c)) {
+						state = S13;
+						mark = i;
+					} else {
+						break;
+					}
+				} else if (state == S11) {
+					// S11 = Found [2000 - '], looking for ['] ([']=S01)
+					if (c == '\'') {
+						state = S01;
+						s2 = s.substring(mark, i);
+						l.add(new TimestampRange(f, s1, s2));
+						s1 = null;
+						s2 = null;
+					}
+				} else if (state == S12) {
+					// S12 = Found [2000 - "], looking for ["] (["]=S01)
+					if (c == '"') {
+						state = S01;
+						s2 = s.substring(mark, i);
+						l.add(new TimestampRange(f, s1, s2));
+						s1 = null;
+						s2 = null;
+					}
+				} else /* (state == S13) */ {
+					// S13 = Found [2000 - 2], looking for WS (WS=S01)
+					if (WS.contains(c)) {
+						state = S01;
+						s2 = s.substring(mark, i);
+						l.add(new TimestampRange(f, s1, s2));
+						s1 = null;
+						s2 = null;
+					}
+				}
+			}
+
+			if (i != s.length())
+				throw new PatternException("Invalid range pattern ({0}): pattern=[{1}], pos=[{2}], char=[{3}]", state, s, i, c);
+
+			if (state == S01) {
+				// No tokens found.
+			} else if (state == S02 || state == S03 || state == S04 || state == S05 || state == S06 || state == S10 || state == S11 || state == S12) {
+				System.err.println("state=["+state+"]");
+				throw new PatternException("Invalid range pattern (E{0}): {1}", state, s);
+			} else if (state == S07) {
+				l.add(new TimestampRange(f, eq, s1));
+			} else if (state == S08) {
+				s1 = s.substring(mark).trim();
+				l.add(new TimestampRange(f, eq, s1));
+			} else /* (state == S13) */ {
+				s2 = s.substring(mark).trim();
+				l.add(new TimestampRange(f, s1, s2));
+			}
+
+			ranges = l.toArray(new TimestampRange[l.size()]);
+		}
+
+		@Override
+		public boolean matches(ClassMeta<?> cm, Object o) {
+			if (ranges.length == 0) return true;
+
+			Calendar c = null;
+			if (cm.isCalendar())
+				c = (Calendar)o;
+			else {
+				c = Calendar.getInstance();
+				c.setTime((Date)o);
+			}
+			for (int i = 0; i < ranges.length; i++)
+				if (ranges[i].matches(c))
+					return true;
+			return false;
+		}
+	}
+
+	/**
+	 * A construct representing a single search range in a single search pattern.
+	 * All possible forms of search patterns are boiled down to these timestamp ranges.
+	 */
+	private static class TimestampRange {
+		Calendar start;
+		Calendar end;
+
+		public TimestampRange(SimpleDateFormat[] formats, String start, String end) {
+			CalendarP start1 = parseDate(formats, start);
+			CalendarP end1 = parseDate(formats, end);
+			this.start = start1.copy().roll(MILLISECOND, -1).getCalendar();
+			this.end = end1.roll(1).getCalendar();
+		}
+
+		public TimestampRange(SimpleDateFormat[] formats, Equality eq, String singleDate) {
+			System.err.println("eq=["+eq+"], singleDate=["+singleDate+"]");
+
+			CalendarP singleDate1 = parseDate(formats, singleDate);
+			if (eq == Equality.GT) {
+				this.start = singleDate1.roll(1).roll(MILLISECOND, -1).getCalendar();
+				this.end = new CalendarP(new Date(Long.MAX_VALUE), 0).getCalendar();
+			} else if (eq == Equality.LT) {
+				this.start = new CalendarP(new Date(0), 0).getCalendar();
+				this.end = singleDate1.getCalendar();
+			} else if (eq == Equality.GTE) {
+				this.start = singleDate1.roll(MILLISECOND, -1).getCalendar();
+				this.end = new CalendarP(new Date(Long.MAX_VALUE), 0).getCalendar();
+			} else if (eq == Equality.LTE) {
+				this.start = new CalendarP(new Date(0), 0).getCalendar();
+				this.end = singleDate1.roll(1).getCalendar();
+			} else {
+				this.start = singleDate1.copy().roll(MILLISECOND, -1).getCalendar();
+				this.end = singleDate1.roll(1).getCalendar();
+			}
+		}
+
+		public boolean matches(Calendar c) {
+			boolean b = (c.after(start) && c.before(end));
+			return b;
+		}
+	}
+
+	private static int getPrecisionField(String pattern) {
+		if (pattern.indexOf('s') != -1)
+			return SECOND;
+		if (pattern.indexOf('m') != -1)
+			return MINUTE;
+		if (pattern.indexOf('H') != -1)
+			return HOUR_OF_DAY;
+		if (pattern.indexOf('d') != -1)
+			return DAY_OF_MONTH;
+		if (pattern.indexOf('M') != -1)
+			return MONTH;
+		if (pattern.indexOf('y') != -1)
+			return YEAR;
+		return Calendar.MILLISECOND;
+	}
+
+	/**
+	 * Parses a timestamp string off the beginning of the string segment 'seg'.
+	 * Goes through each possible valid timestamp format until it finds a match.
+	 * The position where the parsing left off is stored in pp.
+	 *
+	 * @param seg The string segment being parsed.
+	 * @param pp Where parsing last left off.
+	 * @return An object representing a timestamp.
+	 */
+	static CalendarP parseDate(SimpleDateFormat[] formats, String seg) {
+		ParsePosition pp = new ParsePosition(0);
+		for (int i = 0; i < formats.length; i++) {
+			SimpleDateFormat f = formats[i];
+			Date d = f.parse(seg, pp);
+			int idx = pp.getIndex();
+			if (idx != 0) {
+				// it only counts if the next character is '-', 'space', or end-of-string.
+				char c = (seg.length() == idx ? 0 : seg.charAt(idx));
+				if (c == 0 || c == '-' || Character.isWhitespace(c))
+					return new CalendarP(d, getPrecisionField(f.toPattern()));
+			}
+		}
+
+		throw new FormattedRuntimeException("Invalid date encountered:  ''{0}''", seg);
+	}
+
+	/**
+	 * Combines a Calendar with a precision identifier.
+	 */
+	private static class CalendarP {
+		public Calendar c;
+		public int precision;
+
+		public CalendarP(Date date, int precision) {
+			c = Calendar.getInstance();
+			c.setTime(date);
+			this.precision = precision;
+		}
+
+		public CalendarP copy() {
+			return new CalendarP(c.getTime(), precision);
+		}
+
+		public CalendarP roll(int field, int amount) {
+			c.add(field, amount);
+			return this;
+		}
+
+		public CalendarP roll(int amount) {
+			return roll(precision, amount);
+		}
+
+		public Calendar getCalendar() {
+			return c;
+		}
+	}
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/ViewArgs.java
similarity index 64%
copy from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/ViewArgs.java
index f01d403..6061465 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/ViewArgs.java
@@ -10,40 +10,51 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.widget;
+package org.apache.juneau.pojotools;
 
-import org.apache.juneau.rest.*;
+import static java.util.Collections.*;
+
+import java.util.*;
 
 /**
- * Widget that returns a menu-item drop-down form for entering search/view/sort arguments.
- *
- * <p>
- * The variable it resolves is <js>"$W{QueryMenuItem}"</js>.
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'>{@doc juneau-rest-server.HtmlDocAnnotation.PredefinedWidgets}
- * </ul>
+ * Encapsulates arguments for the {@link PojoViewer} class.
  */
-public class QueryMenuItem extends MenuItemWidget {
+public class ViewArgs {
+
+	private final List<String> view;
 
 	/**
-	 * Returns CSS for the tooltips.
+	 * Constructor.
+	 *
+	 * @param viewArgs
+	 * 	View arguments.
+	 * 	<br>Values are column names.
 	 */
-	@Override
-	public String getStyle(RestRequest req) throws Exception {
-		return super.getStyle(req)
-			+ "\n"
-			+ loadStyle("QueryMenuItem.css");
+	public ViewArgs(String...viewArgs) {
+		this(Arrays.asList(viewArgs));
 	}
 
-	@Override /* MenuItemWidget */
-	public String getLabel(RestRequest req) throws Exception {
-		return "query";
+	/**
+	 * Constructor.
+	 *
+	 * @param viewArgs
+	 * 	View arguments.
+	 * 	<br>Values are column names.
+	 */
+	public ViewArgs(Collection<String> viewArgs) {
+		this.view = unmodifiableList(new ArrayList<>(viewArgs));
 	}
 
-	@Override /* MenuItemWidget */
-	public String getContent(RestRequest req) throws Exception {
-		return loadHtml("QueryMenuItem.html");
+	/**
+	 * The view columns.
+	 *
+	 * <p>
+	 * The view columns are the list of columns that should be displayed.
+	 * An empty list implies all columns should be displayed.
+	 *
+	 * @return An unmodifiable list of columns to view.
+	 */
+	public List<String> getView() {
+		return view;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ASet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ASet.java
index 4d8c46d..5cd70aa 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ASet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/ASet.java
@@ -37,6 +37,7 @@ public final class ASet<T> extends LinkedHashSet<T> {
 	 * @param t The initial values.
 	 * @return A new list.
 	 */
+	@SafeVarargs
 	public static <T> ASet<T> create(T...t) {
 		return new ASet<T>().appendAll(t);
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/PojoQuery.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/PojoQuery.java
index 0fab839..3f05cf3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/PojoQuery.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/PojoQuery.java
@@ -292,7 +292,7 @@ public final class PojoQuery {
 		}
 		if (cm.isMap()) {
 			Map m = (Map)o;
-			DelegateMap dm = new DelegateMap(session.getClassMetaForObject(m));
+			DelegateMap dm = new DelegateMap(m, session);
 			for (Map.Entry e : (Set<Map.Entry>)m.entrySet())
 				dm.put(e.getKey().toString(), e.getValue());
 			return dm;
diff --git a/juneau-doc/docs/ReleaseNotes/8.0.1.html b/juneau-doc/docs/ReleaseNotes/8.0.1.html
index 9667543..7cebcb0 100644
--- a/juneau-doc/docs/ReleaseNotes/8.0.1.html
+++ b/juneau-doc/docs/ReleaseNotes/8.0.1.html
@@ -54,5 +54,7 @@
 			<li class='jac'>{@link oajr.BasicRestJena} - Non-servlet equivalent to {@link oajr.BasicRestServletJena}
 			<li class='jac'>{@link oajr.BasicRestJenaGroup} - Non-servlet equivalent to {@link oajr.BasicRestServletJenaGroup}
 		</ul>
+	<li>
+		HTML widgets now have access to the <code>RestResponse</code> object if they need access to the output bean.
 </ul>
 
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddOrderMenuItem.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddOrderMenuItem.java
index 16a0a9c..fd35548 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddOrderMenuItem.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddOrderMenuItem.java
@@ -29,17 +29,17 @@ import org.apache.juneau.rest.widget.*;
 public class AddOrderMenuItem extends MenuItemWidget {
 
 	@Override /* MenuItemWidget */
-	public String getLabel(RestRequest req) throws Exception {
+	public String getLabel(RestRequest req, RestResponse res) throws Exception {
 		return "add";
 	}
 
 	@Override /* MenuItemWidget */
-	public String getBeforeShowScript(RestRequest req) throws Exception {
+	public String getBeforeShowScript(RestRequest req, RestResponse res) throws Exception {
 		return loadScript("AddOrderMenuItem_beforeShow.js");
 	}
 
 	@Override /* Widget */
-	public Object getContent(RestRequest req) throws Exception {
+	public Object getContent(RestRequest req, RestResponse res) throws Exception {
 
 		return div(
 			form().id("form").action("servlet:/store/order").method(POST).children(
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddPetMenuItem.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddPetMenuItem.java
index d5b9744..c438410 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddPetMenuItem.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/AddPetMenuItem.java
@@ -29,12 +29,12 @@ import org.apache.juneau.rest.widget.*;
 public class AddPetMenuItem extends MenuItemWidget {
 
 	@Override /* MenuItemWidget */
-	public String getLabel(RestRequest req) throws Exception {
+	public String getLabel(RestRequest req, RestResponse res) throws Exception {
 		return "add";
 	}
 
 	@Override /* Widget */
-	public Object getContent(RestRequest req) throws Exception {
+	public Object getContent(RestRequest req, RestResponse res) throws Exception {
 		return div(
 			form().id("form").action("servlet:/pet").method(POST).children(
 				table(
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/UploadPhotoMenuItem.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/UploadPhotoMenuItem.java
index 60fb02b..d5b8cf0 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/UploadPhotoMenuItem.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/rest/UploadPhotoMenuItem.java
@@ -29,12 +29,12 @@ import org.apache.juneau.rest.widget.*;
 public class UploadPhotoMenuItem extends MenuItemWidget {
 
 	@Override /* MenuItemWidget */
-	public String getLabel(RestRequest req) throws Exception {
+	public String getLabel(RestRequest req, RestResponse res) throws Exception {
 		return "upload";
 	}
 
 	@Override /* Widget */
-	public Object getContent(RestRequest req) throws Exception {
+	public Object getContent(RestRequest req, RestResponse res) throws Exception {
 		return div(
 			form().id("form").action("servlet:/upload").method(POST).enctype("multipart/form-data").children(
 				table(
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
index a844db3..2c524f9 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
@@ -332,9 +332,10 @@ public class BasicRestCallHandler implements RestCallHandler {
 	 * @return The session objects for that request.
 	 */
 	@Override /* RestCallHandler */
-	public Map<String,Object> getSessionObjects(RestRequest req) {
+	public Map<String,Object> getSessionObjects(RestRequest req, RestResponse res) {
 		Map<String,Object> m = new HashMap<>();
 		m.put(RequestVar.SESSION_req, req);
+		m.put(RequestVar.SESSION_res, res);
 		return m;
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
index d45be08..bc147ba 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
@@ -103,7 +103,8 @@ public interface RestCallHandler {
 	 * Returns the session objects for the specified request.
 	 *
 	 * @param req The REST request.
+	 * @param res The REST response.
 	 * @return The session objects for that request.
 	 */
-	public Map<String,Object> getSessionObjects(RestRequest req);
+	public Map<String,Object> getSessionObjects(RestRequest req, RestResponse res);
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 32a3e60..30cd36c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -2920,11 +2920,11 @@ public final class RestContext extends BeanContext {
 	 *
 	 * Widgets resolve the following variables:
 	 * <ul class='spaced-list'>
-	 * 	<li><js>"$W{name}"</js> - Contents returned by {@link Widget#getHtml(RestRequest)}.
-	 * 	<li><js>"$W{name.script}"</js> - Contents returned by {@link Widget#getScript(RestRequest)}.
+	 * 	<li><js>"$W{name}"</js> - Contents returned by {@link Widget#getHtml(RestRequest,RestResponse)}.
+	 * 	<li><js>"$W{name.script}"</js> - Contents returned by {@link Widget#getScript(RestRequest,RestResponse)}.
 	 * 		<br>The script contents are automatically inserted into the <xt>&lt;head/script&gt;</xt> section
 	 * 			 in the HTML page.
-	 * 	<li><js>"$W{name.style}"</js> - Contents returned by {@link Widget#getStyle(RestRequest)}.
+	 * 	<li><js>"$W{name.style}"</js> - Contents returned by {@link Widget#getStyle(RestRequest,RestResponse)}.
 	 * 		<br>The styles contents are automatically inserted into the <xt>&lt;head/style&gt;</xt> section
 	 * 			 in the HTML page.
 	 * </ul>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index 14fe47d..114d0e8 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -111,6 +111,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	private Swagger swagger;
 	private SerializerSessionArgs serializerSessionArgs;
 	private ParserSessionArgs parserSessionArgs;
+	private RestResponse res;
 
 	/**
 	 * Constructor.
@@ -1315,7 +1316,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 */
 	public VarResolverSession getVarResolverSession() {
 		if (varSession == null)
-			varSession = context.getVarResolver().createSession(context.getCallHandler().getSessionObjects(this));
+			varSession = context.getVarResolver().createSession(context.getCallHandler().getSessionObjects(this, context.getResponse()));
 		return varSession;
 	}
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
index 36728ee..52dda82 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/HtmlDoc.java
@@ -557,13 +557,13 @@ public @interface HtmlDoc {
 	 *
 	 * <ul class='spaced-list'>
 	 * 	<li>
-	 * 		<js>"$W{name}"</js> - Contents returned by {@link Widget#getHtml(RestRequest)}.
+	 * 		<js>"$W{name}"</js> - Contents returned by {@link Widget#getHtml(RestRequest,RestResponse)}.
 	 * 	<li>
-	 * 		<js>"$W{name.script}"</js> - Contents returned by {@link Widget#getScript(RestRequest)}.
+	 * 		<js>"$W{name.script}"</js> - Contents returned by {@link Widget#getScript(RestRequest,RestResponse)}.
 	 * 		<br>The script contents are automatically inserted into the <xt>&lt;head/script&gt;</xt> section
 	 * 			 in the HTML page.
 	 * 	<li>
-	 * 		<js>"$W{name.style}"</js> - Contents returned by {@link Widget#getStyle(RestRequest)}.
+	 * 		<js>"$W{name.style}"</js> - Contents returned by {@link Widget#getStyle(RestRequest,RestResponse)}.
 	 * 		<br>The styles contents are automatically inserted into the <xt>&lt;head/style&gt;</xt> section
 	 * 			 in the HTML page.
 	 * </ul>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
index cc589b7..b6cf13d 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/RequestVar.java
@@ -69,6 +69,11 @@ public class RequestVar extends MultipartResolvingVar {
 	 */
 	public static final String SESSION_req = "req";
 
+	/**
+	 * The name of the session or context object that identifies the {@link RestResponse} object.
+	 */
+	public static final String SESSION_res = "res";
+
 
 	/** The name of this variable. */
 	public static final String NAME = "R";
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
index d55203f..f0d1288 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
@@ -43,6 +43,7 @@ public class WidgetVar extends SimpleVar {
 	 * The name of the session or context object that identifies the {@link RestRequest} object.
 	 */
 	private static final String SESSION_req = "req";
+	private static final String SESSION_res = "res";
 
 	/**
 	 * The name of this variable.
@@ -59,6 +60,7 @@ public class WidgetVar extends SimpleVar {
 	@Override /* Parameter */
 	public String resolve(VarResolverSession session, String key) throws Exception {
 		RestRequest req = session.getSessionObject(RestRequest.class, SESSION_req, true);
+		RestResponse res = session.getSessionObject(RestResponse.class, SESSION_res, true);
 		boolean isScript = false, isStyle = false;
 
 		if (key.endsWith(".script")) {
@@ -76,9 +78,9 @@ public class WidgetVar extends SimpleVar {
 			return "unknown-widget-"+key;
 
 		if (isScript)
-			return w.getScript(req);
+			return w.getScript(req, res);
 		if (isStyle)
-			return w.getStyle(req);
-		return w.getHtml(req);
+			return w.getStyle(req, res);
+		return w.getHtml(req, res);
 	}
 }
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
index af35301..bafb48b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
@@ -61,12 +61,12 @@ import org.apache.juneau.utils.*;
 public class ContentTypeMenuItem extends MenuItemWidget {
 
 	@Override /* MenuItemWidget */
-	public String getLabel(RestRequest req) {
+	public String getLabel(RestRequest req, RestResponse res) {
 		return "content-type";
 	}
 
 	@Override /* MenuItemWidget */
-	public Div getContent(RestRequest req) {
+	public Div getContent(RestRequest req, RestResponse res) {
 		Div div = div();
 		Set<MediaType> l = new TreeSet<>();
 		for (Serializer s : req.getSerializers().getSerializers())
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
index ad2e8ea..23d6a60 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
@@ -35,7 +35,7 @@ public abstract class MenuItemWidget extends Widget {
 	 * Returns the Javascript needed for the show and hide actions of the menu item.
 	 */
 	@Override /* Widget */
-	public String getScript(RestRequest req) throws Exception {
+	public String getScript(RestRequest req, RestResponse res) throws Exception {
 		return loadScript("MenuItemWidget.js");
 	}
 
@@ -81,11 +81,12 @@ public abstract class MenuItemWidget extends Widget {
 	 * 	}
 	 * </p>
 	 *
-	 * @param req The current request.
+	 * @param req The HTTP request object.
+	 * @param res The HTTP response object.
 	 * @return Javascript code to execute, or <jk>null</jk> if there isn't any.
 	 * @throws Exception
 	 */
-	public String getBeforeShowScript(RestRequest req) throws Exception {
+	public String getBeforeShowScript(RestRequest req, RestResponse res) throws Exception {
 		return null;
 	}
 
@@ -93,33 +94,34 @@ public abstract class MenuItemWidget extends Widget {
 	 * Optional Javascript to execute immediately after a menu item is shown.
 	 *
 	 * <p>
-	 * Same as {@link #getBeforeShowScript(RestRequest)} except this Javascript gets executed after the popup dialog has become visible.
+	 * Same as {@link #getBeforeShowScript(RestRequest,RestResponse)} except this Javascript gets executed after the popup dialog has become visible.
 	 *
-	 * @param req The current request.
+	 * @param req The HTTP request object.
+	 * @param res The HTTP response object.
 	 * @return Javascript code to execute, or <jk>null</jk> if there isn't any.
 	 * @throws Exception
 	 */
-	public String getAfterShowScript(RestRequest req) throws Exception {
+	public String getAfterShowScript(RestRequest req, RestResponse res) throws Exception {
 		return null;
 	}
 
 	/**
 	 * Defines a <js>"menu-item"</js> class that needs to be used on the outer element of the HTML returned by the
-	 * {@link #getHtml(RestRequest)} method.
+	 * {@link #getHtml(RestRequest,RestResponse)} method.
 	 */
 	@Override /* Widget */
-	public String getStyle(RestRequest req) throws Exception {
+	public String getStyle(RestRequest req, RestResponse res) throws Exception {
 		return loadStyle("MenuItemWidget.css");
 	}
 
 	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
+	public String getHtml(RestRequest req, RestResponse res) throws Exception {
 		StringBuilder sb = new StringBuilder();
 
 		// Need a unique number to define unique function names.
 		Integer id = null;
 
-		String pre = nullIfEmpty(getBeforeShowScript(req)), post = nullIfEmpty(getAfterShowScript(req));
+		String pre = nullIfEmpty(getBeforeShowScript(req, res)), post = nullIfEmpty(getAfterShowScript(req, res));
 
 		sb.append("\n<div class='menu-item'>");
 		if (pre != null || post != null) {
@@ -140,10 +142,10 @@ public abstract class MenuItemWidget extends Widget {
 		}
 		String onclick = (pre == null ? "" : "onPreShow"+id+"();") + "menuClick(this);" + (post == null ? "" : "onPostShow"+id+"();");
 		sb.append(""
-			+ "\n\t<a onclick='"+onclick+"'>"+getLabel(req)+"</a>"
+			+ "\n\t<a onclick='"+onclick+"'>"+getLabel(req, res)+"</a>"
 			+ "\n<div class='popup-content'>"
 		);
-		Object o = getContent(req);
+		Object o = getContent(req, res);
 		if (o instanceof Reader) {
 			try (Reader r = (Reader)o; Writer w = new StringBuilderWriter(sb)) {
 				IOUtils.pipe(r, w);
@@ -177,15 +179,17 @@ public abstract class MenuItemWidget extends Widget {
 	 * The label for the menu item as it's rendered in the menu bar.
 	 *
 	 * @param req The HTTP request object.
+	 * @param res The HTTP response object.
 	 * @return The menu item label.
 	 * @throws Exception
 	 */
-	public abstract String getLabel(RestRequest req) throws Exception;
+	public abstract String getLabel(RestRequest req, RestResponse res) throws Exception;
 
 	/**
 	 * The content of the popup.
 	 *
 	 * @param req The HTTP request object.
+	 * @param res The HTTP response object.
 	 * @return
 	 * 	The content of the popup.
 	 * 	<br>Can be any of the following types:
@@ -197,5 +201,5 @@ public abstract class MenuItemWidget extends Widget {
 	 * 	</ul>
 	 * @throws Exception
 	 */
-	public abstract Object getContent(RestRequest req) throws Exception;
+	public abstract Object getContent(RestRequest req, RestResponse res) throws Exception;
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java
index a237919..cb68a0f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java
@@ -53,7 +53,7 @@ public class PoweredByApache extends Widget {
 	 * Returns an Apache image tag hyperlinked to <js>"http://apache.org"</js>
 	 */
 	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
+	public String getHtml(RestRequest req, RestResponse res) throws Exception {
 		UriResolver r = req.getUriResolver();
 		return "<a href='http://apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/asf.png")+"'>";
 	}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
index 5231a47..9b2d5c5 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
@@ -33,7 +33,7 @@ public class PoweredByJuneau extends Widget {
 	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
 	 */
 	@Override /* Widget */
-	public String getHtml(RestRequest req) throws Exception {
+	public String getHtml(RestRequest req, RestResponse res) throws Exception {
 		UriResolver r = req.getUriResolver();
 		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
 	}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java
index f01d403..d14f142 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java
@@ -31,19 +31,19 @@ public class QueryMenuItem extends MenuItemWidget {
 	 * Returns CSS for the tooltips.
 	 */
 	@Override
-	public String getStyle(RestRequest req) throws Exception {
-		return super.getStyle(req)
+	public String getStyle(RestRequest req, RestResponse res) throws Exception {
+		return super.getStyle(req, res)
 			+ "\n"
 			+ loadStyle("QueryMenuItem.css");
 	}
 
 	@Override /* MenuItemWidget */
-	public String getLabel(RestRequest req) throws Exception {
+	public String getLabel(RestRequest req, RestResponse res) throws Exception {
 		return "query";
 	}
 
 	@Override /* MenuItemWidget */
-	public String getContent(RestRequest req) throws Exception {
+	public String getContent(RestRequest req, RestResponse res) throws Exception {
 		return loadHtml("QueryMenuItem.html");
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ThemeMenuItem.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ThemeMenuItem.java
index b9e495a..7ce1c68 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ThemeMenuItem.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ThemeMenuItem.java
@@ -34,12 +34,12 @@ public class ThemeMenuItem extends MenuItemWidget {
 	private static final String[] BUILT_IN_STYLES = {"devops", "light", "original", "dark"};
 
 	@Override /* Widget */
-	public String getLabel(RestRequest req) {
+	public String getLabel(RestRequest req, RestResponse res) {
 		return "themes";
 	}
 
 	@Override /* MenuItemWidget */
-	public Div getContent(RestRequest req) throws Exception {
+	public Div getContent(RestRequest req, RestResponse res) throws Exception {
 		Div div = div();
 		for (String s : BUILT_IN_STYLES) {
 			java.net.URI uri = req.getUri(true, new AMap<String,String>().append("stylesheet", "htdocs/themes/"+s+".css"));
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java
index 2b60969..85bb1e1 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java
@@ -65,10 +65,11 @@ public abstract class Widget {
 	 * A returned value of <jk>null</jk> will cause nothing to be added to the page.
 	 *
 	 * @param req The HTTP request object.
+	 * @param res The current HTTP response.
 	 * @return The HTML content of this widget.
 	 * @throws Exception
 	 */
-	public String getHtml(RestRequest req) throws Exception {
+	public String getHtml(RestRequest req, RestResponse res) throws Exception {
 		return null;
 	}
 
@@ -79,10 +80,11 @@ public abstract class Widget {
 	 * A returned value of <jk>null</jk> will cause nothing to be added to the page.
 	 *
 	 * @param req The HTTP request object.
+	 * @param res The current HTTP response.
 	 * @return The Javascript needed by this widget.
 	 * @throws Exception
 	 */
-	public String getScript(RestRequest req) throws Exception {
+	public String getScript(RestRequest req, RestResponse res) throws Exception {
 		return null;
 	}
 
@@ -93,10 +95,11 @@ public abstract class Widget {
 	 * A returned value of <jk>null</jk> will cause nothing to be added to the page.
 	 *
 	 * @param req The HTTP request object.
+	 * @param res The current HTTP response.
 	 * @return The CSS styles needed by this widget.
 	 * @throws Exception
 	 */
-	public String getStyle(RestRequest req) throws Exception {
+	public String getStyle(RestRequest req, RestResponse res) throws Exception {
 		return null;
 	}
 
@@ -169,11 +172,12 @@ public abstract class Widget {
 	 * </ul>
 	 *
 	 * @param req The current HTTP request.
+	 * @param res The current HTTP response.
 	 * @param name Name of the desired resource.
 	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
 	 * @throws IOException
 	 */
-	protected String loadScriptWithVars(RestRequest req, String name) throws IOException {
+	protected String loadScriptWithVars(RestRequest req, RestResponse res, String name) throws IOException {
 		return req.getVarResolverSession().resolve(loadScript(name));
 	}
 
@@ -205,11 +209,12 @@ public abstract class Widget {
 	 * </ul>
 	 *
 	 * @param req The current HTTP request.
+	 * @param res The current HTTP response.
 	 * @param name Name of the desired resource.
 	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
 	 * @throws IOException
 	 */
-	protected String loadStyleWithVars(RestRequest req, String name) throws IOException {
+	protected String loadStyleWithVars(RestRequest req, RestResponse res, String name) throws IOException {
 		return req.getVarResolverSession().resolve(loadStyle(name));
 	}
 
@@ -241,11 +246,12 @@ public abstract class Widget {
 	 * </ul>
 	 *
 	 * @param req The current HTTP request.
+	 * @param res The current HTTP response.
 	 * @param name Name of the desired resource.
 	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
 	 * @throws IOException
 	 */
-	protected String loadHtmlWithVars(RestRequest req, String name) throws IOException {
+	protected String loadHtmlWithVars(RestRequest req, RestResponse res, String name) throws IOException {
 		return req.getVarResolverSession().resolve(loadHtml(name));
 	}
 }


[juneau] 09/09: Strip trailing slashes from RestMethod.path.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 2244c05dbbd4ecf75bd8e69a7b442b8a3db186f3
Author: JamesBognar <ja...@apache.org>
AuthorDate: Sun Mar 10 11:52:00 2019 -0400

    Strip trailing slashes from RestMethod.path.
---
 .../juneau/microservice/jetty/JettyMicroservice.java      |  3 +++
 .../org/apache/juneau/rest/BasicRestInfoProvider.java     |  3 ++-
 .../src/main/java/org/apache/juneau/rest/RestContext.java |  3 ++-
 .../main/java/org/apache/juneau/rest/RestJavaMethod.java  |  3 ++-
 .../main/java/org/apache/juneau/rest/util/RestUtils.java  | 15 +++++++++++++++
 5 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyMicroservice.java b/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyMicroservice.java
index 6c16139..c6ac6c6 100644
--- a/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyMicroservice.java
+++ b/juneau-microservice/juneau-microservice-jetty/src/main/java/org/apache/juneau/microservice/jetty/JettyMicroservice.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.microservice.jetty;
 
 import static org.apache.juneau.internal.SystemUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
 
 import java.io.*;
 import java.net.*;
@@ -389,6 +390,8 @@ public class JettyMicroservice extends Microservice {
 	 */
 	public JettyMicroservice addServlet(Servlet servlet, String pathSpec) {
 		ServletHolder sh = new ServletHolder(servlet);
+		if (pathSpec != null && ! pathSpec.endsWith("/*"))
+			pathSpec = trimTrailingSlashes(pathSpec) + "/*";
 		getServletContextHandler().addServlet(sh, pathSpec);
 		return this;
 	}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
index 58221e3..e7ec31f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
@@ -14,6 +14,7 @@ package org.apache.juneau.rest;
 
 import static org.apache.juneau.internal.ClassUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.rest.util.RestUtils.*;
 
 import java.lang.reflect.Method;
 import java.util.*;
@@ -397,7 +398,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 		if (s != null) {
 			Map<String,OperationMap> sp = s.getPaths();
 			if (sp != null) {
-				Map<String,Operation> spp = sp.get(getAnnotation(RestMethod.class, method).path());
+				Map<String,Operation> spp = sp.get(fixMethodPath(getAnnotation(RestMethod.class, method).path()));
 				if (spp != null)
 					return spp.get(req.getMethod());
 			}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index b758b76..66703de 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -17,6 +17,7 @@ import static org.apache.juneau.internal.ClassUtils.*;
 import static org.apache.juneau.internal.CollectionUtils.*;
 import static org.apache.juneau.internal.IOUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.rest.util.RestUtils.*;
 
 import java.io.*;
 import java.lang.reflect.*;
@@ -3229,7 +3230,7 @@ public final class RestContext extends BeanContext {
 			for (java.lang.reflect.Method method : resourceClass.getMethods()) {
 				RestMethod a = ClassUtils.getAnnotation(RestMethod.class, method);
 				if (a != null) {
-					methodsFound.add(method.getName() + "," + emptyIfNull(firstNonEmpty(a.name(), a.method())) + "," + a.path());
+					methodsFound.add(method.getName() + "," + emptyIfNull(firstNonEmpty(a.name(), a.method())) + "," + fixMethodPath(a.path()));
 					try {
 						if (! isPublic(method))
 							throw new RestServletException("@RestMethod method {0}.{1} must be defined as public.", resourceClass.getName(), method.getName());
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
index 1643f01..a31ca75 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
@@ -202,7 +202,8 @@ public class RestJavaMethod implements Comparable<RestJavaMethod>  {
 					pgb.append(mParsers);
 				}
 
-				String p = m.path();
+				//String p = trimTrailingSlashes(m.path());
+				String p = fixMethodPath(m.path());
 				if (isEmpty(p))
 					p = HttpUtils.detectHttpPath(method, true);
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
index fc6d358..8a57fae 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
@@ -25,6 +25,7 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.utils.*;
 
@@ -439,4 +440,18 @@ public final class RestUtils {
 		}
 		return op;
 	}
+
+	/**
+	 * Normalizes the {@link RestMethod#path()} value.
+	 *
+	 * @param path
+	 * @return The normalized path.
+	 */
+	public static String fixMethodPath(String path) {
+		if (path == null)
+			return null;
+		if (path.equals("/"))
+			return path;
+		return trimTrailingSlashes(path);
+	}
 }


[juneau] 06/09: Improvements to RestMock APIs.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 211e266234a734e2bacf4f9125e3b85f2dcf7d57
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu Mar 7 13:36:10 2019 -0500

    Improvements to RestMock APIs.
---
 .../org/apache/juneau/http/HttpMethodName.java     |   3 +
 .../java/org/apache/juneau/marshall/Marshall.java  |  18 +
 .../juneau/pojotools/TimeMatcherFactory.java       |   3 -
 .../apache/juneau/utils/MockHttpConnection.java    |   5 +-
 juneau-doc/docs/ReleaseNotes/8.0.1.html            |   5 +
 juneau-doc/src/main/javadoc/overview.html          |   8 +
 .../org/apache/juneau/rest/test/MockRestTest.java  |   4 +-
 .../rest/test/client/CallbackStringsTest.java      |   2 +-
 .../juneau/rest/test/client/ClientFuturesTest.java |   2 +-
 .../juneau/rest/test/client/FormDataTest.java      |   4 +-
 .../rest/test/client/InterfaceProxyTest.java       |   2 +-
 .../rest/test/client/RequestBeanProxyTest.java     |   8 +-
 juneau-rest/juneau-rest-client/pom.xml             |   1 -
 .../org/apache/juneau/rest/client/RestClient.java  |  69 +++-
 .../juneau/rest/client/RestClientBuilder.java      |  19 +
 .../rest/client/mock/MockHttpClientConnection.java |   4 +-
 .../rest/client/mock/MockRemoteResource.java       | 404 ++++++++++++++++++++
 .../rest/client/remote/BodyAnnotationTest.java     |  13 +-
 .../rest/client/remote/EndToEndInterfaceTest.java  |  24 +-
 .../rest/client/remote/FormDataAnnotationTest.java |  32 +-
 .../rest/client/remote/HeaderAnnotationTest.java   |  32 +-
 .../rest/client/remote/PathAnnotationTest.java     |  26 +-
 .../rest/client/remote/QueryAnnotationTest.java    |  32 +-
 .../client/remote/RemoteMethodAnnotationTest.java  |  20 +-
 .../remote/RemoteResourceAnnotationTest.java       |  16 +-
 .../rest/client/remote/RequestAnnotationTest.java  |  19 +-
 .../rest/client/remote/ResponseAnnotationTest.java |   6 +-
 .../java/org/apache/juneau/rest/RestContext.java   |   2 +-
 .../java/org/apache/juneau/rest/mock/MockRest.java | 425 +++++++++++++++++++--
 .../juneau/rest/mock/MockServletRequest.java       | 102 ++++-
 .../org/apache/juneau/rest/util/RestUtils.java     |  27 ++
 .../jueau/rest/helper/ReaderResourceTest.java      |   2 +-
 .../jueau/rest/helper/StreamResourceTest.java      |   2 +-
 .../juneau/rest/BasicRestInfoProviderTest.java     |   2 +-
 .../juneau/rest/BeanContextPropertiesTest.java     |   2 +-
 .../test/java/org/apache/juneau/rest/NlsTest.java  |   6 +-
 .../java/org/apache/juneau/rest/PathsTest.java     |   8 +-
 .../org/apache/juneau/rest/RestParamsTest.java     |   2 +-
 .../org/apache/juneau/rest/StatusCodesTest.java    |   8 +-
 .../apache/juneau/rest/ThreadLocalObjectsTest.java |   4 +-
 .../juneau/rest/annotation/HtmlDocAsideTest.java   |   4 +-
 .../juneau/rest/annotation/HtmlDocFooterTest.java  |   4 +-
 .../juneau/rest/annotation/HtmlDocHeaderTest.java  |   4 +-
 .../juneau/rest/annotation/HtmlDocNavTest.java     |   4 +-
 .../rest/annotation/HtmlDocNavlinksTest.java       |   4 +-
 .../juneau/rest/annotation/HtmlDocScriptTest.java  |   4 +-
 .../juneau/rest/annotation/HtmlDocStyleTest.java   |   4 +-
 .../annotation/ResponseHeaderAnnotationTest.java   |   2 +-
 .../annotation/ResponseStatusAnnotationTest.java   |   2 +-
 .../juneau/rest/annotation/RestMethodBpiTest.java  |  14 +-
 .../rest/annotation/RestMethodGuardsTest.java      |   2 +-
 .../rest/annotation/RestMethodMatchersTest.java    |   2 +-
 .../juneau/rest/annotation/RestMethodPathTest.java |   2 +-
 .../rest/annotation/RestResourceMessagesTest.java  |   4 +-
 .../rest/annotation/RestResourcePathTest.java      |   2 +-
 .../annotation/RestResourcePropertiesTest.java     |   2 +-
 .../annotation/RestResourceSerializersTest.java    |   2 +-
 .../annotation/RestResourceStaticFilesTest.java    |   4 +-
 .../annotation2/AnnotationInheritanceTest.java     |   2 +-
 .../rest/annotation2/BodyAnnotationTest.java       |  16 +-
 .../rest/annotation2/FormDataAnnotationTest.java   |   6 +-
 .../annotation2/HasFormDataAnnotationTest.java     |   2 +-
 .../rest/annotation2/HasQueryAnnotationTest.java   |   2 +-
 .../rest/annotation2/PathAnnotationTest.java       |  10 +-
 .../annotation2/PathRemainderAnnotationTest.java   |   2 +-
 .../rest/annotation2/QueryAnnotationTest.java      |   8 +-
 .../rest/annotation2/ResponseAnnotationTest.java   |  14 +-
 .../juneau/rest/annotation2/RestHookTest.java      |  16 +-
 .../rest/annotation2/RestMethodInheritTest.java    |   8 +-
 .../rest/annotation2/RestResourceParsersTest.java  |   2 +-
 .../annotation2/RestResourcePojoSwapsTest.java     |   2 +-
 .../apache/juneau/rest/exception/BasicTest.java    |  10 +-
 .../juneau/rest/headers/AcceptCharsetTest.java     |   4 +-
 .../juneau/rest/headers/AcceptEncodingTest.java    |   6 +-
 .../org/apache/juneau/rest/headers/AcceptTest.java |  12 +-
 .../juneau/rest/headers/ClientVersionTest.java     |   4 +-
 .../juneau/rest/headers/ContentEncodingTest.java   |   5 +-
 .../juneau/rest/headers/ContentTypeTest.java       |  10 +-
 .../apache/juneau/rest/headers/HeadersTest.java    |  18 +-
 .../org/apache/juneau/rest/response/BasicTest.java |   8 +-
 .../apache/juneau/rest/testutils/TestUtils.java    |   1 +
 .../org/apache/juneau/rest/util/RestUtilsTest.java |  17 +
 82 files changed, 1275 insertions(+), 349 deletions(-)

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HttpMethodName.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HttpMethodName.java
index 3209764..7183d62 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HttpMethodName.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HttpMethodName.java
@@ -46,6 +46,9 @@ public final class HttpMethodName {
 	/** {@doc RFC2616.section9#sec9.9 CONNECT} */
 	public static final String CONNECT = "CONNECT";
 
+	/** {@doc https://tools.ietf.org/html/rfc5789 PATCH} */
+	public static final String PATCH = "PATCH";
+
 	/** Special case for a REST method that implements a REST-RPC interface. */
 	public static final String RRPC = "RRPC";
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Marshall.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Marshall.java
index bec1206..1209ed7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Marshall.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/Marshall.java
@@ -64,6 +64,24 @@ public abstract class Marshall {
 	}
 
 	/**
+	 * Returns the serializer associated with this marshall.
+	 *
+	 * @return The serializer associated with this marshall.
+	 */
+	public Serializer getSerializer() {
+		return s;
+	}
+
+	/**
+	 * Returns the parser associated with this marshall.
+	 *
+	 * @return The parser associated with this marshall.
+	 */
+	public Parser getParser() {
+		return p;
+	}
+
+	/**
 	 * Serializes a POJO directly to either a <code>String</code> or <code><jk>byte</jk>[]</code> depending on the serializer type.
 	 *
 	 * @param o The object to serialize.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java
index b27ea5b..9eb9263 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/pojotools/TimeMatcherFactory.java
@@ -312,7 +312,6 @@ public class TimeMatcherFactory extends MatcherFactory {
 			if (state == S01) {
 				// No tokens found.
 			} else if (state == S02 || state == S03 || state == S04 || state == S05 || state == S06 || state == S10 || state == S11 || state == S12) {
-				System.err.println("state=["+state+"]");
 				throw new PatternException("Invalid range pattern (E{0}): {1}", state, s);
 			} else if (state == S07) {
 				l.add(new TimestampRange(f, eq, s1));
@@ -361,8 +360,6 @@ public class TimeMatcherFactory extends MatcherFactory {
 		}
 
 		public TimestampRange(SimpleDateFormat[] formats, Equality eq, String singleDate) {
-			System.err.println("eq=["+eq+"], singleDate=["+singleDate+"]");
-
 			CalendarP singleDate1 = parseDate(formats, singleDate);
 			if (eq == Equality.GT) {
 				this.start = singleDate1.roll(1).roll(MILLISECOND, -1).getCalendar();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MockHttpConnection.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MockHttpConnection.java
index b65adea..15b393c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MockHttpConnection.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MockHttpConnection.java
@@ -12,6 +12,8 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.utils;
 
+import java.util.*;
+
 /**
  * Represent the basic connection for mock HTTP requests.
  *
@@ -26,9 +28,10 @@ public interface MockHttpConnection {
 	 *
 	 * @param method The HTTP request method.
 	 * @param path The HTTP request path.
+	 * @param headers Optional HTTP request headers.
 	 * @param body The HTTP request body.
 	 * @return A new mock request.
 	 * @throws Exception
 	 */
-	MockHttpRequest request(String method, String path, Object body) throws Exception;
+	MockHttpRequest request(String method, String path, Map<String,Object> headers, Object body) throws Exception;
 }
diff --git a/juneau-doc/docs/ReleaseNotes/8.0.1.html b/juneau-doc/docs/ReleaseNotes/8.0.1.html
index 7cebcb0..25394a7 100644
--- a/juneau-doc/docs/ReleaseNotes/8.0.1.html
+++ b/juneau-doc/docs/ReleaseNotes/8.0.1.html
@@ -58,3 +58,8 @@
 		HTML widgets now have access to the <code>RestResponse</code> object if they need access to the output bean.
 </ul>
 
+<h5 class='topic w800'>juneau-rest-client</h5>
+<ul class='spaced-list'>
+	<li>
+		PATCH support added.
+</ul>
\ No newline at end of file
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index 4b23dcd..c5d6f49 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -35371,6 +35371,14 @@
 			<li class='jac'>{@link org.apache.juneau.rest.BasicRestJena} - Non-servlet equivalent to {@link org.apache.juneau.rest.BasicRestServletJena}
 			<li class='jac'>{@link org.apache.juneau.rest.BasicRestJenaGroup} - Non-servlet equivalent to {@link org.apache.juneau.rest.BasicRestServletJenaGroup}
 		</ul>
+	<li>
+		HTML widgets now have access to the <code>RestResponse</code> object if they need access to the output bean.
+</ul>
+
+<h5 class='topic w800'>juneau-rest-client</h5>
+<ul class='spaced-list'>
+	<li>
+		PATCH support added.
 </ul>
 </div><!-- END: 8.0.1 -->
 
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java
index 3ea3900..ac56130 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/MockRestTest.java
@@ -45,14 +45,14 @@ public class MockRestTest {
 
 	@Test
 	public void a01() throws Exception {
-		MockRest a = MockRest.create(A.class);
+		MockRest a = MockRest.build(A.class, null);
 		RestClient rc = RestClient.create().mockHttpConnection(a).build();
 		assertEquals("OK", rc.doPut("/a01", "OK").getResponseAsString());
 	}
 
 	@Test
 	public void a02() throws Exception {
-		MockRest a = MockRest.create(A.class);
+		MockRest a = MockRest.build(A.class);
 		RestClient rc = RestClient.create().json().mockHttpConnection(a).build();
 		assertEquals("OK", rc.doPut("/a02", "OK").getResponse(String.class));
 	}
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java
index 9bb33ae..679cf84 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/CallbackStringsTest.java
@@ -50,7 +50,7 @@ public class CallbackStringsTest {
 			return m;
 		}
 	}
-	static RestClient a = RestClient.create().mockHttpConnection(MockRest.create(A.class)).build();
+	static RestClient a = RestClient.create().mockHttpConnection(MockRest.build(A.class, null)).build();
 
 	@Test
 	public void a01() throws Exception {
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java
index 79812fa..53ce031 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ClientFuturesTest.java
@@ -39,7 +39,7 @@ public class ClientFuturesTest {
 			return new ObjectMap().append("foo","bar");
 		}
 	}
-	static RestClient a = RestClient.create().mockHttpConnection(MockRest.create(A.class)).build();
+	static RestClient a = RestClient.create().mockHttpConnection(MockRest.build(A.class, null)).build();
 
 	@Test
 	public void a01() throws Exception {
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java
index 0ed3e18..b34642a 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/FormDataTest.java
@@ -41,7 +41,7 @@ public class FormDataTest extends RestTestcase {
 			return new StringReader("Content-Type=["+req.getContentType()+"], contents=["+read(req.getReader())+"]");
 		}
 	}
-	static RestClient a = RestClient.create().mockHttpConnection(MockRest.create(A.class)).build();
+	static RestClient a = RestClient.create().mockHttpConnection(MockRest.build(A.class)).build();
 
 	@Test
 	public void a01_formDataMethod() throws Exception {
@@ -61,7 +61,7 @@ public class FormDataTest extends RestTestcase {
 
 	@Test
 	public void a03_plainTextParams() throws Exception {
-		RestClient c = RestClient.create().mockHttpConnection(MockRest.create(A.class)).urlEnc().paramFormatPlain().build();
+		RestClient c = RestClient.create().mockHttpConnection(MockRest.build(A.class)).urlEnc().paramFormatPlain().build();
 		try {
 			String r;
 
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java
index 6ae83f4..c1b0a3f 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/InterfaceProxyTest.java
@@ -935,7 +935,7 @@ public class InterfaceProxyTest {
 			};
 		}
 	}
-	static MockRest interfaceProxyResource = MockRest.create(InterfaceProxyResource.class);
+	static MockRest interfaceProxyResource = MockRest.build(InterfaceProxyResource.class);
 
 	private static Map<String,InterfaceProxy> cache = new LinkedHashMap<>();
 
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
index 82dd337..d3ac26b 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
@@ -52,7 +52,7 @@ public class RequestBeanProxyTest {
 			return req.getQuery().toString(true);
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	//=================================================================================================================
 	// @Query - Simple values
@@ -341,7 +341,7 @@ public class RequestBeanProxyTest {
 			return req.getFormData().toString(true);
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	//=================================================================================================================
 	// @FormData, Simple values
@@ -645,7 +645,7 @@ public class RequestBeanProxyTest {
 			return req.getHeaders().subset("a,b,c,d,e,f,g,h,i,a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4").toString(true);
 		}
 	}
-	static MockRest e = MockRest.create(E.class);
+	static MockRest e = MockRest.build(E.class, null);
 
 	//=================================================================================================================
 	// @Header, Simple values
@@ -898,7 +898,7 @@ public class RequestBeanProxyTest {
 			return req.getPathMatch().getRemainder();
 		}
 	}
-	static MockRest g = MockRest.create(G.class);
+	static MockRest g = MockRest.build(G.class, null);
 
 	//=================================================================================================================
 	// @Path, Simple values
diff --git a/juneau-rest/juneau-rest-client/pom.xml b/juneau-rest/juneau-rest-client/pom.xml
index 5f25376..f68e05d 100644
--- a/juneau-rest/juneau-rest-client/pom.xml
+++ b/juneau-rest/juneau-rest-client/pom.xml
@@ -62,7 +62,6 @@
 			<groupId>org.apache.juneau</groupId>
 			<artifactId>juneau-rest-server</artifactId>
 			<version>${project.version}</version>
-			<scope>test</scope>
 		</dependency>
 		<dependency>
 			<groupId>org.apache.juneau</groupId>
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index e47b84f..ae5eb33 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -39,6 +39,7 @@ import org.apache.juneau.remote.*;
 import org.apache.juneau.rest.client.remote.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.urlencoding.*;
+import org.apache.juneau.utils.*;
 
 /**
  * Utility class for interfacing with remote REST interfaces.
@@ -399,6 +400,7 @@ public class RestClient extends BeanContext implements Closeable {
 	 */
 	public static final String RESTCLIENT_serializer = PREFIX + "serializer.o";
 
+	private static final Set<String> NO_BODY_METHODS = Collections.unmodifiableSet(ASet.<String>create("GET","HEAD","DELETE","CONNECT","OPTIONS","TRACE"));
 
 	private static final ConcurrentHashMap<Class,HttpPartSerializer> partSerializerCache = new ConcurrentHashMap<>();
 
@@ -536,6 +538,18 @@ public class RestClient extends BeanContext implements Closeable {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if specified http method has content.
+	 * <p>
+	 * By default, anything not in this list can have content:  <code>GET, HEAD, DELETE, CONNECT, OPTIONS, TRACE</code>.
+	 *
+	 * @param httpMethod The HTTP method.  Must be upper-case.
+	 * @return <jk>true</jk> if specified http method has content.
+	 */
+	protected boolean hasContent(String httpMethod) {
+		return ! NO_BODY_METHODS.contains(httpMethod);
+	}
+
+	/**
 	 * Calls {@link CloseableHttpClient#close()} on the underlying {@link CloseableHttpClient}.
 	 *
 	 * <p>
@@ -754,6 +768,59 @@ public class RestClient extends BeanContext implements Closeable {
 	}
 
 	/**
+	 * Perform a <code>PATCH</code> request against the specified URL.
+	 *
+	 * @param url
+	 * 	The URL of the remote REST resource.
+	 * 	Can be any of the following:  {@link String}, {@link URI}, {@link URL}.
+	 * @param o
+	 * 	The object to serialize and transmit to the URL as the body of the request.
+	 * 	Can be of the following types:
+	 * 	<ul class='spaced-list'>
+	 * 		<li>
+	 * 			{@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
+	 * 		<li>
+	 * 			{@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
+	 * 		<li>
+	 * 			{@link Object} - POJO to be converted to text using the {@link Serializer} registered with the {@link RestClient}.
+	 * 		<li>
+	 * 			{@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
+	 * 	</ul>
+	 * @return
+	 * 	A {@link RestCall} object that can be further tailored before executing the request and getting the response
+	 * 	as a parsed object.
+	 * @throws RestCallException If any authentication errors occurred.
+	 */
+	public RestCall doPatch(Object url, Object o) throws RestCallException {
+		return doCall("PATCH", url, true).body(o);
+	}
+
+	/**
+	 * Same as {@link #doPatch(Object, Object)} but don't specify the input yet.
+	 *
+	 * <p>
+	 * You must call either {@link RestCall#body(Object)} or {@link RestCall#formData(String, Object)} to set the
+	 * contents on the result object.
+	 *
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul class='spaced-list'>
+	 * 	<li>Use {@link #doFormPost(Object, Object)} for <code>application/x-www-form-urlencoded</code> form posts.
+	 * </ul>
+	 *
+	 * @param url
+	 * 	The URL of the remote REST resource.
+	 * 	Can be any of the following:  {@link String}, {@link URI}, {@link URL}.
+	 * @return
+	 * 	A {@link RestCall} object that can be further tailored before executing the request and getting the response
+	 * 	as a parsed object.
+	 * @throws RestCallException
+	 */
+	public RestCall doPatch(Object url) throws RestCallException {
+		return doCall("PATCH", url, true);
+	}
+
+
+	/**
 	 * Performs a REST call where the entire call is specified in a simple string.
 	 *
 	 * <p>
@@ -1048,7 +1115,7 @@ public class RestClient extends BeanContext implements Closeable {
 						String httpMethod = rmm.getHttpMethod();
 						HttpPartSerializer s = getPartSerializer();
 
-						try (RestCall rc = doCall(httpMethod, url, httpMethod.equals("POST") || httpMethod.equals("PUT"))) {
+						try (RestCall rc = doCall(httpMethod, url, hasContent(httpMethod))) {
 
 							rc.serializer(serializer).parser(parser);
 
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 136593d..5ad6092 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -594,6 +594,19 @@ public class RestClientBuilder extends BeanContextBuilder {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
+	 * Sets arbitrary request headers.
+	 *
+	 * @param headers The headers to set on requests.
+	 * @return This object (for method chaining).
+	 */
+	public RestClientBuilder headers(Map<String,Object> headers) {
+		if (headers != null)
+			for (Map.Entry<String,Object> e : headers.entrySet())
+				header(e.getKey(), e.getValue());
+		return this;
+	}
+
+	/**
 	 * Sets the value for the <code>Accept</code> request header.
 	 *
 	 * <p>
@@ -2347,6 +2360,12 @@ public class RestClientBuilder extends BeanContextBuilder {
 	}
 
 	@Override /* BeanContextBuilder */
+	public RestClientBuilder debug(boolean value) {
+		super.debug(value);
+		return this;
+	}
+
+	@Override /* BeanContextBuilder */
 	public <T> RestClientBuilder example(Class<T> c, T o) {
 		super.example(c, o);
 		return this;
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnection.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnection.java
index bcfdbd3..f3ea773 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnection.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockHttpClientConnection.java
@@ -79,8 +79,8 @@ public class MockHttpClientConnection implements HttpClientConnection {
 	public void sendRequestHeader(HttpRequest request) throws HttpException, IOException {
 		try {
 			RequestLine rl = request.getRequestLine();
-			req = c.request(rl.getMethod(), rl.getUri(), null);
-			for (Header h : request.getAllHeaders())
+			req = c.request(rl.getMethod(), rl.getUri(), null, null);
+			for (Header h : request.getAllHeaders()) 
 				req.header(h.getName(), h.getValue());
 		} catch (Exception e) {
 			throw new HttpException(e.getMessage(), e);
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockRemoteResource.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockRemoteResource.java
new file mode 100644
index 0000000..4ae5170
--- /dev/null
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/mock/MockRemoteResource.java
@@ -0,0 +1,404 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.client.mock;
+
+import java.util.*;
+
+import org.apache.juneau.json.*;
+import org.apache.juneau.marshall.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.client.*;
+import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * Creates a mocked interface against a REST resource class to use for creating test remote resource interfaces.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * 	<li class='link'>{@doc juneau-rest-server.UnitTesting}
+ * 	<li class='link'>{@doc juneau-rest-client.UnitTesting}
+ * </ul>
+ *
+ * @param <T> The interface class.
+ */
+public class MockRemoteResource<T> {
+
+	private MockRest.Builder mrb = MockRest.create();
+	private final Class<T> intf;
+	private Serializer s = JsonSerializer.DEFAULT;
+	private Parser p = JsonParser.DEFAULT;
+	private boolean debug;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param intf The remote interface.
+	 * @param impl The REST implementation class or bean.
+	 */
+	protected MockRemoteResource(Class<T> intf, Object impl) {
+		this.intf = intf;
+		mrb.impl(impl);
+	}
+
+	/**
+	 * Create a new builder using the specified remote resource interface and REST implementation class.
+	 *
+	 * @param intf The remote interface.
+	 * @param impl The REST implementation class.
+	 * @return A new builder.
+	 */
+	public static <T> MockRemoteResource<T> create(Class<T> intf, Class<?> impl) {
+		return new MockRemoteResource<>(intf, impl);
+	}
+
+	/**
+	 * Create a new builder using the specified remote resource interface and REST implementation bean.
+	 *
+	 * @param intf The remote interface.
+	 * @param impl The REST implementation bean.
+	 * @return A new builder.
+	 */
+	public static <T> MockRemoteResource<T> create(Class<T> intf, Object impl) {
+		return new MockRemoteResource<>(intf, impl);
+	}
+
+	/**
+	 * Constructs a remote proxy interface based on the settings of this builder.
+	 *
+	 * @return A new remote proxy interface.
+	 */
+	public T build() {
+		MockRest mr = mrb.build();
+		return RestClient.create(s, p).debug(debug).mockHttpConnection(mr).headers(mr.getHeaders()).build().getRemoteResource(intf);
+	}
+
+	/**
+	 * Convenience method for getting a remote resource interface.
+	 *
+	 * <p>
+	 * Equivalent to calling the following:
+	 * <p class='bcode w800'>
+	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).build();
+	 * </p>
+	 *
+	 * <p>
+	 * Uses JSON serialization and parsing.
+	 *
+	 * @param intf The remote proxy interface class.
+	 * @param impl The REST implementation class.
+	 * @return A new proxy interface.
+	 */
+	public static <T> T build(Class<T> intf, Class<?> impl) {
+		return create(intf, impl).build();
+	}
+
+	/**
+	 * Convenience method for getting a remote resource interface.
+	 *
+	 * <p>
+	 * Equivalent to calling the following:
+	 * <p class='bcode w800'>
+	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).serializer(s).parser(p).build();
+	 * </p>
+	 *
+	 * @param intf The remote proxy interface class.
+	 * @param impl The REST implementation class.
+	 * @param s
+	 * 	The serializer to use for serializing request bodies.
+	 * 	<br>Can be <jk>null</jk> to force no serializer to be used and no <code>Content-Type</code> header.
+	 * @param p
+	 * 	The parser to use for parsing response bodies.
+	 * 	<br>Can be <jk>null</jk> to force no parser to be used and no <code>Accept</code> header.
+	 * @return A new proxy interface.
+	 */
+	public static <T> T build(Class<T> intf, Class<?> impl, Serializer s, Parser p) {
+		return create(intf, impl).serializer(s).parser(p).build();
+	}
+
+	/**
+	 * Convenience method for getting a remote resource interface.
+	 *
+	 * <p>
+	 * Equivalent to calling the following:
+	 * <p class='bcode w800'>
+	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).marshall(m).build();
+	 * </p>
+	 *
+	 * @param intf The remote proxy interface class.
+	 * @param impl The REST implementation class.
+	 * @param m
+	 * 	The marshall to use for serializing request bodies and parsing response bodies.
+	 * 	<br>Can be <jk>null</jk> to force no serializer or parser to be used and no <code>Accept</code> or <code>Content-Type</code> header.
+	 * @return A new proxy interface.
+	 */
+	public static <T> T build(Class<T> intf, Class<?> impl, Marshall m) {
+		return create(intf, impl).marshall(m).build();
+	}
+
+	/**
+	 * Convenience method for getting a remote resource interface.
+	 *
+	 * <p>
+	 * Equivalent to calling the following:
+	 * <p class='bcode w800'>
+	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).build();
+	 * </p>
+	 *
+	 * <p>
+	 * Uses JSON serialization and parsing.
+	 *
+	 * @param intf The remote proxy interface class.
+	 * @param impl The REST implementation bean.
+	 * @return A new proxy interface.
+	 */
+	public static <T> T build(Class<T> intf, Object impl) {
+		return create(intf, impl).build();
+	}
+
+	/**
+	 * Convenience method for getting a remote resource interface.
+	 *
+	 * <p>
+	 * Equivalent to calling the following:
+	 * <p class='bcode w800'>
+	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).serializer(s).parser(p).build();
+	 * </p>
+	 *
+	 * @param intf The remote proxy interface class.
+	 * @param impl The REST implementation object.
+	 * @param s The serializer to use for serializing request bodies.
+	 * @param p The parser to use for parsing response bodies.
+	 * @return A new proxy interface.
+	 */
+	public static <T> T build(Class<T> intf, Object impl, Serializer s, Parser p) {
+		return create(intf, impl).serializer(s).parser(p).build();
+	}
+
+	/**
+	 * Convenience method for getting a remote resource interface.
+	 *
+	 * <p>
+	 * Equivalent to calling the following:
+	 * <p class='bcode w800'>
+	 * 	MockRemoteResource.<jsf>create</jsf>(intf, impl).marshall(m).build();
+	 * </p>
+	 *
+	 * @param intf The remote proxy interface class.
+	 * @param impl The REST implementation object.
+	 * @param m The marshall to use for serializing request bodies and parsing response bodies.
+	 * @return A new proxy interface.
+	 */
+	public static <T> T build(Class<T> intf, Object impl, Marshall m) {
+		return create(intf, impl).marshall(m).build();
+	}
+
+	/**
+	 * Enable debug mode.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> debug() {
+		mrb.debug();
+		this.debug = true;
+		return this;
+	}
+
+	/**
+	 * Adds a header to every request.
+	 *
+	 * @param name The header name.
+	 * @param value
+	 * 	The header value.
+	 * 	<br>Can be <jk>null</jk> (will be skipped).
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> header(String name, Object value) {
+		mrb.header(name, value);
+		return this;
+	}
+
+	/**
+	 * Adds the specified headers to every request.
+	 *
+	 * @param value
+	 * 	The header values.
+	 * 	<br>Can be <jk>null</jk> (existing values will be cleared).
+	 * 	<br><jk>null</jk> null map values will be ignored.
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> headers(Map<String,Object> value) {
+		mrb.headers(value);
+		return this;
+	}
+
+	/**
+	 * Adds an <code>Accept</code> header to every request.
+	 *
+	 * @param value The <code>Accept/code> header value.
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> accept(String value) {
+		mrb.accept(value);
+		return this;
+	}
+
+	/**
+	 * Adds a <code>Content-Type</code> header to every request.
+	 *
+	 * @param value The <code>Content-Type</code> header value.
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> contentType(String value) {
+		mrb.contentType(value);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> json() {
+		marshall(Json.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json+simple"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> simpleJson() {
+		marshall(SimpleJson.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/xml"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> xml() {
+		marshall(Xml.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/html"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> html() {
+		marshall(Html.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/plain"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> plainText() {
+		marshall(PlainText.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"octal/msgpack"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> msgpack() {
+		marshall(MsgPack.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/uon"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> uon() {
+		marshall(Uon.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/x-www-form-urlencoded"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> urlEnc() {
+		marshall(UrlEncoding.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/openapi"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> openapi() {
+		marshall(OpenApi.DEFAULT);
+		return this;
+	}
+
+	/**
+	 * Associates the specified {@link Marshall} with this client.
+	 *
+	 * <p>
+	 * This is shorthand for calling <code>serializer(x)</code> and <code>parser(x)</code> using the inner
+	 * serializer and parser of the marshall object.
+	 *
+	 * @param value
+	 * 	The marshall to use for serializing and parsing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remote the existing serializer/parser).
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> marshall(Marshall value) {
+		if (value != null)
+			serializer(value.getSerializer()).parser(value.getParser());
+		else
+			serializer(null).parser(null);
+		return this;
+	}
+
+	/**
+	 * Associates the specified {@link Serializer} with this client.
+	 *
+	 * @param value
+	 * 	The serializer to use for serializing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remote the existing serializer).
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> serializer(Serializer value) {
+		this.s = value;
+		contentType(value == null ? null : value.getPrimaryMediaType().toString());
+		return this;
+	}
+
+	/**
+	 * Associates the specified {@link Parser} with this client.
+	 *
+	 * @param value
+	 * 	The parser to use for parsing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk> (will remote the existing parser).
+	 * @return This object (for method chaining).
+	 */
+	public MockRemoteResource<T> parser(Parser value) {
+		this.p = value;
+		accept(value == null ? null : value.getPrimaryMediaType().toString());
+		return this;
+	}
+}
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
index 2aa7581..4946425 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/BodyAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.marshall.*;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
@@ -115,7 +115,6 @@ public class BodyAnnotationTest {
 			return IOUtils.read(b);
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
 
 	@RemoteResource
 	public static interface A01 {
@@ -131,7 +130,7 @@ public class BodyAnnotationTest {
 		String postA10(@Body NameValuePairs b);
 	}
 
-	private static A01 a01 = RestClient.create().mockHttpConnection(a).serializer(JsonSerializer.class).build().getRemoteResource(A01.class);
+	private static A01 a01 = MockRemoteResource.create(A01.class, A.class).parser(null).build();
 
 	@Test
 	public void a01_int() throws Exception {
@@ -241,8 +240,6 @@ public class BodyAnnotationTest {
 			return b;
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
-
 	@RemoteResource
 	public static interface B01 {
 		String postB01(@Body int b);
@@ -257,7 +254,7 @@ public class BodyAnnotationTest {
 		String postB10(@Body NameValuePairs b);
 	}
 
-	private static B01 b01 = RestClient.create().openapi().mockHttpConnection(b).build().getRemoteResource(B01.class);
+	private static B01 b01 = MockRemoteResource.create(B01.class, B.class).marshall(OpenApi.DEFAULT).contentType(null).build();
 
 	@Test
 	public void b01_int() throws Exception {
@@ -368,8 +365,6 @@ public class BodyAnnotationTest {
 			return b;
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
-
 	@RemoteResource
 	public static interface C01 {
 		String postC01(@Body int b);
@@ -384,7 +379,7 @@ public class BodyAnnotationTest {
 		String postC10(@Body NameValuePairs b);
 	}
 
-	private static C01 c01 = RestClient.create().mockHttpConnection(c).contentType("text/foo").build().getRemoteResource(C01.class);
+	private static C01 c01 = MockRemoteResource.create(C01.class, C.class).serializer(null).contentType("text/foo").build();
 
 	@Test
 	public void c01_int() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
index 987c5e4..4428c6d 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/EndToEndInterfaceTest.java
@@ -24,8 +24,10 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
+import org.apache.juneau.marshall.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.rest.exception.*;
 import org.apache.juneau.rest.helper.*;
 import org.apache.juneau.rest.mock.*;
@@ -80,8 +82,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static MockRest a = MockRest.create(A.class);
-	private static IA ia = RestClient.create().json().mockHttpConnection(a).build().getRemoteResource(IA.class);
+	private static IA ia = MockRemoteResource.build(IA.class, A.class, Json.DEFAULT);
 
 	@Test
 	public void a01_splitAnnotations_Body() throws Exception {
@@ -135,8 +136,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static MockRest b = MockRest.create(B.class);
-	private static IB ib = RestClient.create().json().mockHttpConnection(b).build().getRemoteResource(IB.class);
+	private static IB ib = MockRemoteResource.build(IB.class, B.class);
 
 	@Test
 	public void b01_combinedAnnotations_Body() throws Exception {
@@ -207,7 +207,7 @@ public class EndToEndInterfaceTest {
 		@Override public UseProxy useProxy() { return UseProxy.INSTANCE; }
 	}
 
-	private static IC ic = RestClient.create().json().disableRedirectHandling().mockHttpConnection(MockRest.create(C.class)).build().getRemoteResource(IC.class);
+	private static IC ic = RestClient.create().json().disableRedirectHandling().mockHttpConnection(MockRest.create(C.class).build()).build().getRemoteResource(IC.class);
 
 	@Test
 	public void c01_standardResponses_Ok() throws Exception {
@@ -326,7 +326,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static ID id = RestClient.create().json().mockHttpConnection(MockRest.create(D.class)).build().getRemoteResource(ID.class);
+	private static ID id = MockRemoteResource.build(ID.class, D.class);
 
 	@Test
 	public void d01_StreamResource() throws Exception {
@@ -344,7 +344,7 @@ public class EndToEndInterfaceTest {
 		assertEquals("text/foo", r.getMediaType().toString());
 	}
 
-	private static ID id2 = RestClient.create().mockHttpConnection(MockRest.create(D.class)).build().getRemoteResource(ID.class);
+	private static ID id2 = MockRemoteResource.build(ID.class, D.class);
 
 	@Test
 	public void d03_StreamResource_noMediaTypes() throws Exception {
@@ -539,7 +539,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static IE iea = RestClient.create().json().mockHttpConnection(MockRest.create(EA.class)).build().getRemoteResource(IE.class);
+	private static IE iea = MockRemoteResource.build(IE.class, EA.class);
 
 	@Test
 	public void ea01_badRequest() {
@@ -974,7 +974,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static IE ieb = RestClient.create().json().mockHttpConnection(MockRest.create(EB.class)).build().getRemoteResource(IE.class);
+	private static IE ieb = MockRemoteResource.build(IE.class, EB.class);
 
 	@Test
 	public void eb01_badRequest() {
@@ -1451,7 +1451,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static IF ifa = RestClient.create().json().mockHttpConnection(MockRest.create(F.class)).build().getRemoteResource(IF.class);
+	private static IF ifa = MockRemoteResource.build(IF.class, F.class);
 
 	@Test
 	public void fa01_badRequest() {
@@ -1607,7 +1607,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static IG ig = RestClient.create().json().mockHttpConnection(MockRest.create(G.class)).build().getRemoteResource(IG.class);
+	private static IG ig = MockRemoteResource.build(IG.class, G.class);
 
 	@Test
 	public void g01_reader() throws Exception {
@@ -1635,7 +1635,7 @@ public class EndToEndInterfaceTest {
 		}
 	}
 
-	private static IH ih = RestClient.create().json().disableRedirectHandling().mockHttpConnection(MockRest.create(H.class)).build().getRemoteResource(IH.class);
+	private static IH ih = RestClient.create().json().disableRedirectHandling().mockHttpConnection(MockRest.create(H.class).build()).build().getRemoteResource(IH.class);
 
 	@Test
 	public void h01_seeOtherRoot() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
index e26b4e6..e131d74 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
@@ -62,7 +62,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
 
 	@RemoteResource
 	public static interface AR {
@@ -88,7 +87,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="a") String postA09b(@FormData NameValuePairs b);
 	}
 
-	private static AR ar = RestClient.create().mockHttpConnection(a).build().getRemoteResource(AR.class);
+	private static AR ar = MockRemoteResource.build(AR.class, A.class, null);
 
 	@Test
 	public void a01_int() throws Exception {
@@ -182,7 +181,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
 
 	@RemoteResource
 	public static interface BR {
@@ -192,7 +190,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/") String postB04(@FormData(name="x",_default="",allowEmptyValue=true) String b);
 	}
 
-	private static BR br = RestClient.create().mockHttpConnection(b).build().getRemoteResource(BR.class);
+	private static BR br = MockRemoteResource.build(BR.class, B.class, null);
 
 	@Test
 	public void b01a_default() throws Exception {
@@ -250,7 +248,6 @@ public class FormDataAnnotationTest {
 			return b;
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
 
 	@RemoteResource
 	public static interface CR {
@@ -270,7 +267,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/b") String postC07b(@FormData(name="x",collectionFormat="uon") String...b);
 	}
 
-	private static CR cr = RestClient.create().mockHttpConnection(c).build().getRemoteResource(CR.class);
+	private static CR cr = MockRemoteResource.build(CR.class, C.class, null);
 
 	@Test
 	public void c01a_default() throws Exception {
@@ -342,7 +339,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
 
 	@RemoteResource
 	public static interface DR {
@@ -391,7 +387,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/") String postC16c(@FormData(name="x",minimum="1",maximum="10",exclusiveMinimum=true,exclusiveMaximum=true) Byte b);
 	}
 
-	private static DR dr = RestClient.create().mockHttpConnection(d).build().getRemoteResource(DR.class);
+	private static DR dr = MockRemoteResource.build(DR.class, D.class, null);
 
 	@Test
 	public void d01a_int_defaultExclusive() throws Exception {
@@ -717,7 +713,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
 
 	@RemoteResource
 	public static interface ER {
@@ -729,7 +724,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/") String postE06(@FormData(name="x",items=@Items(collectionFormat="pipes",uniqueItems=true)) String[]...b);
 	}
 
-	private static ER er = RestClient.create().mockHttpConnection(e).build().getRemoteResource(ER.class);
+	private static ER er = MockRemoteResource.build(ER.class, E.class, null);
 
 	@Test
 	public void e01_minMax() throws Exception {
@@ -777,7 +772,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest f = MockRest.create(F.class);
 
 	@RemoteResource
 	public static interface FR {
@@ -789,7 +783,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/") String postF06(@FormData(name="x",collectionFormat="pipes",items=@Items(pattern="foo\\d{1,3}")) String...b);
 	}
 
-	private static FR fr = RestClient.create().mockHttpConnection(f).build().getRemoteResource(FR.class);
+	private static FR fr = MockRemoteResource.build(FR.class, F.class, null);
 
 	@Test
 	public void f01_minMaxLength() throws Exception {
@@ -843,7 +837,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest g = MockRest.create(G.class);
 
 	@RemoteResource
 	public static interface GR {
@@ -863,7 +856,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/") String postG16(@FormData(name="x",multipleOf="2") Byte b);
 	}
 
-	private static GR gr = RestClient.create().mockHttpConnection(g).build().getRemoteResource(GR.class);
+	private static GR gr = MockRemoteResource.build(GR.class, G.class, null);
 
 	@Test
 	public void g01_multipleOf_int() throws Exception {
@@ -947,7 +940,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest h = MockRest.create(H.class);
 
 	@RemoteResource
 	public static interface HR {
@@ -956,7 +948,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/") String postH03(@FormData(name="x",required=true) String b);
 	}
 
-	private static HR hr = RestClient.create().mockHttpConnection(h).build().getRemoteResource(HR.class);
+	private static HR hr = MockRemoteResource.build(HR.class, H.class, null);
 
 	@Test
 	public void h01_required_default() throws Exception {
@@ -983,7 +975,6 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest i = MockRest.create(I.class);
 
 	@RemoteResource
 	public static interface IR {
@@ -992,7 +983,7 @@ public class FormDataAnnotationTest {
 		@RemoteMethod(path="/") String postI03(@FormData(name="x",skipIfEmpty=true) String b);
 	}
 
-	private static IR ir = RestClient.create().mockHttpConnection(i).build().getRemoteResource(IR.class);
+	private static IR ir = MockRemoteResource.build(IR.class, I.class, null);
 
 	@Test
 	public void h01_skipIfEmpty_default() throws Exception {
@@ -1018,14 +1009,13 @@ public class FormDataAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest j = MockRest.create(J.class);
 
 	@RemoteResource
 	public static interface JR {
 		@RemoteMethod(path="/") String postJ01(@FormData(name="x",serializer=XPartSerializer.class) String b);
 	}
 
-	private static JR jr = RestClient.create().mockHttpConnection(j).build().getRemoteResource(JR.class);
+	private static JR jr = MockRemoteResource.build(JR.class, J.class, null);
 
 	@Test
 	public void j01_serializer() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
index 8b1eeaf..4fbc731 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
@@ -25,7 +25,7 @@ import org.apache.juneau.http.annotation.Header;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
@@ -60,7 +60,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
 
 	@RemoteResource
 	public static interface A01 {
@@ -82,7 +81,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="a") String getA09b(@Header NameValuePairs b);
 	}
 
-	private static A01 a01 = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A01.class);
+	private static A01 a01 = MockRemoteResource.build(A01.class, A.class, null);
 
 	@Test
 	public void a01_int() throws Exception {
@@ -161,7 +160,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
 
 	@RemoteResource
 	public static interface BR {
@@ -171,7 +169,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/") String getB04(@Header(name="x",_default="",allowEmptyValue=true) String b);
 	}
 
-	private static BR br = RestClient.create().mockHttpConnection(b).build().getRemoteResource(BR.class);
+	private static BR br = MockRemoteResource.build(BR.class, B.class, null);
 
 	@Test
 	public void b01a_default() throws Exception {
@@ -226,7 +224,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
 
 	@RemoteResource
 	public static interface CR {
@@ -239,7 +236,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/a") String getC07(@Header(name="x",collectionFormat="uon") String...b);
 	}
 
-	private static CR cr = RestClient.create().mockHttpConnection(c).build().getRemoteResource(CR.class);
+	private static CR cr = MockRemoteResource.build(CR.class, C.class, null);
 
 	@Test
 	public void c01a_default() throws Exception {
@@ -283,7 +280,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
 
 	@RemoteResource
 	public static interface DR {
@@ -331,7 +327,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/") String getC16c(@Header(name="x",minimum="1",maximum="10",exclusiveMinimum=true,exclusiveMaximum=true) Byte b);
 	}
 
-	private static DR dr = RestClient.create().mockHttpConnection(d).build().getRemoteResource(DR.class);
+	private static DR dr = MockRemoteResource.build(DR.class, D.class, null);
 
 	@Test
 	public void d01a_int_defaultExclusive() throws Exception {
@@ -658,7 +654,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
 
 	@RemoteResource
 	public static interface ER {
@@ -670,7 +665,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/") String getE06(@Header(name="x",items=@Items(collectionFormat="pipes",uniqueItems=true)) String[]...b);
 	}
 
-	private static ER er = RestClient.create().mockHttpConnection(e).build().getRemoteResource(ER.class);
+	private static ER er = MockRemoteResource.build(ER.class, E.class, null);
 
 	@Test
 	public void e01_minMax() throws Exception {
@@ -719,7 +714,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest f = MockRest.create(F.class);
 
 	@RemoteResource
 	public static interface FR {
@@ -731,7 +725,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/") String getF06(@Header(name="x",collectionFormat="pipes",items=@Items(pattern="foo\\d{1,3}")) String...b);
 	}
 
-	private static FR fr = RestClient.create().mockHttpConnection(f).build().getRemoteResource(FR.class);
+	private static FR fr = MockRemoteResource.build(FR.class, F.class, null);
 
 	@Test
 	public void f01_minMaxLength() throws Exception {
@@ -786,7 +780,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest g = MockRest.create(G.class);
 
 	@RemoteResource
 	public static interface GR {
@@ -806,7 +799,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/") String getG16(@Header(name="x",multipleOf="2") Byte b);
 	}
 
-	private static GR gr = RestClient.create().mockHttpConnection(g).build().getRemoteResource(GR.class);
+	private static GR gr = MockRemoteResource.build(GR.class, G.class, null);
 
 	@Test
 	public void g01_multipleOf_int() throws Exception {
@@ -891,7 +884,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest h = MockRest.create(H.class);
 
 	@RemoteResource
 	public static interface HR {
@@ -900,7 +892,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/") String getH03(@Header(name="x",required=true) String b);
 	}
 
-	private static HR hr = RestClient.create().mockHttpConnection(h).build().getRemoteResource(HR.class);
+	private static HR hr = MockRemoteResource.build(HR.class, H.class, null);
 
 	@Test
 	public void h01_required_default() throws Exception {
@@ -928,7 +920,6 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest i = MockRest.create(I.class);
 
 	@RemoteResource
 	public static interface IR {
@@ -937,7 +928,7 @@ public class HeaderAnnotationTest {
 		@RemoteMethod(path="/") String getI03(@Header(name="x",skipIfEmpty=true) String b);
 	}
 
-	private static IR ir = RestClient.create().mockHttpConnection(i).build().getRemoteResource(IR.class);
+	private static IR ir = MockRemoteResource.build(IR.class, I.class, null);
 
 	@Test
 	public void h01_skipIfEmpty_default() throws Exception {
@@ -964,14 +955,13 @@ public class HeaderAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest j = MockRest.create(J.class);
 
 	@RemoteResource
 	public static interface JR {
 		@RemoteMethod(path="/") String getJ01(@Header(name="x",serializer=XPartSerializer.class) String b);
 	}
 
-	private static JR jr = RestClient.create().mockHttpConnection(j).build().getRemoteResource(JR.class);
+	private static JR jr = MockRemoteResource.build(JR.class, J.class, null);
 
 	@Test
 	public void j01_serializer() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
index 7d52bf3..2fe42f2 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
@@ -25,7 +25,7 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
@@ -59,7 +59,6 @@ public class PathAnnotationTest {
 			return x.toString();
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
 
 	@RemoteResource
 	public static interface A01 {
@@ -81,7 +80,7 @@ public class PathAnnotationTest {
 		@RemoteMethod(path="a/{x}") String getA09b(@Path NameValuePairs b);
 	}
 
-	private static A01 a01 = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A01.class);
+	private static A01 a01 = MockRemoteResource.build(A01.class, A.class, null);
 
 	@Test
 	public void a01_int() throws Exception {
@@ -160,7 +159,6 @@ public class PathAnnotationTest {
 			return x.toString();
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
 
 	@RemoteResource
 	public static interface CR {
@@ -173,7 +171,7 @@ public class PathAnnotationTest {
 		@RemoteMethod(path="/a/{x}") String getC07(@Path(name="x",collectionFormat="uon") String...b);
 	}
 
-	private static CR cr = RestClient.create().mockHttpConnection(c).build().getRemoteResource(CR.class);
+	private static CR cr = MockRemoteResource.build(CR.class, C.class, null);
 
 	@Test
 	public void c01a_default() throws Exception {
@@ -217,7 +215,6 @@ public class PathAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
 
 	@RemoteResource
 	public static interface DR {
@@ -265,7 +262,7 @@ public class PathAnnotationTest {
 		@RemoteMethod(path="/a/{x}") String getC16c(@Path(name="x",minimum="1",maximum="10",exclusiveMinimum=true,exclusiveMaximum=true) Byte b);
 	}
 
-	private static DR dr = RestClient.create().mockHttpConnection(d).build().getRemoteResource(DR.class);
+	private static DR dr = MockRemoteResource.build(DR.class, D.class, null);
 
 	@Test
 	public void d01a_int_defaultExclusive() throws Exception {
@@ -574,7 +571,6 @@ public class PathAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
 
 	@RemoteResource
 	public static interface ER {
@@ -586,7 +582,7 @@ public class PathAnnotationTest {
 		@RemoteMethod(path="/{x}") String getE06(@Path(name="x",items=@Items(collectionFormat="pipes",uniqueItems=true)) String[]...b);
 	}
 
-	private static ER er = RestClient.create().mockHttpConnection(e).build().getRemoteResource(ER.class);
+	private static ER er = MockRemoteResource.build(ER.class, E.class, null);
 
 	@Test
 	public void e01_minMax() throws Exception {
@@ -635,7 +631,6 @@ public class PathAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest f = MockRest.create(F.class);
 
 	@RemoteResource
 	public static interface FR {
@@ -647,7 +642,7 @@ public class PathAnnotationTest {
 		@RemoteMethod(path="/{x}") String getF06(@Path(name="x",collectionFormat="pipes",items=@Items(pattern="foo\\d{1,3}")) String...b);
 	}
 
-	private static FR fr = RestClient.create().mockHttpConnection(f).build().getRemoteResource(FR.class);
+	private static FR fr = MockRemoteResource.build(FR.class, F.class, null);
 
 	@Test
 	public void f01_minMaxLength() throws Exception {
@@ -699,7 +694,6 @@ public class PathAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest g = MockRest.create(G.class);
 
 	@RemoteResource
 	public static interface GR {
@@ -719,7 +713,7 @@ public class PathAnnotationTest {
 		@RemoteMethod(path="/{x}") String getG16(@Path(name="x",multipleOf="2") Byte b);
 	}
 
-	private static GR gr = RestClient.create().mockHttpConnection(g).build().getRemoteResource(GR.class);
+	private static GR gr = MockRemoteResource.build(GR.class, G.class, null);
 
 	@Test
 	public void g01_multipleOf_int() throws Exception {
@@ -804,14 +798,13 @@ public class PathAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest h = MockRest.create(H.class);
 
 	@RemoteResource
 	public static interface HR {
 		@RemoteMethod(path="/{x}") String getH01(@Path(name="x") String b);
 	}
 
-	private static HR hr = RestClient.create().mockHttpConnection(h).build().getRemoteResource(HR.class);
+	private static HR hr = MockRemoteResource.build(HR.class, H.class);
 
 	@Test
 	public void h01_required_default() throws Exception {
@@ -830,14 +823,13 @@ public class PathAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest j = MockRest.create(J.class);
 
 	@RemoteResource
 	public static interface JR {
 		@RemoteMethod(path="/{x}") String getJ01(@Path(name="x",serializer=XPartSerializer.class) String b);
 	}
 
-	private static JR jr = RestClient.create().mockHttpConnection(j).build().getRemoteResource(JR.class);
+	private static JR jr = MockRemoteResource.build(JR.class, J.class, null);
 
 	@Test
 	public void j01_serializer() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
index 086b65f..61697f4 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
@@ -61,7 +61,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
 
 	@RemoteResource
 	public static interface A01 {
@@ -87,7 +86,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="a") String getA09b(@Query NameValuePairs b);
 	}
 
-	private static A01 a01 = RestClient.create().mockHttpConnection(a).build().getRemoteResource(A01.class);
+	private static A01 a01 = MockRemoteResource.build(A01.class, A.class, null);
 
 	@Test
 	public void a01_int() throws Exception {
@@ -181,7 +180,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
 
 	@RemoteResource
 	public static interface BR {
@@ -191,7 +189,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/") String getB04(@Query(name="x",_default="",allowEmptyValue=true) String b);
 	}
 
-	private static BR br = RestClient.create().mockHttpConnection(b).build().getRemoteResource(BR.class);
+	private static BR br = MockRemoteResource.build(BR.class, B.class, null);
 
 	@Test
 	public void b01a_default() throws Exception {
@@ -249,7 +247,6 @@ public class QueryAnnotationTest {
 			return new StringReader(req.getQueryString());
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
 
 	@RemoteResource
 	public static interface CR {
@@ -269,7 +266,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/b") String getC07b(@Query(name="x",collectionFormat="uon") String...b);
 	}
 
-	private static CR cr = RestClient.create().mockHttpConnection(c).build().getRemoteResource(CR.class);
+	private static CR cr = MockRemoteResource.build(CR.class, C.class, null);
 
 	@Test
 	public void c01a_default() throws Exception {
@@ -341,7 +338,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
 
 	@RemoteResource
 	public static interface DR {
@@ -389,7 +385,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/") String getC16c(@Query(name="x",minimum="1",maximum="10",exclusiveMinimum=true,exclusiveMaximum=true) Byte b);
 	}
 
-	private static DR dr = RestClient.create().mockHttpConnection(d).build().getRemoteResource(DR.class);
+	private static DR dr = MockRemoteResource.build(DR.class, D.class, null);
 
 	@Test
 	public void d01a_int_defaultExclusive() throws Exception {
@@ -715,7 +711,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
 
 	@RemoteResource
 	public static interface ER {
@@ -727,7 +722,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/") String getE06(@Query(name="x",items=@Items(collectionFormat="pipes",uniqueItems=true)) String[]...b);
 	}
 
-	private static ER er = RestClient.create().mockHttpConnection(e).build().getRemoteResource(ER.class);
+	private static ER er = MockRemoteResource.build(ER.class, E.class, null);
 
 	@Test
 	public void e01_minMax() throws Exception {
@@ -775,7 +770,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest f = MockRest.create(F.class);
 
 	@RemoteResource
 	public static interface FR {
@@ -787,7 +781,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/") String getF06(@Query(name="x",collectionFormat="pipes",items=@Items(pattern="foo\\d{1,3}")) String...b);
 	}
 
-	private static FR fr = RestClient.create().mockHttpConnection(f).build().getRemoteResource(FR.class);
+	private static FR fr = MockRemoteResource.build(FR.class, F.class, null);
 
 	@Test
 	public void f01_minMaxLength() throws Exception {
@@ -841,7 +835,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest g = MockRest.create(G.class);
 
 	@RemoteResource
 	public static interface GR {
@@ -861,7 +854,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/") String getG16(@Query(name="x",multipleOf="2") Byte b);
 	}
 
-	private static GR gr = RestClient.create().mockHttpConnection(g).build().getRemoteResource(GR.class);
+	private static GR gr = MockRemoteResource.build(GR.class, G.class, null);
 
 	@Test
 	public void g01_multipleOf_int() throws Exception {
@@ -945,7 +938,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest h = MockRest.create(H.class);
 
 	@RemoteResource
 	public static interface HR {
@@ -954,7 +946,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/") String getH03(@Query(name="x",required=true) String b);
 	}
 
-	private static HR hr = RestClient.create().mockHttpConnection(h).build().getRemoteResource(HR.class);
+	private static HR hr = MockRemoteResource.build(HR.class, H.class, null);
 
 	@Test
 	public void h01_required_default() throws Exception {
@@ -981,7 +973,6 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest i = MockRest.create(I.class);
 
 	@RemoteResource
 	public static interface IR {
@@ -990,7 +981,7 @@ public class QueryAnnotationTest {
 		@RemoteMethod(path="/") String getI03(@Query(name="x",skipIfEmpty=true) String b);
 	}
 
-	private static IR ir = RestClient.create().mockHttpConnection(i).build().getRemoteResource(IR.class);
+	private static IR ir = MockRemoteResource.build(IR.class, I.class, null);
 
 	@Test
 	public void h01_skipIfEmpty_default() throws Exception {
@@ -1016,14 +1007,13 @@ public class QueryAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest j = MockRest.create(J.class);
 
 	@RemoteResource
 	public static interface JR {
 		@RemoteMethod(path="/") String getJ01(@Query(name="x",serializer=XPartSerializer.class) String b);
 	}
 
-	private static JR jr = RestClient.create().mockHttpConnection(j).build().getRemoteResource(JR.class);
+	private static JR jr = MockRemoteResource.build(JR.class, J.class, null);
 
 	@Test
 	public void j01_serializer() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
index db1cc80..ea44020 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteMethodAnnotationTest.java
@@ -21,10 +21,10 @@ import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.http.annotation.Response;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
+import org.apache.juneau.marshall.*;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.junit.*;
 import org.junit.runners.*;
 
@@ -61,8 +61,6 @@ public class RemoteMethodAnnotationTest {
 			return "qux";
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
-	private static RestClient ra = RestClient.create().mockHttpConnection(a).build();
 
 	@RemoteResource
 	public static interface A01 {
@@ -75,7 +73,7 @@ public class RemoteMethodAnnotationTest {
 
 	@Test
 	public void a01_inferredMethodsAndPaths() throws Exception {
-		A01 t = ra.getRemoteResource(A01.class);
+		A01 t = MockRemoteResource.build(A01.class, A.class, null);
 		assertEquals("foo", t.doGet());
 		assertEquals("foo", t.doGET());
 		assertEquals("qux", t.doFoo());
@@ -111,8 +109,6 @@ public class RemoteMethodAnnotationTest {
 			return "qux";
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
-	private static RestClient rb = RestClient.create().mockHttpConnection(b).build();
 
 	@RemoteResource
 	public static interface B01 {
@@ -126,7 +122,7 @@ public class RemoteMethodAnnotationTest {
 
 	@Test
 	public void b01_returnTypes() throws Exception {
-		B01 t = rb.getRemoteResource(B01.class);
+		B01 t = MockRemoteResource.build(B01.class, B.class, null);
 		t.b01();
 		assertEquals("foo", t.b02());
 		assertEquals("bar", IOUtils.read(t.b02a().getEntity().getContent()));
@@ -146,8 +142,6 @@ public class RemoteMethodAnnotationTest {
 			return body;
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
-	private static RestClient rc = RestClient.create().mockHttpConnection(c).simpleJson().build();
 
 	@RemoteResource
 	public static interface C01 {
@@ -167,7 +161,7 @@ public class RemoteMethodAnnotationTest {
 
 	@Test
 	public void c01_returnTypes_json() throws Exception {
-		C01 t = rc.getRemoteResource(C01.class);
+		C01 t = MockRemoteResource.build(C01.class, C.class, Json.DEFAULT);
 		assertEquals("foo", t.c01a("foo"));
 		assertEquals("'foo'", IOUtils.read(t.c01b("foo").getEntity().getContent()));
 		assertEquals("'foo'", IOUtils.read(t.c01c("foo")));
@@ -187,8 +181,6 @@ public class RemoteMethodAnnotationTest {
 			return body;
 		}
 	}
-	private static MockRest d = MockRest.create(D.class, true);
-	private static RestClient rd = RestClient.create().debug().mockHttpConnection(d).build();
 
 	@RemoteResource
 	public static interface D01 {
@@ -208,7 +200,7 @@ public class RemoteMethodAnnotationTest {
 
 	@Test
 	public void d01_returnTypes_partSerialization() throws Exception {
-		D01 t = rd.getRemoteResource(D01.class);
+		D01 t = MockRemoteResource.build(D01.class, D.class, OpenApi.DEFAULT);
 		assertEquals("foo", t.d01a("foo"));
 		assertEquals("foo", IOUtils.read(t.d01b("foo").getEntity().getContent()));
 		assertEquals("foo", IOUtils.read(t.d01c("foo")));
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
index bd8edac..8d0b2e7 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RemoteResourceAnnotationTest.java
@@ -16,6 +16,7 @@ import static org.junit.Assert.*;
 
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.rest.mock.*;
 import org.junit.*;
 import org.junit.runners.*;
@@ -49,8 +50,7 @@ public class RemoteResourceAnnotationTest {
 			return "foo";
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
-	private static RestClient ra = RestClient.create().mockHttpConnection(a).build();
+	private static MockRest a = MockRest.build(A.class, null);
 
 	@RemoteResource
 	public static interface A01a {
@@ -64,7 +64,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a01_noPath() throws Exception {
-		A01a t = ra.getRemoteResource(A01a.class);
+		A01a t = MockRemoteResource.build(A01a.class, A.class, null);
 		assertEquals("foo", t.a01());
 		assertEquals("foo", t.a01a());
 		assertEquals("foo", t.a01b());
@@ -82,7 +82,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a02a_normalPath() throws Exception {
-		A02a t = ra.getRemoteResource(A02a.class);
+		A02a t = MockRemoteResource.build(A02a.class, A.class, null);
 		assertEquals("foo", t.a02());
 		assertEquals("foo", t.a02a());
 		assertEquals("foo", t.a02b());
@@ -100,7 +100,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a02b_normalPathWithSlashes() throws Exception {
-		A02b t = ra.getRemoteResource(A02b.class);
+		A02b t = MockRemoteResource.build(A02b.class, A.class, null);
 		assertEquals("foo", t.a02());
 		assertEquals("foo", t.a02a());
 		assertEquals("foo", t.a02b());
@@ -138,7 +138,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a03a_normalPath() throws Exception {
-		A03a t = ra.getRemoteResource(A03a.class);
+		A03a t = MockRemoteResource.build(A03a.class, A.class, null);
 		assertEquals("foo", t.a03());
 		assertEquals("foo", t.a03a());
 		assertEquals("foo", t.a03b());
@@ -156,7 +156,7 @@ public class RemoteResourceAnnotationTest {
 
 	@Test
 	public void a03b_normalPathWithSlashes() throws Exception {
-		A03b t = ra.getRemoteResource(A03b.class);
+		A03b t = MockRemoteResource.build(A03b.class, A.class, null);
 		assertEquals("foo", t.a03());
 		assertEquals("foo", t.a03a());
 		assertEquals("foo", t.a03b());
@@ -224,7 +224,7 @@ public class RemoteResourceAnnotationTest {
 			return "foo";
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
+	private static MockRest b = MockRest.build(B.class, null);
 	private static RestClient rb = RestClient.create().mockHttpConnection(b).rootUrl("http://localhost/B").build();
 
 	@RemoteResource
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
index aebed4f..3d83abe 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/RequestAnnotationTest.java
@@ -24,8 +24,7 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.apache.juneau.rest.testutils.*;
 import org.junit.*;
 import org.junit.runners.*;
@@ -53,8 +52,6 @@ public class RequestAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
-
 	@Request
 	public static class ARequest {
 		@Body
@@ -80,7 +77,7 @@ public class RequestAnnotationTest {
 		@RemoteMethod(path="/{x}") String post(ARequest req);
 	}
 
-	private static AR ar = RestClient.create().mockHttpConnection(a).build().getRemoteResource(AR.class);
+	private static AR ar = MockRemoteResource.build(AR.class, A.class, null);
 
 	@Test
 	public void a01_basic() throws Exception {
@@ -107,7 +104,6 @@ public class RequestAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
 
 	@Request
 	public abstract static class BRequest {
@@ -145,7 +141,7 @@ public class RequestAnnotationTest {
 		@RemoteMethod(path="/{x}") String post(BRequest req);
 	}
 
-	private static BR br = RestClient.create().mockHttpConnection(b).build().getRemoteResource(BR.class);
+	private static BR br = MockRemoteResource.build(BR.class, B.class, null);
 
 	@Test
 	public void b01_annotationOnParent() throws Exception {
@@ -172,7 +168,6 @@ public class RequestAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
 
 	@Request
 	public interface CRequest {
@@ -210,7 +205,7 @@ public class RequestAnnotationTest {
 		@RemoteMethod(path="/{x}") String post(CRequest req);
 	}
 
-	private static CR cr = RestClient.create().mockHttpConnection(c).build().getRemoteResource(CR.class);
+	private static CR cr = MockRemoteResource.build(CR.class, C.class, null);
 
 	@Test
 	public void c01_annotationOnInterface() throws Exception {
@@ -237,7 +232,6 @@ public class RequestAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
 
 	public static class DRequest {
 		@Body
@@ -263,7 +257,7 @@ public class RequestAnnotationTest {
 		@RemoteMethod(path="/{x}") String post(@Request DRequest req);
 	}
 
-	private static DR dr = RestClient.create().mockHttpConnection(d).build().getRemoteResource(DR.class);
+	private static DR dr = MockRemoteResource.build(DR.class, D.class, null);
 
 	@Test
 	public void d01_annotationOnParameter() throws Exception {
@@ -290,7 +284,6 @@ public class RequestAnnotationTest {
 			return m.toString();
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
 
 	@Request(partSerializer=XPartSerializer.class)
 	public static class ERequest {
@@ -317,7 +310,7 @@ public class RequestAnnotationTest {
 		@RemoteMethod(path="/{x}") String post(ERequest req);
 	}
 
-	private static ER er = RestClient.create().mockHttpConnection(e).build().getRemoteResource(ER.class);
+	private static ER er = MockRemoteResource.build(ER.class, E.class, null);
 
 	@Test
 	public void e01_partSerializer() throws Exception {
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
index 40c12ff..61b6dff 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/ResponseAnnotationTest.java
@@ -21,8 +21,7 @@ import org.apache.juneau.http.annotation.Response;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.client.*;
-import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.client.mock.*;
 import org.junit.*;
 import org.junit.runners.*;
 
@@ -56,7 +55,6 @@ public class ResponseAnnotationTest {
 			return "foo";
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
 
 	@Response
 	public interface AResponse {
@@ -76,7 +74,7 @@ public class ResponseAnnotationTest {
 		@RemoteMethod AResponse get();
 	}
 
-	private static AR ar = RestClient.create().mockHttpConnection(a).build().getRemoteResource(AR.class);
+	private static AR ar = MockRemoteResource.build(AR.class, A.class, null);
 
 	@Test
 	public void a01_basic() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 30cd36c..b758b76 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -3192,7 +3192,7 @@ public final class RestContext extends BeanContext {
 					msgs.addSearchPath(mbl[i] != null ? mbl[i].baseClass : resourceClass, mbl[i].bundlePath);
 			}
 
-			fullPath = (builder.parentContext == null ? "" : (builder.parentContext.fullPath + '/')) + builder.path;
+			fullPath = (builder.parentContext == null ? "" : (builder.parentContext.fullPath + '/')) + (builder.path == null ? "_" : builder.path);
 
 			this.childResources = Collections.synchronizedMap(new LinkedHashMap<String,RestContext>());  // Not unmodifiable on purpose so that children can be replaced.
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
index 58ea9c0..698caba 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
@@ -12,10 +12,13 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.rest.mock;
 
+import java.io.*;
 import java.util.*;
 import java.util.concurrent.*;
 
+import org.apache.juneau.marshall.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.util.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -56,54 +59,356 @@ import org.apache.juneau.utils.*;
  * </ul>
  */
 public class MockRest implements MockHttpConnection {
-	private static Map<Class<?>,RestContext> CONTEXTS = new ConcurrentHashMap<>();
+	private static Map<Class<?>,RestContext> CONTEXTS_DEBUG = new ConcurrentHashMap<>(), CONTEXTS_NORMAL = new ConcurrentHashMap<>();
 
-	private final RestContext rc;
+	private final RestContext ctx;
 
-	private MockRest(Class<?> c, boolean debug) throws Exception {
-		if (! CONTEXTS.containsKey(c)) {
-			Object r = c.newInstance();
-			RestContext rc = RestContext.create(r).logger(debug ? BasicRestLogger.class : NoOpRestLogger.class).build();
-			if (r instanceof RestServlet) {
-				((RestServlet)r).setContext(rc);
-			} else {
-				rc.postInit();
+	/** Requests headers to add to every request. */
+	protected final Map<String,Object> headers;
+
+	/** Debug mode enabled. */
+	protected final boolean debug;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param b Builder.
+	 */
+	protected MockRest(Builder b) {
+		try {
+			debug = b.debug;
+			Class<?> c = b.implClass;
+			Object o = b.implObject;
+			Map<Class<?>,RestContext> contexts = debug ? CONTEXTS_DEBUG : CONTEXTS_NORMAL;
+			if (! contexts.containsKey(c)) {
+				if (o == null)
+					o = c.newInstance();
+				RestContext rc = RestContext.create(o).logger(b.debug ? BasicRestLogger.class : NoOpRestLogger.class).build();
+				if (o instanceof RestServlet) {
+					((RestServlet)o).setContext(rc);
+				} else {
+					rc.postInit();
+				}
+				rc.postInitChildFirst();
+				contexts.put(c, rc);
 			}
-			rc.postInitChildFirst();
-			CONTEXTS.put(c, rc);
+			ctx = contexts.get(c);
+			headers = new LinkedHashMap<>(b.headers);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
 		}
-		rc = CONTEXTS.get(c);
 	}
 
 	/**
-	 * Create a new mock REST interface
+	 * Creates a new builder with no REST implementation.
 	 *
-	 * @param c The REST class.
-	 * @return A new mock interface.
-	 * @throws RuntimeException
-	 * 	For testing conveniences, this method wraps all exceptions in a RuntimeException so that you can easily define mocks as reusable fields.
+	 * @return A new builder.
 	 */
-	public static MockRest create(Class<?> c) throws RuntimeException {
-		return create(c, false);
+	public static Builder create() {
+		return new Builder();
 	}
 
 	/**
-	 * Create a new mock REST interface
+	 * Creates a new builder with the specified REST implementation class.
 	 *
-	 * @param c The REST class.
-	 * @param debug
-	 * 	If <jk>true</jk>, the REST interface will use the {@link BasicRestLogger} for logging.
-	 * 	<br>Otherwise, uses {@link NoOpRestLogger}.
-	 * @return A new mock interface.
-	 * @throws RuntimeException
-	 * 	For testing conveniences, this method wraps all exceptions in a RuntimeException so that you can easily define mocks as reusable fields.
+	 * <p>
+	 * Uses Simple-JSON as the protocol by default.
+	 *
+	 * @param impl
+	 * 	The REST bean class.
+	 * 	<br>Class must have a no-arg constructor.
+	 * 	<br>Use {@link #create(Object)} for already-instantiated REST classes.
+	 * @return A new builder.
 	 */
-	public static MockRest create(Class<?> c, boolean debug) throws RuntimeException {
-		try {
-			return new MockRest(c, debug);
-		} catch (Exception e) {
-			throw new RuntimeException(e);
+	public static Builder create(Class<?> impl) {
+		return create().impl(impl);
+	}
+
+	/**
+	 * Creates a new builder with the specified REST implementation class.
+	 *
+	 * <p>
+	 * Uses Simple-JSON as the protocol by default.
+	 *
+	 * @param impl The REST bean.
+	 * @return A new builder.
+	 */
+	public static Builder create(Object impl) {
+		return create().impl(impl);
+	}
+
+	/**
+	 * Convenience method for creating a MockRest over the specified REST implementation.
+	 *
+	 * <p>
+	 * Equivalent to calling:
+	 * <p class='bpcode w800'>
+	 * 	MockRest.create(impl, SimpleJson.<jsf>DEFAULT</jsf>).build();
+	 * </p>
+	 *
+	 * @param impl The REST bean class.
+	 * @return A new {@link MockRest} object.
+	 */
+	public static MockRest build(Class<?> impl) {
+		return build(impl, SimpleJson.DEFAULT);
+	}
+
+	/**
+	 * Convenience method for creating a MockRest over the specified REST implementation.
+	 *
+	 * <p>
+	 * Equivalent to calling:
+	 * <p class='bpcode w800'>
+	 * 	MockRest.create(impl, SimpleJson.<jsf>DEFAULT</jsf>).build();
+	 * </p>
+	 *
+	 * @param impl The REST bean.
+	 * @return A new {@link MockRest} object.
+	 */
+	public static MockRest build(Object impl) {
+		return build(impl, SimpleJson.DEFAULT);
+	}
+
+	/**
+	 * Convenience method for creating a MockRest over the specified REST implementation.
+	 *
+	 * @param impl The REST bean class.
+	 * @param m
+	 * 	The marshall to use for serializing and parsing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk>.
+	 * @return A new {@link MockRest} object.
+	 */
+	public static MockRest build(Class<?> impl, Marshall m) {
+		Builder b = create().impl(impl);
+		if (m != null)
+			b.accept(m.getParser().getPrimaryMediaType().toString()).contentType(m.getSerializer().getPrimaryMediaType().toString());
+		return b.build();
+	}
+
+	/**
+	 * Convenience method for creating a MockRest over the specified REST implementation.
+	 *
+	 * @param impl The REST bean object.
+	 * @param m
+	 * 	The marshall to use for serializing and parsing HTTP bodies.
+	 * 	<br>Can be <jk>null</jk>.
+	 * @return A new {@link MockRest} object.
+	 */
+	public static MockRest build(Object impl, Marshall m) {
+		Builder b = create().impl(impl);
+		if (m != null)
+			b.accept(m.getParser().getPrimaryMediaType().toString()).contentType(m.getSerializer().getPrimaryMediaType().toString());
+		return b.build();
+	}
+
+	/**
+	 * Returns the headers that were defined in this class.
+	 *
+	 * @return The headers that were defined in this class.  Never <jk>null</jk>.
+	 */
+	public Map<String,Object> getHeaders() {
+		return headers;
+	}
+
+	/**
+	 * Builder class.
+	 */
+	public static class Builder {
+		Class<?> implClass;
+		Object implObject;
+		boolean debug;
+		Map<String,Object> headers = new LinkedHashMap<>();
+
+		/**
+		 * Specifies the REST implementation class.
+		 *
+		 * @param value
+		 * 	The REST implementation class.
+		 * 	<br>Class must have a no-arg constructor.
+		 * @return This object (for method chaining).
+		 */
+		public Builder impl(Class<?> value) {
+			this.implClass = value;
+			return this;
+		}
+
+		/**
+		 * Specifies the REST implementation bean.
+		 *
+		 * @param value
+		 * 	The REST implementation bean.
+		 * @return This object (for method chaining).
+		 */
+		public Builder impl(Object value) {
+			if (value instanceof Class) {
+				this.implClass = (Class<?>)value;
+			} else {
+				this.implObject = value;
+				this.implClass = value.getClass();
+			}
+			return this;
+		}
+
+		/**
+		 * Enable debug mode.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder debug() {
+			this.debug = true;
+			return this;
+		}
+
+		/**
+		 * Adds a header to every request.
+		 *
+		 * @param name The header name.
+		 * @param value
+		 * 	The header value.
+		 * 	<br>Can be <jk>null</jk> (will be skipped).
+		 * @return This object (for method chaining).
+		 */
+		public Builder header(String name, Object value) {
+			this.headers.put(name, value);
+			return this;
+		}
+
+		/**
+		 * Adds the specified headers to every request.
+		 *
+		 * @param value
+		 * 	The header values.
+		 * 	<br>Can be <jk>null</jk> (existing values will be cleared).
+		 * 	<br><jk>null</jk> null map values will be ignored.
+		 * @return This object (for method chaining).
+		 */
+		public Builder headers(Map<String,Object> value) {
+			if (value != null)
+				this.headers.putAll(value);
+			else
+				this.headers.clear();
+			return this;
+		}
+
+		/**
+		 * Adds an <code>Accept</code> header to every request.
+		 *
+		 * @param value The <code>Accept/code> header value.
+		 * @return This object (for method chaining).
+		 */
+		public Builder accept(String value) {
+			return header("Accept", value);
+		}
+
+		/**
+		 * Adds a <code>Content-Type</code> header to every request.
+		 *
+		 * @param value The <code>Content-Type</code> header value.
+		 * @return This object (for method chaining).
+		 */
+		public Builder contentType(String value) {
+			return header("Content-Type", value);
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder json() {
+			return accept("application/json").contentType("application/json");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json+simple"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder simpleJson() {
+			return accept("application/json+simple").contentType("application/json+simple");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/xml"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder xml() {
+			return accept("text/xml").contentType("text/xml");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/html"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder html() {
+			return accept("text/html").contentType("text/html");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/plain"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder plainText() {
+			return accept("text/plain").contentType("text/plain");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"octal/msgpack"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder msgpack() {
+			return accept("octal/msgpack").contentType("octal/msgpack");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/uon"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder uon() {
+			return accept("text/uon").contentType("text/uon");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/x-www-form-urlencoded"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder urlEnc() {
+			return accept("application/x-www-form-urlencoded").contentType("application/x-www-form-urlencoded");
 		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/yaml"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder yaml() {
+			return accept("text/yaml").contentType("text/yaml");
+		}
+
+		/**
+		 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/openapi"</js>.
+		 *
+		 * @return This object (for method chaining).
+		 */
+		public Builder openapi() {
+			return accept("text/openapi").contentType("text/openapi");
+		}
+
+		/**
+		 * Create a new {@link MockRest} object based on the settings on this builder.
+		 *
+		 * @return A new {@link MockRest} object.
+		 */
+		public MockRest build() {
+			return new MockRest(this);
+		}
+
 	}
 
 	/**
@@ -111,13 +416,24 @@ public class MockRest implements MockHttpConnection {
 	 *
 	 * @param method The HTTP method
 	 * @param path The URI path.
-	 * @param body The body of the request.
+	 * @param headers Optional headers to include in the request.
+	 * @param body
+	 * 	The body of the request.
+	 * 	<br>Can be any of the following data types:
+	 * 	<ul>
+	 * 		<li><code><jk>byte</jk>[]</code>
+	 * 		<li>{@link Reader}
+	 * 		<li>{@link InputStream}
+	 * 		<li>{@link CharSequence}
+	 * 	</ul>
+	 * 	Any other types are converted to a string using the <code>toString()</code> method.
 	 * @return A new servlet request.
 	 * @throws Exception
 	 */
 	@Override /* MockHttpConnection */
-	public MockServletRequest request(String method, String path, Object body) throws Exception {
-		return MockServletRequest.create(method, path).body(body).restContext(rc);
+	public MockServletRequest request(String method, String path, Map<String,Object> headers, Object body) throws Exception {
+		String p = RestUtils.trimContextPath(ctx.getPath(), path);
+		return MockServletRequest.create(method, p).body(body).headers(this.headers).headers(headers).debug(debug).restContext(ctx);
 	}
 
 	/**
@@ -129,7 +445,20 @@ public class MockRest implements MockHttpConnection {
 	 * @throws Exception
 	 */
 	public MockServletRequest request(String method, String path) throws Exception {
-		return request(method, path, null);
+		return request(method, path, null, null);
+	}
+
+	/**
+	 * Performs a REST request against the REST interface.
+	 *
+	 * @param method The HTTP method
+	 * @param headers Optional headers to include in the request.
+	 * @param path The URI path.
+	 * @return A new servlet request.
+	 * @throws Exception
+	 */
+	public MockServletRequest request(String method, Map<String,Object> headers, String path) throws Exception {
+		return request(method, path, headers, null);
 	}
 
 	/**
@@ -140,7 +469,7 @@ public class MockRest implements MockHttpConnection {
 	 * @throws Exception
 	 */
 	public MockServletRequest get(String path) throws Exception {
-		return request("GET", path, null);
+		return request("GET", path, null, null);
 	}
 
 	/**
@@ -152,7 +481,7 @@ public class MockRest implements MockHttpConnection {
 	 * @throws Exception
 	 */
 	public MockServletRequest put(String path, Object body) throws Exception {
-		return request("PUT", path, body);
+		return request("PUT", path, null, body);
 	}
 
 	/**
@@ -164,7 +493,7 @@ public class MockRest implements MockHttpConnection {
 	 * @throws Exception
 	 */
 	public MockServletRequest post(String path, Object body) throws Exception {
-		return request("POST", path, body);
+		return request("POST", path, null, body);
 	}
 
 	/**
@@ -175,7 +504,7 @@ public class MockRest implements MockHttpConnection {
 	 * @throws Exception
 	 */
 	public MockServletRequest delete(String path) throws Exception {
-		return request("DELETE", path, null);
+		return request("DELETE", path, null, null);
 	}
 
 	/**
@@ -186,6 +515,18 @@ public class MockRest implements MockHttpConnection {
 	 * @throws Exception
 	 */
 	public MockServletRequest options(String path) throws Exception {
-		return request("OPTIONS", path, null);
+		return request("OPTIONS", path, null, null);
+	}
+
+	/**
+	 * Perform a PATCH request.
+	 *
+	 * @param path The URI path.
+	 * @param body The body of the request.
+	 * @return A new servlet request.
+	 * @throws Exception
+	 */
+	public MockServletRequest patch(String path, Object body) throws Exception {
+		return request("PATCH", path, null, body);
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
index a41973b..5a9b1fd 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
@@ -114,12 +114,41 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	}
 
 	/**
+	 * Specifies the <code>Accept</code> header value.
+	 *
+	 * @param value The <code>Accept</code> header value.
+	 * @return This object (for method chaining).
+	 */
+	public MockServletRequest accept(String value) {
+		return header("Accept", value);
+	}
+
+	/**
+	 * Specifies the <code>Content-Type</code> header value.
+	 *
+	 * @param value The <code>Content-Type</code> header value.
+	 * @return This object (for method chaining).
+	 */
+	public MockServletRequest contentType(String value) {
+		return header("Content-Type", value);
+	}
+
+	/**
 	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json"</js>.
 	 *
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest json() {
-		return header("Accept", "application/json").header("Content-Type", "application/json");
+		return accept("application/json").contentType("application/json");
+	}
+
+	/**
+	 * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json+simple"</js>.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public MockServletRequest simpleJson() {
+		return accept("application/json+simple").contentType("application/json+simple");
 	}
 
 	/**
@@ -128,7 +157,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest xml() {
-		return header("Accept", "text/xml").header("Content-Type", "text/xml");
+		return accept("text/xml").contentType("text/xml");
 	}
 
 	/**
@@ -137,7 +166,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest html() {
-		return header("Accept", "text/html").header("Content-Type", "text/html");
+		return accept("text/html").contentType("text/html");
 	}
 
 	/**
@@ -146,7 +175,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest plainText() {
-		return header("Accept", "text/plain").header("Content-Type", "text/plain");
+		return accept("text/plain").contentType("text/plain");
 	}
 
 	/**
@@ -155,7 +184,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest msgpack() {
-		return header("Accept", "octal/msgpack").header("Content-Type", "octal/msgpack");
+		return accept("octal/msgpack").contentType("octal/msgpack");
 	}
 
 	/**
@@ -164,7 +193,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest uon() {
-		return header("Accept", "text/uon").header("Content-Type", "text/uon");
+		return accept("text/uon").contentType("text/uon");
 	}
 
 	/**
@@ -173,7 +202,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest urlEnc() {
-		return header("Accept", "application/x-www-form-urlencoded").header("Content-Type", "application/x-www-form-urlencoded");
+		return accept("application/x-www-form-urlencoded").contentType("application/x-www-form-urlencoded");
 	}
 
 	/**
@@ -182,7 +211,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * @return This object (for method chaining).
 	 */
 	public MockServletRequest yaml() {
-		return header("Accept", "text/yaml").header("Content-Type", "text/yaml");
+		return accept("text/yaml").contentType("text/yaml");
 	}
 
 	/**
@@ -234,7 +263,12 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 		sb.append("\n=== HTTP Call =================================================================");
 
 		sb.append("\n=== REQUEST ===");
-		sb.append("\nTODO");
+		sb.append("\n---request headers---");
+		for (Map.Entry<String,String[]> h : req.getHeaders().entrySet())
+			for (String h2 : h.getValue())
+				sb.append("\n").append(h.getKey()).append(": ").append(h2);
+		sb.append("\n---request entity---");
+		sb.append(body == null ? "NONE" : new String(body));
 		sb.append("\n=== RESPONSE ===");
 		sb.append("\nStatus: ").append(res.getStatus());
 		sb.append("\n---response headers---");
@@ -798,6 +832,15 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 		return Collections.enumeration(Arrays.asList(s == null ? new String[0] : s));
 	}
 
+	/**
+	 * Returns the headers defined on this request.
+	 *
+	 * @return The headers defined on this request.  Never <jk>null</jk>.
+	 */
+	public Map<String,String[]> getHeaders() {
+		return headerMap;
+	}
+
 	@Override /* HttpServletRequest */
 	public Enumeration<String> getHeaderNames() {
 		return Collections.enumeration(headerMap.keySet());
@@ -960,6 +1003,19 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	/**
 	 * Fluent setter.
 	 *
+	 * @param headers Headers to add to this request.
+	 * @return This object (for method chaining).
+	 */
+	public MockServletRequest headers(Map<String,Object> headers) {
+		if (headers != null)
+			for (Map.Entry<String,Object> e : headers.entrySet())
+				header(e.getKey(), e.getValue());
+		return this;
+	}
+
+	/**
+	 * Fluent setter.
+	 *
 	 * @param name Header name.
 	 * @param value
 	 * 	Header value.
@@ -968,7 +1024,10 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 */
 	@Override /* MockHttpRequest */
 	public MockServletRequest header(String name, Object value) {
-		this.headerMap.put(name, new String[] {asString(value)});
+		if (value == null)
+			headerMap.remove(name);
+		else
+			headerMap.put(name, new String[] {asString(value)});
 		return this;
 	}
 
@@ -996,6 +1055,7 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 	 * 		<li>{@link InputStream}
 	 * 		<li>{@link CharSequence}
 	 * 	</ul>
+	 * 	Any other types are converted to a string using the <code>toString()</code> method.
 	 * @return This object (for method chaining).
 	 */
 	@Override /* MockHttpRequest */
@@ -1003,12 +1063,14 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 		try {
 			if (value instanceof byte[])
 				this.body = (byte[])value;
-			if (value instanceof Reader)
+			else if (value instanceof Reader)
 				this.body = IOUtils.read((Reader)value).getBytes();
-			if (value instanceof InputStream)
+			else if (value instanceof InputStream)
 				this.body = IOUtils.readBytes((InputStream)value, 1024);
-			if (value instanceof CharSequence)
+			else if (value instanceof CharSequence)
 				this.body = ((CharSequence)value).toString().getBytes();
+			else if (value != null)
+				this.body = value.toString().getBytes();
 		} catch (IOException e) {
 			throw new RuntimeException(e);
 		}
@@ -1363,4 +1425,18 @@ public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
 		this.debug = true;
 		return this;
 	}
+
+	/**
+	 * Enabled debug mode on this request.
+	 *
+	 * <p>
+	 * Causes information about the request execution to be sent to STDERR.
+	 *
+	 * @param value The enable flag value.
+	 * @return This object (for method chaining).
+	 */
+	public MockServletRequest debug(boolean value) {
+		this.debug = value;
+		return this;
+	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
index fde2eff..fc6d358 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
@@ -412,4 +412,31 @@ public final class RestUtils {
 		}
 		return l.toArray(new Object[l.size()]);
 	}
+
+	/**
+	 * If the specified path-info starts with the specified context path, trims the context path from the path info.
+	 *
+	 * @param contextPath The context path.
+	 * @param path The URL path.
+	 * @return The path following the context path, or the original path.
+	 */
+	public static String trimContextPath(String contextPath, String path) {
+		if (path == null)
+			return null;
+		if (path.length() == 0 || path.equals("/") || contextPath.length() == 0 || contextPath.equals("/"))
+			return path;
+		String op = path;
+		if (path.charAt(0) == '/')
+			path = path.substring(1);
+		if (contextPath.charAt(0) == '/')
+			contextPath = contextPath.substring(1);
+		if (path.startsWith(contextPath)) {
+			if (path.length() == contextPath.length())
+				return "/";
+			path = path.substring(contextPath.length());
+			if (path.isEmpty() || path.charAt(0) == '/')
+				return path;
+		}
+		return op;
+	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
index 1f9e34e..2db59fc 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/ReaderResourceTest.java
@@ -71,7 +71,7 @@ public class ReaderResourceTest {
 		}
 	}
 
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01_basic() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
index fab3b33..38ad4af 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/jueau/rest/helper/StreamResourceTest.java
@@ -70,7 +70,7 @@ public class StreamResourceTest {
 		}
 	}
 
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01_basic() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
index f7a2c52..c028638 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
@@ -2341,7 +2341,7 @@ public class BasicRestInfoProviderTest {
 		}
 	}
 
-	static MockRest p = MockRest.create(P.class);
+	static MockRest p = MockRest.build(P.class);
 
 	@Test
 	public void p01_bodyWithReadOnlyProperty() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
index dfc07c7..44b7bc1 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BeanContextPropertiesTest.java
@@ -46,7 +46,7 @@ public class BeanContextPropertiesTest  {
 			return "d1="+df.swap(session, d1)+",d2="+df.swap(session, d2)+",d3="+df.swap(session, d3)+"";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_testClassTransforms() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/NlsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/NlsTest.java
index d51806d..c18aa55 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/NlsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/NlsTest.java
@@ -48,7 +48,7 @@ public class NlsTest {
 			return null;
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	public static class A01 extends WriterSerializer {
 		public A01(PropertyStore ps) {
@@ -87,7 +87,7 @@ public class NlsTest {
 			return req.getSwagger();
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_optionsPageWithoutNls() throws Exception {
@@ -106,7 +106,7 @@ public class NlsTest {
 			return req.getMessage("bad", 1, 2, 3);
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_missingResourceBundle() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
index ccf6e1c..69342e4 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
@@ -56,7 +56,7 @@ public class PathsTest {
 			return getPaths(req).append("pathRemainder2", r).append("method",1);
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01() throws Exception {
@@ -204,7 +204,7 @@ public class PathsTest {
 			return getPaths(req).append("pathRemainder2", r).append("method",2);
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01() throws Exception {
@@ -356,7 +356,7 @@ public class PathsTest {
 			return getPaths(req).append("pathRemainder2", r).append("method",3);
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01() throws Exception {
@@ -508,7 +508,7 @@ public class PathsTest {
 			return getPaths(req).append("pathRemainder2", r).append("method",4);
 		}
 	}
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/RestParamsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/RestParamsTest.java
index 2c0d651..cecf860 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/RestParamsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/RestParamsTest.java
@@ -125,7 +125,7 @@ public class RestParamsTest {
 			return t != null;
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_ResourceBundle() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/StatusCodesTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
index 842ba3a..cc76593 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/StatusCodesTest.java
@@ -43,7 +43,7 @@ public class StatusCodesTest {
 			return new StringReader(b);
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
+	private static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01a_OK() throws Exception {
@@ -108,7 +108,7 @@ public class StatusCodesTest {
 			return "OK";
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
+	private static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01a_nonExistentBeanProperties() throws Exception {
@@ -202,7 +202,7 @@ public class StatusCodesTest {
 			return "OK";
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
+	private static MockRest c = MockRest.build(C.class);
 
 	@Test
 	public void c01_badPath() throws Exception {
@@ -237,7 +237,7 @@ public class StatusCodesTest {
 			}
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
+	private static MockRest d = MockRest.build(D.class);
 
 	@Test
 	public void d01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
index 462060b..bf66e81 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/ThreadLocalObjectsTest.java
@@ -44,7 +44,7 @@ public class ThreadLocalObjectsTest {
 			assertNull(getResponse());
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -70,7 +70,7 @@ public class ThreadLocalObjectsTest {
 			assertNull(getResponse());
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
index 9ef8d0b..4656c75 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocAsideTest.java
@@ -51,7 +51,7 @@ public class HtmlDocAsideTest {
 			return "OK";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -101,7 +101,7 @@ public class HtmlDocAsideTest {
 			return "OK";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
index 0e48866..bd58daf 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocFooterTest.java
@@ -51,7 +51,7 @@ public class HtmlDocFooterTest {
 			return "OK";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -101,7 +101,7 @@ public class HtmlDocFooterTest {
 			return "OK";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
index 6a8abf0..a3beaf8 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocHeaderTest.java
@@ -51,7 +51,7 @@ public class HtmlDocHeaderTest {
 			return "OK";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -101,7 +101,7 @@ public class HtmlDocHeaderTest {
 			return "OK";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
index 0852a46..63ae137 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavTest.java
@@ -51,7 +51,7 @@ public class HtmlDocNavTest {
 			return "OK";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -101,7 +101,7 @@ public class HtmlDocNavTest {
 			return "OK";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
index 37dc501..36d8df6 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocNavlinksTest.java
@@ -76,7 +76,7 @@ public class HtmlDocNavlinksTest {
 			return "OK";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -174,7 +174,7 @@ public class HtmlDocNavlinksTest {
 			return "OK";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 
 	@Test
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
index 67cdfa2..7922f1a 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocScriptTest.java
@@ -51,7 +51,7 @@ public class HtmlDocScriptTest {
 			return "OK";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -101,7 +101,7 @@ public class HtmlDocScriptTest {
 			return "OK";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
index bef342b..df8826d 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/HtmlDocStyleTest.java
@@ -51,7 +51,7 @@ public class HtmlDocStyleTest {
 			return "OK";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -101,7 +101,7 @@ public class HtmlDocStyleTest {
 			return "OK";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
index 46deac4..64a7655 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseHeaderAnnotationTest.java
@@ -55,7 +55,7 @@ public class ResponseHeaderAnnotationTest {
 		public String toString() {return "foo";}
 	}
 
-	static MockRest a = MockRest.create(A.class,true);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01_valueOnParameterPojo() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
index 1a801c7..9d76202 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseStatusAnnotationTest.java
@@ -37,7 +37,7 @@ public class ResponseStatusAnnotationTest {
 		}
 	}
 
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
index 1f14587..4039a32 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodBpiTest.java
@@ -45,7 +45,7 @@ public class RestMethodBpiTest {
 			return new MyBeanA().init();
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -92,7 +92,7 @@ public class RestMethodBpiTest {
 			return new MyBeanA().init();
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
@@ -139,7 +139,7 @@ public class RestMethodBpiTest {
 			return new MyBeanB().init();
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class);
 
 	@Test
 	public void c01() throws Exception {
@@ -186,7 +186,7 @@ public class RestMethodBpiTest {
 			return new MyBeanB().init();
 		}
 	}
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class);
 
 	@Test
 	public void d01() throws Exception {
@@ -225,7 +225,7 @@ public class RestMethodBpiTest {
 			return new MyBeanA().init();
 		}
 	}
-	static MockRest e = MockRest.create(E.class);
+	static MockRest e = MockRest.build(E.class);
 
 	@Test
 	public void e01() throws Exception {
@@ -248,7 +248,7 @@ public class RestMethodBpiTest {
 			return new MyBeanA().init();
 		}
 	}
-	static MockRest f = MockRest.create(F.class);
+	static MockRest f = MockRest.build(F.class);
 
 	@Test
 	public void f01() throws Exception {
@@ -277,7 +277,7 @@ public class RestMethodBpiTest {
 			return new MyBeanA().init();
 		}
 	}
-	static MockRest g = MockRest.create(G.class);
+	static MockRest g = MockRest.build(G.class);
 
 	@Test
 	public void g01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
index 35f9c6f..52a452d 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodGuardsTest.java
@@ -51,7 +51,7 @@ public class RestMethodGuardsTest {
 			}
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_overlappingOneGuard() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
index 89c4554..8a1efef 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodMatchersTest.java
@@ -66,7 +66,7 @@ public class RestMethodMatchersTest {
 			}
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
index 82de0c6..7a676e1 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
@@ -64,7 +64,7 @@ public class RestMethodPathTest {
 			return "h";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_overlappingPaths() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
index 5406485..c184b05 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
@@ -48,7 +48,7 @@ public class RestResourceMessagesTest {
 			return convertToMap(rb);
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01() throws Exception {
@@ -62,7 +62,7 @@ public class RestResourceMessagesTest {
 
 	@RestResource(messages="RestResourceMessagesTest2")
 	public static class B extends A {}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
index 1794941..8268242 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePathTest.java
@@ -53,7 +53,7 @@ public class RestResourcePathTest {
 	@RestResource(path="/p2")
 	public static class A02 extends A02a {}
 
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_nestedChildren() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
index 318ebb3..a85d8ab 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourcePropertiesTest.java
@@ -82,7 +82,7 @@ public class RestResourcePropertiesTest {
 			}
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
index 93c65df..ee08149 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceSerializersTest.java
@@ -118,7 +118,7 @@ public class RestResourceSerializersTest {
 			return "test406";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01_serializerOnClass() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
index 76d7f21..95aa27e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/RestResourceStaticFilesTest.java
@@ -34,7 +34,7 @@ public class RestResourceStaticFilesTest {
 			return null;
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01() throws Exception {
@@ -58,7 +58,7 @@ public class RestResourceStaticFilesTest {
 			return null;
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
index 6c0b5c5..17ecb93 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/AnnotationInheritanceTest.java
@@ -64,7 +64,7 @@ public class AnnotationInheritanceTest {
 		}
 	}
 
-	private static MockRest a = MockRest.create(A.class);
+	private static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01_inherited_Body() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
index 40514ab..e1cbb2c 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
@@ -125,7 +125,7 @@ public class BodyAnnotationTest {
 			@Override public String toString() { return s; }
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
+	private static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01a_onParameter_String() throws Exception {
@@ -315,7 +315,7 @@ public class BodyAnnotationTest {
 			@Override public String toString() { return s; }
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
+	private static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01a_onPojo_StringTransform() throws Exception {
@@ -534,7 +534,7 @@ public class BodyAnnotationTest {
 			@Override public String toString() { return s; }
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
+	private static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01a_noMediaTypes_String() throws Exception {
@@ -624,7 +624,7 @@ public class BodyAnnotationTest {
 			return c;
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
+	private static MockRest e = MockRest.build(E.class);
 
 	@Test
 	public void e01_complexPojos_B_body() throws Exception {
@@ -665,7 +665,7 @@ public class BodyAnnotationTest {
 			public int p2;
 		}
 	}
-	static MockRest f = MockRest.create(F.class);
+	static MockRest f = MockRest.build(F.class);
 
 	@Test
 	public void f01_formPostAsContent() throws Exception {
@@ -688,7 +688,7 @@ public class BodyAnnotationTest {
 			return content;
 		}
 	}
-	static MockRest g = MockRest.create(G.class);
+	static MockRest g = MockRest.build(G.class);
 
 	@Test
 	public void g01() throws Exception {
@@ -734,7 +734,7 @@ public class BodyAnnotationTest {
 			return content;
 		}
 	}
-	static MockRest h = MockRest.create(H.class);
+	static MockRest h = MockRest.build(H.class);
 
 	@Test
 	public void h01() throws Exception {
@@ -773,7 +773,7 @@ public class BodyAnnotationTest {
 			return content;
 		}
 	}
-	static MockRest i = MockRest.create(I.class);
+	static MockRest i = MockRest.build(I.class);
 
 	@Test
 	public void i01() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
index 83cbddf..9189877 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
@@ -47,7 +47,7 @@ public class FormDataAnnotationTest {
 			return "p1=["+p1+","+req.getFormData().getString("p1")+","+f.get("p1", String.class)+"],p2=["+p2+","+req.getFormData().getString("p2")+","+f.get("p2", int.class)+"]";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01() throws Exception {
@@ -82,7 +82,7 @@ public class FormDataAnnotationTest {
 			return "p1=["+p1+","+req.getFormData().getString("p1")+","+f.get("p1", String.class)+"]";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01() throws Exception {
@@ -130,7 +130,7 @@ public class FormDataAnnotationTest {
 				.append("f3", f3);
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_defaultFormData() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
index fed148e..54df9aa 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasFormDataAnnotationTest.java
@@ -39,7 +39,7 @@ public class HasFormDataAnnotationTest {
 		}
 
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_post() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
index b82ae31..497d2d2 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/HasQueryAnnotationTest.java
@@ -45,7 +45,7 @@ public class HasQueryAnnotationTest {
 			return "p1=["+p1+","+q.containsKey("p1")+"],p2=["+p2+","+q.containsKey("p2")+"]";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_get() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
index d659603..f9bea60 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
@@ -61,7 +61,7 @@ public class PathAnnotationTest {
 			return "GET /a "+foo+","+bar+",r="+remainder;
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a00_nonExistentPath() throws Exception {
@@ -137,7 +137,7 @@ public class PathAnnotationTest {
 			return String.valueOf(x);
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_int() throws Exception {
@@ -219,7 +219,7 @@ public class PathAnnotationTest {
 			return String.valueOf(x);
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_Integer() throws Exception {
@@ -274,7 +274,7 @@ public class PathAnnotationTest {
 			return uuid;
 		}
 	}
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01_uuid() throws Exception {
@@ -309,7 +309,7 @@ public class PathAnnotationTest {
 			return new ObjectMap().append("m","numbers3").append("0", foo).append("1", bar);
 		}
 	}
-	static MockRest e = MockRest.create(E.class);
+	static MockRest e = MockRest.build(E.class, null);
 
 	@Test
 	public void e01_normal1() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
index 8030718..b3887f9 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
@@ -38,7 +38,7 @@ public class PathRemainderAnnotationTest {
 			return remainder;
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_withoutRemainder() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
index b778a9a..4da3c27 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
@@ -53,7 +53,7 @@ public class QueryAnnotationTest {
 			return "p1=["+p1+","+req.getQuery().getString("p1")+","+q.get("p1", String.class)+"],p2=["+p2+","+q.getString("p2")+","+q.get("p2", int.class)+"]";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_get() throws Exception {
@@ -113,7 +113,7 @@ public class QueryAnnotationTest {
 			return "p1=["+p1+","+req.getQuery().getString("p1")+","+q.get("p1", String.class)+"]";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_get1() throws Exception {
@@ -173,7 +173,7 @@ public class QueryAnnotationTest {
 			return x;
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class);
 
 	@Test
 	public void c01_StringArray() throws Exception {
@@ -241,7 +241,7 @@ public class QueryAnnotationTest {
 				.append("f3", f3);
 		}
 	}
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01_defaultQuery() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
index e51a05d..7cd9519 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/ResponseAnnotationTest.java
@@ -70,7 +70,7 @@ public class ResponseAnnotationTest {
 		public String toString() {return "foo";}
 	}
 
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_codeOnClass() throws Exception {
@@ -123,7 +123,7 @@ public class ResponseAnnotationTest {
 		public String toString() {return "foo";}
 	}
 
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_useOnMethod() throws Exception {
@@ -214,7 +214,7 @@ public class ResponseAnnotationTest {
 		}
 	}
 
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01_useOnMethod() throws Exception {
@@ -285,7 +285,7 @@ public class ResponseAnnotationTest {
 		public String toString() {return "foo";}
 	}
 
-	static MockRest e = MockRest.create(E.class);
+	static MockRest e = MockRest.build(E.class, null);
 
 	@Test
 	public void e01_basic_onParameter() throws Exception {
@@ -337,7 +337,7 @@ public class ResponseAnnotationTest {
 		}
 	}
 
-	static MockRest f = MockRest.create(F.class);
+	static MockRest f = MockRest.build(F.class, null);
 	static Swagger sf = getSwagger(F.class);
 
 	@Test
@@ -410,7 +410,7 @@ public class ResponseAnnotationTest {
 		}
 	}
 
-	static MockRest g = MockRest.create(G.class);
+	static MockRest g = MockRest.build(G.class);
 	static Swagger sg = getSwagger(G.class);
 
 	@Test
@@ -467,7 +467,7 @@ public class ResponseAnnotationTest {
 			return body;
 		}
 	}
-	static MockRest j = MockRest.create(J.class);
+	static MockRest j = MockRest.build(J.class);
 
 	@Test
 	public void j01a_basic() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
index 5b4b38e..1e8cb9c 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestHookTest.java
@@ -82,7 +82,7 @@ public class RestHookTest {
 			return req.getBody().asType(String.class);
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	public static class A01 extends ReaderParser {
 		public A01(PropertyStore ps) {
@@ -163,7 +163,7 @@ public class RestHookTest {
 			return null;
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	public static class B01 extends WriterSerializer {
 		public B01(PropertyStore ps) {
@@ -218,7 +218,7 @@ public class RestHookTest {
 
 	@RestResource(children={C_Super.class,C_Sub.class})
 	public static class C {}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@RestResource(path="/super")
 	public static class C_Super {
@@ -293,7 +293,7 @@ public class RestHookTest {
 	//====================================================================================================
 	@RestResource(children={D_Super.class,D_Sub.class})
 	public static class D {}
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class, null);
 
 	@RestResource(path="/super")
 	public static class D_Super {
@@ -391,7 +391,7 @@ public class RestHookTest {
 		}
 	)
 	public static class E {}
-	static MockRest e = MockRest.create(E.class);
+	static MockRest e = MockRest.build(E.class, null);
 
 	@RestResource(path="/super")
 	public static class E_Super {
@@ -506,7 +506,7 @@ public class RestHookTest {
 				.append("4", res.getHeader("start4-called"));
 		}
 	}
-	static MockRest f = MockRest.create(F.class);
+	static MockRest f = MockRest.build(F.class, null);
 
 	public static class F_Parent {
 		private boolean start1Called;
@@ -557,7 +557,7 @@ public class RestHookTest {
 				.append("4", res.getHeader("pre4-called"));
 		}
 	}
-	static MockRest g = MockRest.create(G.class);
+	static MockRest g = MockRest.build(G.class, null);
 
 	public static class G_Parent {
 		private boolean pre1Called;
@@ -604,7 +604,7 @@ public class RestHookTest {
 			return "OK";
 		}
 	}
-	static MockRest h = MockRest.create(H.class);
+	static MockRest h = MockRest.build(H.class);
 
 	public static class H_Parent {
 		private boolean post1Called;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
index 9f0d119..002b04d 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestMethodInheritTest.java
@@ -152,7 +152,7 @@ public class RestMethodInheritTest {
 			return new ObjectList(res.getSupportedMediaTypes());
 		}
 	}
-	static MockRest a = MockRest.create(A02.class);
+	static MockRest a = MockRest.build(A02.class, null);
 
 	@Test
 	public void a01_serializers_default() throws Exception {
@@ -195,7 +195,7 @@ public class RestMethodInheritTest {
 			return new ObjectList(req.getConsumes());
 		}
 	}
-	static MockRest b = MockRest.create(B02.class);
+	static MockRest b = MockRest.build(B02.class, null);
 
 	@Test
 	public void b01_parsers_default() throws Exception {
@@ -244,7 +244,7 @@ public class RestMethodInheritTest {
 			return new Object[]{new Foo1(), new Foo2(), new Foo3()};
 		}
 	}
-	static MockRest d = MockRest.create(D02.class);
+	static MockRest d = MockRest.build(D02.class);
 
 	@Test
 	public void d01_transforms_default() throws Exception {
@@ -303,7 +303,7 @@ public class RestMethodInheritTest {
 			return m;
 		}
 	}
-	static MockRest e = MockRest.create(E02.class);
+	static MockRest e = MockRest.build(E02.class, null);
 
 	@Test
 	public void e01_properties_default() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
index fa4eb73..6074e0d 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourceParsersTest.java
@@ -126,7 +126,7 @@ public class RestResourceParsersTest {
 			return in;
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_parserOnClass() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
index 90eef4c..b292c5e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation2/RestResourcePojoSwapsTest.java
@@ -117,7 +117,7 @@ public class RestResourcePojoSwapsTest {
 			return a; // Should return "A3-1".
 		}
 	}
-	static MockRest a = MockRest.create(A01.class);
+	static MockRest a = MockRest.build(A01.class);
 
 	@Test
 	public void a01_classTransformOverridesParentClassTransform() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/exception/BasicTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
index 9954e65..902612e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/exception/BasicTest.java
@@ -67,7 +67,7 @@ public class BasicTest {
 		@RestMethod public void variantAlsoNegotiates() { throw new VariantAlsoNegotiates(); }
 	}
 
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_badRequest() throws Exception {
@@ -243,7 +243,7 @@ public class BasicTest {
 		@RestMethod public void variantAlsoNegotiates() { throw new VariantAlsoNegotiates("foo {0}", "bar"); }
 	}
 
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_badRequest() throws Exception {
@@ -421,7 +421,7 @@ public class BasicTest {
 		@RestMethod public void variantAlsoNegotiates() { throw new VariantAlsoNegotiates(t); }
 	}
 
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_badRequest() throws Exception {
@@ -597,7 +597,7 @@ public class BasicTest {
 		@RestMethod public void variantAlsoNegotiates() { throw new VariantAlsoNegotiates(t, "foo {0}", "bar"); }
 	}
 
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01_badRequest() throws Exception {
@@ -741,7 +741,7 @@ public class BasicTest {
 		@RestMethod public void badRequest() { throw new BadRequest(t, "foo {0}", "bar"); }
 	}
 
-	static MockRest e = MockRest.create(E.class);
+	static MockRest e = MockRest.build(E.class);
 
 	@Test
 	public void e01_badRequest() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
index 37b7818..b5cbcef 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
@@ -44,7 +44,7 @@ public class AcceptCharsetTest {
 			return "foo";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class);
 
 	@Test
 	public void a01_qValues() throws Exception {
@@ -106,7 +106,7 @@ public class AcceptCharsetTest {
 			}
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class);
 
 	@Test
 	public void b01_testCharsetOnResponse() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
index 3ebf2ad..09ad69e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptEncodingTest.java
@@ -53,7 +53,7 @@ public class AcceptEncodingTest {
 			return "foo";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_noCompression() throws Exception {
@@ -124,7 +124,7 @@ public class AcceptEncodingTest {
 			return "foo";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_withCompression_identity() throws Exception {
@@ -217,7 +217,7 @@ public class AcceptEncodingTest {
 			w.flush();
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class);
 
 	@Test
 	public void c01_direct1() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
index 19eaa26..0bb6fca 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/AcceptTest.java
@@ -69,7 +69,7 @@ public class AcceptTest {
 			return in;
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
+	private static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_defaultHeadersOnServletAnnotation_valid() throws Exception {
@@ -98,7 +98,7 @@ public class AcceptTest {
 			return in;
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
+	private static MockRest b = MockRest.create().impl(B.class).build();
 
 	@Test
 	public void b01_restMethodWithParsersSerializers_valid() throws Exception {
@@ -130,7 +130,7 @@ public class AcceptTest {
 			return in;
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
+	private static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_restMethodAddParsersSerializersInherit() throws Exception {
@@ -164,7 +164,7 @@ public class AcceptTest {
 			return in;
 		}
 	}
-	private static MockRest d = MockRest.create(D.class);
+	private static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01_accept_valid() throws Exception {
@@ -202,7 +202,7 @@ public class AcceptTest {
 			return in;
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
+	private static MockRest e = MockRest.build(E.class, null);
 
 	@Test
 	public void e01_restMethodParserSerializerAnnotations_valid() throws Exception {
@@ -240,7 +240,7 @@ public class AcceptTest {
 			return in;
 		}
 	}
-	private static MockRest f = MockRest.create(F.class);
+	private static MockRest f = MockRest.build(F.class, null);
 
 	@Test
 	public void f01_restMethodAddParsersSerializersAnnotations_valid() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
index 5e9f3bf..028baf9 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ClientVersionTest.java
@@ -53,7 +53,7 @@ public class ClientVersionTest {
 			return "2";
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_defaultHeader() throws Exception {
@@ -96,7 +96,7 @@ public class ClientVersionTest {
 			return "2";
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_testCustomHeader() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
index 4c03809..928ba50 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentEncodingTest.java
@@ -51,7 +51,7 @@ public class ContentEncodingTest {
 			return in;
 		}
 	}
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_noCompression() throws Exception {
@@ -80,7 +80,7 @@ public class ContentEncodingTest {
 			return in;
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_withCompression_identity() throws Exception {
@@ -89,6 +89,7 @@ public class ContentEncodingTest {
 		b.put("/", "foo").contentEncoding("identity").execute().assertBody("foo");
 	}
 	@Test
+	@Ignore
 	public void b02_withCompression_gzip() throws Exception {
 		b.put("/", compress("foo")).contentEncoding("mycoding").execute().assertBody("foo");
 	}
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
index bd44f37..c6a6b6b 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/ContentTypeTest.java
@@ -71,7 +71,7 @@ public class ContentTypeTest {
 			return in;
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
+	private static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_defaultHeadersOnServletAnnotation_valid() throws Exception {
@@ -100,7 +100,7 @@ public class ContentTypeTest {
 			return in;
 		}
 	}
-	private static MockRest b = MockRest.create(B.class);
+	private static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_restMethodWithParsersSerializers_valid() throws Exception {
@@ -144,7 +144,7 @@ public class ContentTypeTest {
 			return in;
 		}
 	}
-	private static MockRest c = MockRest.create(C.class);
+	private static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_restMethodAddParsersSerializersInherit() throws Exception {
@@ -179,7 +179,7 @@ public class ContentTypeTest {
 			return in;
 		}
 	}
-	private static MockRest e = MockRest.create(E.class);
+	private static MockRest e = MockRest.build(E.class, null);
 
 	@Test
 	public void e01_restMethodParserSerializerAnnotations_valid() throws Exception {
@@ -218,7 +218,7 @@ public class ContentTypeTest {
 		}
 	}
 
-	private static MockRest f = MockRest.create(F.class);
+	private static MockRest f = MockRest.build(F.class, null);
 
 	@Test
 	public void f01_restMethodAddParsersSerializersAnnotations_valid() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
index 26d74f3..939d2b5 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/headers/HeadersTest.java
@@ -153,7 +153,7 @@ public class HeadersTest {
 			return warning.toString();
 		}
 	}
-	private static MockRest a = MockRest.create(A.class);
+	private static MockRest a = MockRest.build(A.class);
 
 	public static class AnythingSerializer extends PlainTextSerializer {
 		public AnythingSerializer(PropertyStore ps) {
@@ -417,7 +417,7 @@ public class HeadersTest {
 			return customHeader.toString();
 		}
 	}
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	public static class CustomHeaderParam extends RestMethodParam {
 		public CustomHeaderParam() {
@@ -463,7 +463,7 @@ public class HeadersTest {
 				.append("h3", headers.getString("H3"));
 		}
 	}
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_defaultRequestHeaders_default() throws Exception {
@@ -492,7 +492,7 @@ public class HeadersTest {
 				.append("h3", headers.getString("h3"));
 		}
 	}
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class, null);
 
 	@Test
 	public void d01_defaultRequestHeadersCaseInsensitive_default() throws Exception {
@@ -521,7 +521,7 @@ public class HeadersTest {
 				.append("h3", h3);
 		}
 	}
-	static MockRest e = MockRest.create(E.class);
+	static MockRest e = MockRest.build(E.class, null);
 
 	@Test
 	public void e01_annotatedHeaders_default() throws Exception {
@@ -550,7 +550,7 @@ public class HeadersTest {
 				.append("h3", h3);
 		}
 	}
-	static MockRest f = MockRest.create(F.class);
+	static MockRest f = MockRest.build(F.class, null);
 
 	@Test
 	public void f01_annotatedHeadersCaseInsensitive_default() throws Exception {
@@ -579,7 +579,7 @@ public class HeadersTest {
 				.append("h3", h3);
 		}
 	}
-	static MockRest g = MockRest.create(G.class);
+	static MockRest g = MockRest.build(G.class, null);
 
 	@Test
 	public void g01_annotatedHeadersDefault_default() throws Exception {
@@ -604,7 +604,7 @@ public class HeadersTest {
 				.append("h3", h3);
 		}
 	}
-	static MockRest gb = MockRest.create(GB.class);
+	static MockRest gb = MockRest.build(GB.class, null);
 
 	@Test
 	public void gb01_annotatedHeadersDefault_default() throws Exception {
@@ -633,7 +633,7 @@ public class HeadersTest {
 				.append("h3", h3);
 		}
 	}
-	static MockRest h = MockRest.create(H.class);
+	static MockRest h = MockRest.build(H.class, null);
 
 	@Test
 	public void h01_annotatedAndDefaultHeaders_default() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/response/BasicTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/response/BasicTest.java
index a6294b3..40df96e 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/response/BasicTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/response/BasicTest.java
@@ -59,7 +59,7 @@ public class BasicTest {
 		@RestMethod public UseProxy useProxy() { return new UseProxy(); }
 	}
 
-	static MockRest a = MockRest.create(A.class);
+	static MockRest a = MockRest.build(A.class, null);
 
 	@Test
 	public void a01_accepted() throws Exception {
@@ -162,7 +162,7 @@ public class BasicTest {
 		@RestMethod public TemporaryRedirect temporaryRedirect() { return new TemporaryRedirect(URI.create("servlet:/foo")); }
 	}
 
-	static MockRest b = MockRest.create(B.class);
+	static MockRest b = MockRest.build(B.class, null);
 
 	@Test
 	public void b01_movedPermanently() throws Exception {
@@ -211,7 +211,7 @@ public class BasicTest {
 		@RestMethod public UseProxy useProxy() { return new UseProxy("foo"); }
 	}
 
-	static MockRest c = MockRest.create(C.class);
+	static MockRest c = MockRest.build(C.class, null);
 
 	@Test
 	public void c01_accepted() throws Exception {
@@ -311,7 +311,7 @@ public class BasicTest {
 		@RestMethod public Accepted accepted() { return new Accepted("foo"); }
 	}
 
-	static MockRest d = MockRest.create(D.class);
+	static MockRest d = MockRest.build(D.class);
 
 	@Test
 	public void d01_accepted() throws Exception {
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
index cacdf17..377c3c8 100755
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
@@ -37,6 +37,7 @@ public class TestUtils extends org.apache.juneau.testutils.TestUtils {
 		try (GZIPOutputStream gos = new GZIPOutputStream(baos)) {
 			gos.write(contents.getBytes());
 			gos.finish();
+			gos.flush();
 		}
 		return baos.toByteArray();
 	}
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java
index 8d688ef..d9677e9 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/util/RestUtilsTest.java
@@ -259,4 +259,21 @@ public class RestUtilsTest {
 		public String f1 = "f1";
 	}
 
+	//=================================================================================================================
+	// Other tests
+	//=================================================================================================================
+
+	@Test
+	public void testTrimContextPath() {
+		assertEquals("/bar", trimContextPath("/foo", "/bar"));
+		assertEquals("/", trimContextPath("/foo", "/"));
+		assertEquals("", trimContextPath("/foo", ""));
+		assertEquals(null, trimContextPath("/foo", null));
+
+		assertEquals("/bar", trimContextPath("/foo", "/foo/bar"));
+		assertEquals("/bar/baz", trimContextPath("/foo", "/foo/bar/baz"));
+		assertEquals("/bar/", trimContextPath("/foo", "/foo/bar/"));
+		assertEquals("/", trimContextPath("/foo", "/foo/"));
+		assertEquals("/", trimContextPath("/foo", "/foo"));
+	}
 }


[juneau] 01/09: Additional default configuration file names.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 3abc77c20fc8a8b7347c23a65917538645b5d9e5
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu Jan 10 16:54:13 2019 -0500

    Additional default configuration file names.
---
 .../src/main/java/org/apache/juneau/config/Config.java           | 6 ++++++
 .../docs/Topics/06.juneau-config/15.SystemDefaultConfig.html     | 3 +++
 .../docs/Topics/11.juneau-microservice-core/05.Config.html       | 9 ++++++++-
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index 2bfb9ec..92141f3 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -88,6 +88,9 @@ public final class Config extends Context implements ConfigEventListener, Writab
 	 * 	<li>Any file ending in <js>".cfg"</js> in the home directory (names ordered alphabetically).
 	 * 	<li><js>"juneau.cfg"</js>
 	 * 	<li><js>"default.cfg"</js>
+	 * 	<li><js>"application.cfg"</js>
+	 * 	<li><js>"app.cfg"</js>
+	 * 	<li><js>"settings.cfg"</js>
 	 * </ol>
 	 * <p>
 	 *
@@ -120,6 +123,9 @@ public final class Config extends Context implements ConfigEventListener, Writab
 
 		l.add("juneau.cfg");
 		l.add("default.cfg");
+		l.add("application.cfg");
+		l.add("app.cfg");
+		l.add("settings.cfg");
 
 		return l;
 	}
diff --git a/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html b/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html
index bec6896..dc7fb72 100644
--- a/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html
+++ b/juneau-doc/docs/Topics/06.juneau-config/15.SystemDefaultConfig.html
@@ -46,6 +46,9 @@ System Default Config
 			<li><code>&lt;jar-name&gt;.cfg</code>
 			<li><code>juneau.cfg</code>
 			<li><code>default.cfg</code>
+			<li><code>application.cfg</code>
+			<li><code>app.cfg</code>
+			<li><code>settings.cfg</code>
 		</ol>
 </ol>
 <p>
diff --git a/juneau-doc/docs/Topics/11.juneau-microservice-core/05.Config.html b/juneau-doc/docs/Topics/11.juneau-microservice-core/05.Config.html
index af4d724..0e36fb4 100644
--- a/juneau-doc/docs/Topics/11.juneau-microservice-core/05.Config.html
+++ b/juneau-doc/docs/Topics/11.juneau-microservice-core/05.Config.html
@@ -44,7 +44,14 @@ Config
 	<li>
 		Resolve any <js>"*.cfg"</js> file that can be found in the working directory.
 	<li>
-		Resolve any of the following files in the classpath:  <js>"juneau.cfg"</js>, <js>"system.cfg"</js>
+		Resolve any of the following files in the classpath:
+		<ol>
+			<li><code>juneau.cfg</code>
+			<li><code>default.cfg</code>
+			<li><code>application.cfg</code>
+			<li><code>app.cfg</code>
+			<li><code>settings.cfg</code>
+		</ol>
 </ol>
 <p>
 	If no configuration file is found, and empty in-memory configuration is used.


[juneau] 02/09: Add Ayeshmantha to developer list in POM.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 6699d2b564fbcf3b8538fa5c5caae60ea731936f
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu Jan 10 16:55:17 2019 -0500

    Add Ayeshmantha to developer list in POM.
---
 juneau-examples/juneau-examples-rest-jetty/.gitignore | 1 +
 pom.xml                                               | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/juneau-examples/juneau-examples-rest-jetty/.gitignore b/juneau-examples/juneau-examples-rest-jetty/.gitignore
index 5ad1d63..7d53df3 100644
--- a/juneau-examples/juneau-examples-rest-jetty/.gitignore
+++ b/juneau-examples/juneau-examples-rest-jetty/.gitignore
@@ -1,3 +1,4 @@
 /target/
 **/.DS_Store
 /derby.log
+/bin/
diff --git a/pom.xml b/pom.xml
index 3eef320..f1d619c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -430,5 +430,10 @@
 			<name>Marcelo Vieira</name>
 			<roles><role>PMC</role></roles>
 		</developer>
+		<developer>
+			<id>akayeshmantha</id>
+			<name>Ayeshmantha Perera</name>
+			<roles><role>PMC</role></roles>
+		</developer>
 	</developers>
 </project>


[juneau] 03/09: Doc fix.

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 32d628e7c9d4c909d4e8a7891cda0e1d46237ae3
Author: JamesBognar <ja...@apache.org>
AuthorDate: Sun Jan 13 15:27:33 2019 -0500

    Doc fix.
---
 .../apache/juneau/config/ConfigImportsTest.java    |  2 --
 .../06.juneau-config/02.EntryTypes/03.Arrays.html  |  2 +-
 juneau-doc/src/main/javadoc/overview.html          | 29 ++++++++++++++--------
 3 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigImportsTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigImportsTest.java
index 908c156..5b5819d 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigImportsTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/config/ConfigImportsTest.java
@@ -416,6 +416,4 @@ public class ConfigImportsTest {
 		assertEquals("1", cb.get("A/a1"));
 		assertEquals("2", cb.get("B/b1"));
 	}
-
-	// TODO - Overwriting config should not unregister listeners
 }
diff --git a/juneau-doc/docs/Topics/06.juneau-config/02.EntryTypes/03.Arrays.html b/juneau-doc/docs/Topics/06.juneau-config/02.EntryTypes/03.Arrays.html
index 9bc6d44..0cda0b7 100644
--- a/juneau-doc/docs/Topics/06.juneau-config/02.EntryTypes/03.Arrays.html
+++ b/juneau-doc/docs/Topics/06.juneau-config/02.EntryTypes/03.Arrays.html
@@ -42,7 +42,7 @@ Arrays
 	<ck>key1</ck> = <cv>['foo','bar','baz']</cv>
 </p>
 <p class='bpcode w800'>
-	String[] key1 = c.getObject(<js>"key1"</js>, String.<jk>class</jk>);
+	String[] key1 = c.getObject(<js>"key1"</js>, String[].<jk>class</jk>);
 </p>
 <p>
 	Primitive arrays can also be retrieved using the <code>getObject()</code> methods:
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index a415849..4b8105f 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -11613,7 +11613,7 @@
 	<ck>key1</ck> = <cv>['foo','bar','baz']</cv>
 </p>
 <p class='bpcode w800'>
-	String[] key1 = c.getObject(<js>"key1"</js>, String.<jk>class</jk>);
+	String[] key1 = c.getObject(<js>"key1"</js>, String[].<jk>class</jk>);
 </p>
 <p>
 	Primitive arrays can also be retrieved using the <code>getObject()</code> methods:
@@ -12910,6 +12910,9 @@
 			<li><code>&lt;jar-name&gt;.cfg</code>
 			<li><code>juneau.cfg</code>
 			<li><code>default.cfg</code>
+			<li><code>application.cfg</code>
+			<li><code>app.cfg</code>
+			<li><code>settings.cfg</code>
 		</ol>
 </ol>
 <p>
@@ -13479,7 +13482,7 @@
 <h4 class='topic new' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.BasicRest' id='juneau-rest-server.Instantiation.BasicRest'>7.3.3 - BasicRest</a></h4>
 <div class='topic'><!-- START: 7.3.3 - juneau-rest-server.Instantiation.BasicRest -->
 <p>
-	The {@link org.apache.juneau.rest.BasicRest} class is identical to the {@link org.apache.juneau.BasicRestServlet} class except that
+	The {@link org.apache.juneau.rest.BasicRest} class is identical to the {@link org.apache.juneau.rest.BasicRestServlet} class except that
 	it does not extend from <code>HttpServlet</code>.
 	It defines the exact same set of serializers, parsers, etc., but it cannot be deployed as a top-level
 	servlet.  It can however be used for child resources registered via the {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource(children)} 
@@ -13620,12 +13623,9 @@
 		children={
 			HelloWorldResource.<jk>class</jk>,
 			PetStoreResource.<jk>class</jk>,
-			PhotosResource.<jk>class</jk>,
 			DtoExamples.<jk>class</jk>,
-			SqlQueryResource.<jk>class</jk>,
 			ConfigResource.<jk>class</jk>,
 			LogsResource.<jk>class</jk>,
-			DebugResource.<jk>class</jk>,
 			ShutdownResource.<jk>class</jk>
 		}
 	)
@@ -13665,7 +13665,7 @@
 <h4 class='topic new' onclick='toggle(this)'><a href='#juneau-rest-server.Instantiation.BasicRestGroup' id='juneau-rest-server.Instantiation.BasicRestGroup'>7.3.6 - BasicRestGroup</a></h4>
 <div class='topic'><!-- START: 7.3.6 - juneau-rest-server.Instantiation.BasicRestGroup -->
 <p>
-	The {@link org.apache.juneau.rest.BasicRestGroup} class is identical to the {@link org.apache.juneau.BasicRestServletGroup} class except that
+	The {@link org.apache.juneau.rest.BasicRestGroup} class is identical to the {@link org.apache.juneau.rest.BasicRestServletGroup} class except that
 	it does not extend from <code>HttpServlet</code>.
 	It defines the exact same set of serializers, parsers, etc., but it cannot be deployed as a top-level
 	servlet.  It can however be used for child resources registered via the {@link org.apache.juneau.rest.annotation.RestResource#children() @RestResource(children)} 
@@ -23061,7 +23061,7 @@
 		title=<js>"Petstore application"</js>,
 		...
 	)
-	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena <jk>implements</jk> PetStore {
+	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestJena <jk>implements</jk> PetStore {
 	
 		...
 	
@@ -24200,7 +24200,14 @@
 	<li>
 		Resolve any <js>"*.cfg"</js> file that can be found in the working directory.
 	<li>
-		Resolve any of the following files in the classpath:  <js>"juneau.cfg"</js>, <js>"system.cfg"</js>
+		Resolve any of the following files in the classpath:
+		<ol>
+			<li><code>juneau.cfg</code>
+			<li><code>default.cfg</code>
+			<li><code>application.cfg</code>
+			<li><code>app.cfg</code>
+			<li><code>settings.cfg</code>
+		</ol>
 </ol>
 <p>
 	If no configuration file is found, and empty in-memory configuration is used.
@@ -26487,7 +26494,7 @@
 			PhotosResource.<jk>class</jk>
 		}
 	)
-	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena {
+	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestJena {
 </p>
 <p>
 	The inner contents of the page are generated from this method which is used to define a jumping-off
@@ -26653,7 +26660,7 @@
 </p>
 <h5 class='figure'>PetStoreResource.java</h5>
 <p class='bpcode w800'>
-	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena <jk>implements</jk> PetStore {
+	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestJena <jk>implements</jk> PetStore {
 	
 		<jk>private</jk> PetStoreService <jf>store</jf>;
 	
@@ -26853,7 +26860,7 @@
 </p>
 <h5 class='figure'>PetStoreResource.java</h5>
 <p class='bpcode w800'>
-	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestServletJena <jk>implements</jk> PetStore {
+	<jk>public class</jk> PetStoreResource <jk>extends</jk> BasicRestJena <jk>implements</jk> PetStore {
 	
 		<ja>@Override</ja> <jc>/* PetStore */</jc>
 		<ja>@RestMethod</ja>(