juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [juneau] branch master updated: Implement OpenApiPartSerializer
Date Thu, 05 Jul 2018 20:57:03 GMT
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


The following commit(s) were added to refs/heads/master by this push:
     new 8abfc70  Implement OpenApiPartSerializer
8abfc70 is described below

commit 8abfc7027cbffd7ab2474dfe6d3bbdc8a90e4555
Author: JamesBognar <jamesbognar@apache.org>
AuthorDate: Thu Jul 5 16:56:49 2018 -0400

    Implement OpenApiPartSerializer
---
 .../juneau/httppart/OpenApiPartSerializerTest.java | 1079 ++++++++++++++++++++
 .../main/java/org/apache/juneau/BeanSession.java   |    5 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |   36 +-
 .../org/apache/juneau/httppart/HttpPartSchema.java |    2 +-
 .../apache/juneau/httppart/OpenApiPartParser.java  |   18 +-
 .../juneau/httppart/OpenApiPartSerializer.java     |  280 +++--
 .../org/apache/juneau/internal/StringUtils.java    |   20 +
 .../apache/juneau/rest/BasicRestCallHandler.java   |    7 +
 .../java/org/apache/juneau/rest/RestContext.java   |   46 +-
 .../org/apache/juneau/rest/RestContextBuilder.java |   20 +
 .../juneau/rest/annotation/RestResource.java       |   25 +
 11 files changed, 1363 insertions(+), 175 deletions(-)

diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
new file mode 100644
index 0000000..7289117
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
@@ -0,0 +1,1079 @@
+// ***************************************************************************************************************************
+// * 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.httppart;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.junit.*;
+
+public class OpenApiPartSerializerTest {
+
+	static OpenApiPartSerializer s = OpenApiPartSerializer.DEFAULT;
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Input validations
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void a01_outputValidations_nullOutput() throws Exception {
+		HttpPartSchema ps = schema().build();
+		assertNull(s.serialize(ps, null));
+
+		ps = schema().required(false).build();
+		assertNull(s.serialize(ps, null));
+
+		ps = schema().required().build();
+		try {
+			s.serialize(ps, null);
+			fail();
+		} catch (Exception e) {
+			assertEquals("Required value not provided.", e.getMessage());
+		}
+
+		ps = schema().required(true).build();
+		try {
+			s.serialize(ps, null);
+			fail();
+		} catch (Exception e) {
+			assertEquals("Required value not provided.", e.getMessage());
+		}
+	}
+
+	@Test
+	public void a02_outputValidations_emptyOutput() throws Exception {
+
+		HttpPartSchema ps = schema().allowEmptyValue().build();
+		assertEquals("", s.serialize(ps, ""));
+
+		ps = schema().allowEmptyValue().build();
+		assertEquals("", s.serialize(ps, ""));
+
+		ps = schema().allowEmptyValue(false).build();
+		try {
+			s.serialize(ps, "");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Empty value not allowed.", e.getMessage());
+		}
+
+		try {
+			s.serialize(ps, "");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Empty value not allowed.", e.getMessage());
+		}
+
+		assertEquals(" ", s.serialize(ps, " "));
+	}
+
+	@Test
+	public void a03_outputValidations_pattern() throws Exception {
+		HttpPartSchema ps = schema().pattern("x.*").allowEmptyValue().build();
+		assertEquals("x", s.serialize(ps, "x"));
+		assertEquals("xx", s.serialize(ps, "xx"));
+		assertEquals(null, s.serialize(ps, null));
+
+		try {
+			s.serialize(ps, "y");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Value does not match expected pattern.  Must match pattern: x.*", e.getMessage());
+		}
+
+		try {
+			s.serialize(ps, "");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Value does not match expected pattern.  Must match pattern: x.*", e.getMessage());
+		}
+
+		// Blank/null patterns are ignored.
+		ps = schema().pattern("").allowEmptyValue().build();
+		assertEquals("x", s.serialize(ps, "x"));
+		ps = schema().pattern(null).allowEmptyValue().build();
+		assertEquals("x", s.serialize(ps, "x"));
+	}
+
+	@Test
+	public void a04_outputValidations_enum() throws Exception {
+		HttpPartSchema ps = schema()._enum("foo").allowEmptyValue().build();
+
+		assertEquals("foo", s.serialize(ps, "foo"));
+		assertEquals(null, s.serialize(ps, null));
+
+		try {
+			s.serialize(ps, "bar");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Value does not match one of the expected values.  Must be one of the following: ['foo']", e.getMessage());
+		}
+
+		try {
+			s.serialize(ps, "");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Value does not match one of the expected values.  Must be one of the following: ['foo']", e.getMessage());
+		}
+
+		ps = schema()._enum((Set<String>)null).build();
+		assertEquals("foo", s.serialize(ps, "foo"));
+		ps = schema()._enum((Set<String>)null).allowEmptyValue().build();
+		assertEquals("foo", s.serialize(ps, "foo"));
+
+		ps = schema()._enum("foo","foo").build();
+		assertEquals("foo", s.serialize(ps, "foo"));
+	}
+
+	@Test
+	public void a05_outputValidations_minMaxLength() throws Exception {
+		HttpPartSchema ps = schema().minLength(1l).maxLength(2l).allowEmptyValue().build();
+
+		assertEquals(null, s.serialize(ps, null));
+		assertEquals("1", s.serialize(ps, "1"));
+		assertEquals("12", s.serialize(ps, "12"));
+
+		try {
+			s.serialize(ps, "");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Minimum length of value not met.", e.getMessage());
+		}
+
+		try {
+			s.serialize(ps, "123");
+			fail();
+		} catch (Exception e) {
+			assertEquals("Maximum length of value exceeded.", e.getMessage());
+		}
+	}
+
+//	//-----------------------------------------------------------------------------------------------------------------
+//	// type = string
+//	//-----------------------------------------------------------------------------------------------------------------
+//
+//	public static class C1 {
+//		private String f;
+//		public C1(byte[] b) {
+//			f = "C1-" + new String(b);
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class C2 {
+//		private String f;
+//		public C2(String s) {
+//			f = "C2-" + s;
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class C3 {
+//		private String f;
+//		public C3(String[] in) {
+//			f = "C3-" + JsonSerializer.DEFAULT_LAX.toString(in);
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//
+//	@Test
+//	public void c01_stringType_simple() throws Exception {
+//		HttpPartSchema ps = schema("string").build();
+//		assertEquals("foo", s.serialize(ps, "foo", String.class));
+//	}
+//
+//	@Test
+//	public void c02_stringType_default() throws Exception {
+//		HttpPartSchema ps = schema("string")._default("x").build();
+//		assertEquals("foo", s.serialize(ps, "foo", String.class));
+//		assertEquals("x", s.serialize(ps, null, String.class));
+//	}
+//
+//	@Test
+//	public void c03_stringType_byteFormat() throws Exception {
+//		HttpPartSchema ps = schema("string", "byte").build();
+//		String in = base64Encode("foo".getBytes());
+//		assertEquals("foo", s.serialize(ps, in, String.class));
+//		assertEquals("foo", IOUtils.read(s.serialize(ps, in, InputStream.class)));
+//		assertEquals("foo", IOUtils.read(s.serialize(ps, in, Reader.class)));
+//		assertEquals("C1-foo", s.serialize(ps, in, C1.class).toString());
+//	}
+//
+//	@Test
+//	public void c04_stringType_binaryFormat() throws Exception {
+//		HttpPartSchema ps = schema("string", "binary").build();
+//		String in = toHex("foo".getBytes());
+//		assertEquals("foo", s.serialize(ps, in, String.class));
+//		assertEquals("foo", IOUtils.read(s.serialize(ps, in, InputStream.class)));
+//		assertEquals("foo", IOUtils.read(s.serialize(ps, in, Reader.class)));
+//		assertEquals("C1-foo", s.serialize(ps, in, C1.class).toString());
+//	}
+//
+//	@Test
+//	public void c05_stringType_binarySpacedFormat() throws Exception {
+//		HttpPartSchema ps = schema("string", "binary-spaced").build();
+//		String in = toSpacedHex("foo".getBytes());
+//		assertEquals("foo", s.serialize(ps, in, String.class));
+//		assertEquals("foo", IOUtils.read(s.serialize(ps, in, InputStream.class)));
+//		assertEquals("foo", IOUtils.read(s.serialize(ps, in, Reader.class)));
+//		assertEquals("C1-foo", s.serialize(ps, in, C1.class).toString());
+//	}
+//
+//	@Test
+//	public void c06_stringType_dateFormat() throws Exception {
+//		HttpPartSchema ps = schema("string", "date").build();
+//		String in = "2012-12-21";
+//		assertTrue(s.serialize(ps, in, String.class).contains("2012"));
+//		assertTrue(s.serialize(ps, in, Date.class).toString().contains("2012"));
+//		assertEquals(2012, s.serialize(ps, in, Calendar.class).get(Calendar.YEAR));
+//		assertEquals(2012, s.serialize(ps, in, GregorianCalendar.class).get(Calendar.YEAR));
+//	}
+//
+//	@Test
+//	public void c07_stringType_dateTimeFormat() throws Exception {
+//		HttpPartSchema ps = schema("string", "date-time").build();
+//		String in = "2012-12-21T12:34:56.789";
+//		assertTrue(s.serialize(ps, in, String.class).contains("2012"));
+//		assertTrue(s.serialize(ps, in, Date.class).toString().contains("2012"));
+//		assertEquals(2012, s.serialize(ps, in, Calendar.class).get(Calendar.YEAR));
+//		assertEquals(2012, s.serialize(ps, in, GregorianCalendar.class).get(Calendar.YEAR));
+//	}
+//
+//	@Test
+//	public void c08_stringType_uonFormat() throws Exception {
+//		HttpPartSchema ps = schema("string", "uon").build();
+//		assertEquals("foo", s.serialize(ps, "foo", String.class));
+//		assertEquals("foo", s.serialize(ps, "'foo'", String.class));
+//		assertEquals("C2-foo", s.serialize(ps, "'foo'", C2.class).toString());
+//		// UonPartParserTest should handle all other cases.
+//	}
+//
+//	@Test
+//	public void c09_stringType_noneFormat() throws Exception {
+//		// If no format is specified, then we should transform directly from a string.
+//		HttpPartSchema ps = schema("string").build();
+//		assertEquals("foo", s.serialize(ps, "foo", String.class));
+//		assertEquals("'foo'", s.serialize(ps, "'foo'", String.class));
+//		assertEquals("C2-foo", s.serialize(ps, "foo", C2.class).toString());
+//	}
+//
+//	@Test
+//	public void c10_stringType_noneFormat_2d() throws Exception {
+//		HttpPartSchema ps = schema("array").items(schema("string")).build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", Object[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", List.class, Object.class));
+//		Object o = s.serialize(ps, "foo,bar", Object.class);
+//		assertObjectEquals("['foo','bar']", o);
+//		assertClass(ObjectList.class, o);
+//		assertObjectEquals("['C2-foo','C2-bar']", s.serialize(ps, "foo,bar", C2[].class));
+//		assertObjectEquals("['C2-foo','C2-bar']", s.serialize(ps, "foo,bar", List.class, C2.class));
+//		assertEquals("C3-['foo','bar']", s.serialize(ps, "foo,bar", C3.class).toString());
+//	}
+//
+//	@Test
+//	public void c11_stringType_noneFormat_3d() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").items(schema("array").items(schema("string"))).build();
+//		assertObjectEquals("[['foo','bar'],['baz']]", s.serialize(ps, "foo,bar|baz", String[][].class));
+//		assertObjectEquals("[['foo','bar'],['baz']]", s.serialize(ps, "foo,bar|baz", List.class, String[].class));
+//		assertObjectEquals("[['foo','bar'],['baz']]", s.serialize(ps, "foo,bar|baz", List.class, List.class, String.class));
+//		assertObjectEquals("[['foo','bar'],['baz']]", s.serialize(ps, "foo,bar|baz", Object[][].class));
+//		assertObjectEquals("[['foo','bar'],['baz']]", s.serialize(ps, "foo,bar|baz", List.class, Object[].class));
+//		assertObjectEquals("[['foo','bar'],['baz']]", s.serialize(ps, "foo,bar|baz", List.class, List.class, Object.class));
+//		Object o = s.serialize(ps, "foo,bar|baz", Object.class);
+//		assertObjectEquals("[['foo','bar'],['baz']]", o);
+//		assertClass(ObjectList.class, o);
+//		assertObjectEquals("[['C2-foo','C2-bar'],['C2-baz']]", s.serialize(ps, "foo,bar|baz", C2[][].class));
+//		assertObjectEquals("[['C2-foo','C2-bar'],['C2-baz']]", s.serialize(ps, "foo,bar|baz", List.class, C2[].class));
+//		assertObjectEquals("[['C2-foo','C2-bar'],['C2-baz']]", s.serialize(ps, "foo,bar|baz", List.class, List.class, C2.class));
+//		assertObjectEquals("['C3-[\\'foo\\',\\'bar\\']','C3-[\\'baz\\']']", s.serialize(ps, "foo,bar|baz", C3[].class));
+//		assertObjectEquals("['C3-[\\'foo\\',\\'bar\\']','C3-[\\'baz\\']']", s.serialize(ps, "foo,bar|baz", List.class, C3.class));
+//	}
+//
+//	//-----------------------------------------------------------------------------------------------------------------
+//	// type = array
+//	//-----------------------------------------------------------------------------------------------------------------
+//
+//	public static class D {
+//		private String f;
+//		public D(String in) {
+//			this.f = "D-" + in;
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	@Test
+//	public void d01_arrayType_collectionFormatCsv() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("csv").build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", Object[].class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo,bar", D[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", List.class, Object.class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo,bar", List.class, D.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", Object.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", ObjectList.class));
+//	}
+//
+//	@Test
+//	public void d02_arrayType_collectionFormatPipes() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo|bar", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo|bar", Object[].class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo|bar", D[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo|bar", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo|bar", List.class, Object.class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo|bar", List.class, D.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo|bar", Object.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo|bar", ObjectList.class));
+//	}
+//
+//	@Test
+//	public void d03_arrayType_collectionFormatSsv() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("ssv").build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo bar", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo bar", Object[].class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo bar", D[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo bar", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo bar", List.class, Object.class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo bar", List.class, D.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo bar", Object.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo bar", ObjectList.class));
+//	}
+//
+//	@Test
+//	public void d04_arrayType_collectionFormatTsv() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("tsv").build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo\tbar", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo\tbar", Object[].class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo\tbar", D[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo\tbar", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo\tbar", List.class, Object.class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo\tbar", List.class, D.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo\tbar", Object.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo\tbar", ObjectList.class));
+//	}
+//
+//	@Test
+//	public void d05_arrayType_collectionFormatUon() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("uon").build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", Object[].class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "@(foo,bar)", D[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", List.class, Object.class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "@(foo,bar)", List.class, D.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", Object.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", ObjectList.class));
+//	}
+//
+//	@Test
+//	public void d06a_arrayType_collectionFormatNone() throws Exception {
+//		HttpPartSchema ps = schema("array").build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", Object[].class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo,bar", D[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", List.class, Object.class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "foo,bar", List.class, D.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "foo,bar", Object.class));
+//	}
+//
+//	@Test
+//	public void d06b_arrayType_collectionFormatNone_autoDetectUon() throws Exception {
+//		HttpPartSchema ps = schema("array").build();
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", String[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", Object[].class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "@(foo,bar)", D[].class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", List.class, String.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", List.class, Object.class));
+//		assertObjectEquals("['D-foo','D-bar']", s.serialize(ps, "@(foo,bar)", List.class, D.class));
+//		assertObjectEquals("['foo','bar']", s.serialize(ps, "@(foo,bar)", Object.class));
+//	}
+//
+//	@Test
+//	public void d07_arrayType_collectionFormatMulti() throws Exception {
+//		// collectionFormat=multi should not do any sort of splitting.
+//		HttpPartSchema ps = schema("array").collectionFormat("multi").build();
+//		assertObjectEquals("['foo,bar']", s.serialize(ps, "foo,bar", String[].class));
+//		assertObjectEquals("['foo,bar']", s.serialize(ps, "foo,bar", Object[].class));
+//		assertObjectEquals("['D-foo,bar']", s.serialize(ps, "foo,bar", D[].class));
+//		assertObjectEquals("['foo,bar']", s.serialize(ps, "foo,bar", List.class, String.class));
+//		assertObjectEquals("['foo,bar']", s.serialize(ps, "foo,bar", List.class, Object.class));
+//		assertObjectEquals("['D-foo,bar']", s.serialize(ps, "foo,bar", List.class, D.class));
+//		assertObjectEquals("['foo,bar']", s.serialize(ps, "foo,bar", Object.class));
+//	}
+//
+//	@Test
+//	public void d08_arrayType_collectionFormatCsvAndPipes() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").items(schema("array").collectionFormat("csv")).build();
+//		assertObjectEquals("[['foo','bar'],['baz','qux']]", s.serialize(ps, "foo,bar|baz,qux", String[][].class));
+//		assertObjectEquals("[['foo','bar'],['baz','qux']]", s.serialize(ps, "foo,bar|baz,qux", Object[][].class));
+//		assertObjectEquals("[['D-foo','D-bar'],['D-baz','D-qux']]", s.serialize(ps, "foo,bar|baz,qux", D[][].class));
+//		assertObjectEquals("[['foo','bar'],['baz','qux']]", s.serialize(ps, "foo,bar|baz,qux", List.class, List.class, String.class));
+//		assertObjectEquals("[['foo','bar'],['baz','qux']]", s.serialize(ps, "foo,bar|baz,qux", List.class, List.class, Object.class));
+//		assertObjectEquals("[['D-foo','D-bar'],['D-baz','D-qux']]", s.serialize(ps, "foo,bar|baz,qux", List.class, List.class, D.class));
+//		assertObjectEquals("[['foo','bar'],['baz','qux']]", s.serialize(ps, "foo,bar|baz,qux", Object.class));
+//	}
+//
+//	@Test
+//	public void d09_arrayType_itemsInteger() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("csv").items(schema("integer")).build();
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", int[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Integer[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Object[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Integer.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Object.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Object.class));
+//	}
+//
+//	//-----------------------------------------------------------------------------------------------------------------
+//	// type = boolean
+//	//-----------------------------------------------------------------------------------------------------------------
+//
+//	public static class E1 {
+//		private String f;
+//		public E1(Boolean in) {
+//			this.f = "E1-" + in.toString();
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class E2 {
+//		private String f;
+//		public E2(Boolean[] in) {
+//			this.f = "E2-" + JsonSerializer.DEFAULT_LAX.toString(in);
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	@Test
+//	public void e01_booleanType() throws Exception {
+//		HttpPartSchema ps = schema("boolean").build();
+//		assertEquals(true, s.serialize(ps, "true", boolean.class));
+//		assertEquals(true, s.serialize(ps, "true", Boolean.class));
+//		assertEquals(true, s.serialize(ps, "True", boolean.class));
+//		assertEquals(true, s.serialize(ps, "TRUE", boolean.class));
+//		assertEquals("true", s.serialize(ps, "true", String.class));
+//		assertEquals(true, s.serialize(ps, "true", Object.class));
+//		assertObjectEquals("'E1-true'", s.serialize(ps, "true", E1.class));
+//	}
+//
+//	@Test
+//	public void e02_booleanType_2d() throws Exception {
+//		HttpPartSchema ps = schema("array").items(schema("boolean")).build();
+//		assertObjectEquals("[true,true]", s.serialize(ps, "true,true", boolean[].class));
+//		assertObjectEquals("[true,true]", s.serialize(ps, "true,true", Boolean[].class));
+//		assertObjectEquals("[true,true]", s.serialize(ps, "true,true", List.class, Boolean.class));
+//		assertObjectEquals("['true','true']", s.serialize(ps, "true,true", String[].class));
+//		assertObjectEquals("['true','true']", s.serialize(ps, "true,true", List.class, String.class));
+//		assertObjectEquals("[true,true]", s.serialize(ps, "true,true", Object[].class));
+//		assertObjectEquals("[true,true]", s.serialize(ps, "true,true", List.class, Object.class));
+//		assertObjectEquals("['E1-true','E1-true']", s.serialize(ps, "true,true", E1[].class));
+//		assertObjectEquals("['E1-true','E1-true']", s.serialize(ps, "true,true", List.class, E1.class));
+//		assertObjectEquals("'E2-[true,true]'", s.serialize(ps, "true,true", E2.class));
+//
+//		assertObjectEquals("[true,true]", s.serialize(ps, "True,true", boolean[].class));
+//		assertObjectEquals("[true,true]", s.serialize(ps, "TRUE,true", boolean[].class));
+//	}
+//
+//	@Test
+//	public void e03_booleanType_3d() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").items(schema("array").items(schema("boolean"))).build();
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", boolean[][].class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", List.class, boolean[].class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", Boolean[][].class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", List.class, Boolean[].class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", List.class, List.class, Boolean.class));
+//		assertObjectEquals("[['true','true'],['false']]", s.serialize(ps, "true,true|false", String[][].class));
+//		assertObjectEquals("[['true','true'],['false']]", s.serialize(ps, "true,true|false", List.class, List.class, String.class));
+//		assertObjectEquals("[['true','true'],['false']]", s.serialize(ps, "true,true|false", List.class, String[].class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", Object[][].class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", List.class, List.class, Object.class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "true,true|false", List.class, Object[].class));
+//		assertObjectEquals("[['E1-true','E1-true'],['E1-false']]", s.serialize(ps, "true,true|false", E1[][].class));
+//		assertObjectEquals("[['E1-true','E1-true'],['E1-false']]", s.serialize(ps, "true,true|false", List.class, List.class, E1.class));
+//		assertObjectEquals("[['E1-true','E1-true'],['E1-false']]", s.serialize(ps, "true,true|false", List.class, E1[].class));
+//		assertObjectEquals("['E2-[true,true]','E2-[false]']", s.serialize(ps, "true,true|false", E2[].class));
+//		assertObjectEquals("['E2-[true,true]','E2-[false]']", s.serialize(ps, "true,true|false", List.class, E2.class));
+//
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "True,true|false", boolean[][].class));
+//		assertObjectEquals("[[true,true],[false]]", s.serialize(ps, "TRUE,true|false", boolean[][].class));
+//	}
+//
+//	//-----------------------------------------------------------------------------------------------------------------
+//	// type = integer
+//	//-----------------------------------------------------------------------------------------------------------------
+//
+//	public static class F1 {
+//		private String f;
+//		public F1(Integer in) {
+//			this.f = "F1-" + in.toString();
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class F2 {
+//		private String f;
+//		public F2(Integer[] in) {
+//			this.f = "F2-" + JsonSerializer.DEFAULT_LAX.toString(in);
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class F3 {
+//		private String f;
+//		public F3(Long in) {
+//			this.f = "F3-" + in.toString();
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class F4 {
+//		private String f;
+//		public F4(Long[] in) {
+//			this.f = "F4-" + JsonSerializer.DEFAULT_LAX.toString(in);
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	@Test
+//	public void f01_integerType_int32() throws Exception {
+//		HttpPartSchema ps = schema("integer", "int32").build();
+//		assertObjectEquals("1", s.serialize(ps, "1", int.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", Integer.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", short.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", Short.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", long.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", Long.class));
+//		assertObjectEquals("'1'", s.serialize(ps, "1", String.class));
+//		Object o = s.serialize(ps, "1", Object.class);
+//		assertObjectEquals("1", o);
+//		assertClass(Integer.class, o);
+//		assertObjectEquals("'F1-1'", s.serialize(ps,  "1", F1.class));
+//	}
+//
+//	@Test
+//	public void f02_integerType_int32_2d() throws Exception {
+//		HttpPartSchema ps = schema("array").items(schema("integer", "int32")).build();
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", int[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Integer[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Integer.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", short[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Short[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Short.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", long[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Long[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Long.class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", String[].class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", List.class, String.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Object[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Object.class));
+//		assertObjectEquals("['F1-1','F1-2']", s.serialize(ps,  "1,2", F1[].class));
+//		assertObjectEquals("['F1-1','F1-2']", s.serialize(ps,  "1,2", List.class, F1.class));
+//		assertObjectEquals("'F2-[1,2]'", s.serialize(ps,  "1,2", F2.class));
+//	}
+//
+//	@Test
+//	public void f03_integerType_int32_3d() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").items(schema("array").items(schema("integer", "int32"))).build();
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", int[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, int[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Integer[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Integer[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Integer.class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", short[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, short[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Short[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Short[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Short.class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", long[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, long[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Long[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Long[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Long.class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", String[][].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, String[].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, List.class, String.class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Object[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Object[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Object.class));
+//		assertObjectEquals("[['F1-1','F1-2'],['F1-3']]", s.serialize(ps,  "1,2|3", F1[][].class));
+//		assertObjectEquals("[['F1-1','F1-2'],['F1-3']]", s.serialize(ps,  "1,2|3", List.class, F1[].class));
+//		assertObjectEquals("[['F1-1','F1-2'],['F1-3']]", s.serialize(ps,  "1,2|3", List.class, List.class, F1.class));
+//		assertObjectEquals("['F2-[1,2]','F2-[3]']", s.serialize(ps, "1,2|3", F2[].class));
+//		assertObjectEquals("['F2-[1,2]','F2-[3]']", s.serialize(ps, "1,2|3", List.class, F2.class));
+//	}
+//
+//	@Test
+//	public void f04_integerType_int64() throws Exception {
+//		HttpPartSchema ps = schema("integer", "int64").build();
+//		assertObjectEquals("1", s.serialize(ps, "1", int.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", Integer.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", short.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", Short.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", long.class));
+//		assertObjectEquals("1", s.serialize(ps, "1", Long.class));
+//		assertObjectEquals("'1'", s.serialize(ps, "1", String.class));
+//		Object o = s.serialize(ps, "1", Object.class);
+//		assertObjectEquals("1", o);
+//		assertClass(Long.class, o);
+//		assertObjectEquals("'F3-1'", s.serialize(ps,  "1", F3.class));
+//	}
+//
+//	@Test
+//	public void f05_integerType_int64_2d() throws Exception {
+//		HttpPartSchema ps = schema("array").items(schema("integer", "int64")).build();
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", int[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Integer[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Integer.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", short[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Short[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Short.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", long[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Long[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Long.class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", String[].class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", List.class, String.class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", Object[].class));
+//		assertObjectEquals("[1,2]", s.serialize(ps, "1,2", List.class, Object.class));
+//		assertObjectEquals("['F3-1','F3-2']", s.serialize(ps,  "1,2", F3[].class));
+//		assertObjectEquals("['F3-1','F3-2']", s.serialize(ps,  "1,2", List.class, F3.class));
+//		assertObjectEquals("'F4-[1,2]'", s.serialize(ps,  "1,2", F4.class));
+//	}
+//
+//	@Test
+//	public void f06_integerType_int64_3d() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").items(schema("array").items(schema("integer", "int64"))).build();
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", int[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, int[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Integer[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Integer[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Integer.class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", short[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, short[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Short[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Short[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Short.class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", long[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, long[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Long[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Long[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Long.class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", String[][].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, String[].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, List.class, String.class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", Object[][].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, Object[].class));
+//		assertObjectEquals("[[1,2],[3]]", s.serialize(ps, "1,2|3", List.class, List.class, Object.class));
+//		assertObjectEquals("[['F3-1','F3-2'],['F3-3']]", s.serialize(ps,  "1,2|3", F3[][].class));
+//		assertObjectEquals("[['F3-1','F3-2'],['F3-3']]", s.serialize(ps,  "1,2|3", List.class, F3[].class));
+//		assertObjectEquals("[['F3-1','F3-2'],['F3-3']]", s.serialize(ps,  "1,2|3", List.class, List.class, F3.class));
+//		assertObjectEquals("['F4-[1,2]','F4-[3]']", s.serialize(ps, "1,2|3", F4[].class));
+//		assertObjectEquals("['F4-[1,2]','F4-[3]']", s.serialize(ps, "1,2|3", List.class, F4.class));
+//	}
+//
+//
+//	//-----------------------------------------------------------------------------------------------------------------
+//	// type = number
+//	//-----------------------------------------------------------------------------------------------------------------
+//
+//	public static class G1 {
+//		private String f;
+//		public G1(Float in) {
+//			this.f = "G1-" + in.toString();
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class G2 {
+//		private String f;
+//		public G2(Float[] in) {
+//			this.f = "G2-" + JsonSerializer.DEFAULT_LAX.toString(in);
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class G3 {
+//		private String f;
+//		public G3(Double in) {
+//			this.f = "G3-" + in.toString();
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	public static class G4 {
+//		private String f;
+//		public G4(Double[] in) {
+//			this.f = "G4-" + JsonSerializer.DEFAULT_LAX.toString(in);
+//		}
+//		@Override
+//		public String toString() {
+//			return f;
+//		}
+//	}
+//
+//	@Test
+//	public void g01_numberType_float() throws Exception {
+//		HttpPartSchema ps = schema("number", "float").build();
+//		assertObjectEquals("1.0", s.serialize(ps, "1", float.class));
+//		assertObjectEquals("1.0", s.serialize(ps, "1", Float.class));
+//		assertObjectEquals("1.0", s.serialize(ps, "1", double.class));
+//		assertObjectEquals("1.0", s.serialize(ps, "1", Double.class));
+//		assertObjectEquals("'1'", s.serialize(ps, "1", String.class));
+//		Object o =  s.serialize(ps, "1", Object.class);
+//		assertObjectEquals("1.0",o);
+//		assertClass(Float.class, o);
+//		assertObjectEquals("'G1-1.0'", s.serialize(ps,  "1", G1.class));
+//	}
+//
+//	@Test
+//	public void g02_numberType_float_2d() throws Exception {
+//		HttpPartSchema ps = schema("array").items(schema("number", "float")).build();
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", float[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", Float[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", List.class, Float.class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", double[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", Double[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", List.class, Double.class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", String[].class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", List.class, String.class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", Object[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", List.class, Object.class));
+//		assertObjectEquals("['G1-1.0','G1-2.0']", s.serialize(ps,  "1,2", G1[].class));
+//		assertObjectEquals("['G1-1.0','G1-2.0']", s.serialize(ps,  "1,2", List.class, G1.class));
+//		assertObjectEquals("'G2-[1.0,2.0]'", s.serialize(ps,  "1,2", G2.class));
+//	}
+//
+//	@Test
+//	public void g03_numberType_float_3d() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").items(schema("array").items(schema("number", "float"))).build();
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", float[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, float[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", Float[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, Float[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, List.class, Float.class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", double[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, double[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", Double[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, Double[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, List.class, Double.class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", String[][].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, String[].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, List.class, String.class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", Object[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, Object[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, List.class, Object.class));
+//		assertObjectEquals("[['G1-1.0','G1-2.0'],['G1-3.0']]", s.serialize(ps,  "1,2|3", G1[][].class));
+//		assertObjectEquals("[['G1-1.0','G1-2.0'],['G1-3.0']]", s.serialize(ps,  "1,2|3", List.class, G1[].class));
+//		assertObjectEquals("[['G1-1.0','G1-2.0'],['G1-3.0']]", s.serialize(ps,  "1,2|3", List.class, List.class, G1.class));
+//		assertObjectEquals("['G2-[1.0,2.0]','G2-[3.0]']", s.serialize(ps, "1,2|3", G2[].class));
+//		assertObjectEquals("['G2-[1.0,2.0]','G2-[3.0]']", s.serialize(ps, "1,2|3", List.class, G2.class));
+//	}
+//
+//	@Test
+//	public void g04_numberType_double() throws Exception {
+//		HttpPartSchema ps = schema("number", "double").build();
+//		assertObjectEquals("1.0", s.serialize(ps, "1", float.class));
+//		assertObjectEquals("1.0", s.serialize(ps, "1", Float.class));
+//		assertObjectEquals("1.0", s.serialize(ps, "1", double.class));
+//		assertObjectEquals("1.0", s.serialize(ps, "1", Double.class));
+//		assertObjectEquals("'1'", s.serialize(ps, "1", String.class));
+//		Object o = s.serialize(ps, "1", Object.class);
+//		assertObjectEquals("1.0", o);
+//		assertClass(Double.class, o);
+//		assertObjectEquals("'G3-1.0'", s.serialize(ps,  "1", G3.class));
+//	}
+//
+//	@Test
+//	public void g05_numberType_double_2d() throws Exception {
+//		HttpPartSchema ps = schema("array").items(schema("number", "double")).build();
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", float[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", Float[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", List.class, Float.class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", double[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", Double[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", List.class, Double.class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", String[].class));
+//		assertObjectEquals("['1','2']", s.serialize(ps, "1,2", List.class, String.class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", Object[].class));
+//		assertObjectEquals("[1.0,2.0]", s.serialize(ps, "1,2", List.class, Object.class));
+//		assertObjectEquals("['G3-1.0','G3-2.0']", s.serialize(ps,  "1,2", G3[].class));
+//		assertObjectEquals("['G3-1.0','G3-2.0']", s.serialize(ps,  "1,2", List.class, G3.class));
+//		assertObjectEquals("'G4-[1.0,2.0]'", s.serialize(ps,  "1,2", G4.class));
+//	}
+//
+//	@Test
+//	public void g06_numberType_double_3d() throws Exception {
+//		HttpPartSchema ps = schema("array").collectionFormat("pipes").items(schema("array").items(schema("number", "double"))).build();
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", float[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, float[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", Float[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, Float[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, List.class, Float.class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", double[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, double[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", Double[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, Double[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, List.class, Double.class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", String[][].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, String[].class));
+//		assertObjectEquals("[['1','2'],['3']]", s.serialize(ps, "1,2|3", List.class, List.class, String.class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", Object[][].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, Object[].class));
+//		assertObjectEquals("[[1.0,2.0],[3.0]]", s.serialize(ps, "1,2|3", List.class, List.class, Object.class));
+//		assertObjectEquals("[['G3-1.0','G3-2.0'],['G3-3.0']]", s.serialize(ps,  "1,2|3", G3[][].class));
+//		assertObjectEquals("[['G3-1.0','G3-2.0'],['G3-3.0']]", s.serialize(ps,  "1,2|3", List.class, G3[].class));
+//		assertObjectEquals("[['G3-1.0','G3-2.0'],['G3-3.0']]", s.serialize(ps,  "1,2|3", List.class, List.class, G3.class));
+//		assertObjectEquals("['G4-[1.0,2.0]','G4-[3.0]']", s.serialize(ps, "1,2|3", G4[].class));
+//		assertObjectEquals("['G4-[1.0,2.0]','G4-[3.0]']", s.serialize(ps, "1,2|3", List.class, G4.class));
+//	}
+//
+//
+//	//-----------------------------------------------------------------------------------------------------------------
+//	// type = object
+//	//-----------------------------------------------------------------------------------------------------------------
+//
+//	public static class H1 {
+//		public int f;
+//	}
+//
+//	@Test
+//	public void h01_objectType() throws Exception {
+//		HttpPartSchema ps = HttpPartSchema.create().type("object").build();
+//		assertObjectEquals("{f:1}", s.serialize(ps, "(f=1)", H1.class));
+//		assertObjectEquals("{f:1}", s.serialize(ps, "(f=1)", ObjectMap.class));
+//		Object o = s.serialize(ps, "(f=1)", Object.class);
+//		assertObjectEquals("{f:1}", o);
+//		assertClass(ObjectMap.class, o);
+//	}
+//
+//	@Test
+//	public void h02_objectType_2d() throws Exception {
+//		HttpPartSchema ps = schema("array").format("uon").items(schema("object")).build();
+//		assertObjectEquals("[{f:1},{f:2}]", s.serialize(ps, "@((f=1),(f=2))", H1[].class));
+//		assertObjectEquals("[{f:1},{f:2}]", s.serialize(ps, "@((f=1),(f=2))", List.class, H1.class));
+//		assertObjectEquals("[{f:1},{f:2}]", s.serialize(ps, "@((f=1),(f=2))", ObjectMap[].class));
+//		assertObjectEquals("[{f:1},{f:2}]", s.serialize(ps, "@((f=1),(f=2))", List.class, ObjectMap.class));
+//		assertObjectEquals("[{f:1},{f:2}]", s.serialize(ps, "@((f=1),(f=2))", Object[].class));
+//		assertObjectEquals("[{f:1},{f:2}]", s.serialize(ps, "@((f=1),(f=2))", List.class, Object.class));
+//		Object o = s.serialize(ps, "@((f=1),(f=2))", Object.class);
+//		assertObjectEquals("[{f:1},{f:2}]", o);
+//		assertClass(ObjectList.class, o);
+//	}
+//
+//	@Test
+//	public void h03_objectType_3d() throws Exception {
+//		HttpPartSchema ps = schema("array").format("uon").items(schema("array").items(schema("object"))).build();
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", H1[][].class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", List.class, H1[].class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", List.class, List.class, H1.class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", ObjectMap[][].class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", List.class, ObjectMap[].class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", List.class, List.class, ObjectMap.class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", Object[][].class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", List.class, Object[].class));
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", List.class, List.class, Object.class));
+//		Object o =  s.serialize(ps, "@(@((f=1),(f=2)),@((f=3)))", Object.class);
+//		assertObjectEquals("[[{f:1},{f:2}],[{f:3}]]", o);
+//		assertClass(ObjectList.class, o);
+//	}
+//
+//	public static class H2 {
+//		public Object f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f99;
+//	}
+//
+//	@Test
+//	public void h04_objectType_simpleProperties() throws Exception {
+//		HttpPartSchema ps = schema("object")
+//			.property("f1", schema("string"))
+//			.property("f2", schema("string", "byte"))
+//			.property("f4", schema("string", "date-time"))
+//			.property("f5", schema("string", "binary"))
+//			.property("f6", schema("string", "binary-spaced"))
+//			.property("f7", schema("string", "uon"))
+//			.property("f8", schema("integer"))
+//			.property("f9", schema("integer", "int64"))
+//			.property("f10", schema("number"))
+//			.property("f11", schema("number", "double"))
+//			.property("f12", schema("boolean"))
+//			.additionalProperties(schema("integer"))
+//			.build();
+//
+//		byte[] foob = "foo".getBytes();
+//		String in = "(f1=foo,f2="+base64Encode(foob)+",f4=2012-12-21T12:34:56Z,f5="+toHex(foob)+",f6='"+toSpacedHex(foob)+"',f7=foo,f8=1,f9=1,f10=1,f11=1,f12=true,f99=1)";
+//
+//		H2 h2 = s.serialize(ps, in, H2.class);
+//		assertObjectEquals("{f1:'foo',f2:[102,111,111],f4:'2012-12-21T12:34:56Z',f5:[102,111,111],f6:[102,111,111],f7:'foo',f8:1,f9:1,f10:1.0,f11:1.0,f12:true,f99:1}", h2);
+//		assertClass(String.class, h2.f1);
+//		assertClass(byte[].class, h2.f2);
+//		assertClass(GregorianCalendar.class, h2.f4);
+//		assertClass(byte[].class, h2.f5);
+//		assertClass(byte[].class, h2.f6);
+//		assertClass(String.class, h2.f7);
+//		assertClass(Integer.class, h2.f8);
+//		assertClass(Long.class, h2.f9);
+//		assertClass(Float.class, h2.f10);
+//		assertClass(Double.class, h2.f11);
+//		assertClass(Boolean.class, h2.f12);
+//		assertClass(Integer.class, h2.f99);
+//
+//		ObjectMap om = s.serialize(ps, in, ObjectMap.class);
+//		assertObjectEquals("{f1:'foo',f2:[102,111,111],f4:'2012-12-21T12:34:56Z',f5:[102,111,111],f6:[102,111,111],f7:'foo',f8:1,f9:1,f10:1.0,f11:1.0,f12:true,f99:1}", om);
+//		assertClass(String.class, om.get("f1"));
+//		assertClass(byte[].class, om.get("f2"));
+//		assertClass(GregorianCalendar.class, om.get("f4"));
+//		assertClass(byte[].class, om.get("f5"));
+//		assertClass(byte[].class, om.get("f6"));
+//		assertClass(String.class, om.get("f7"));
+//		assertClass(Integer.class, om.get("f8"));
+//		assertClass(Long.class, om.get("f9"));
+//		assertClass(Float.class, om.get("f10"));
+//		assertClass(Double.class, om.get("f11"));
+//		assertClass(Boolean.class, om.get("f12"));
+//		assertClass(Integer.class, om.get("f99"));
+//
+//		om = (ObjectMap)s.serialize(ps, in, Object.class);
+//		assertObjectEquals("{f1:'foo',f2:[102,111,111],f4:'2012-12-21T12:34:56Z',f5:[102,111,111],f6:[102,111,111],f7:'foo',f8:1,f9:1,f10:1.0,f11:1.0,f12:true,f99:1}", om);
+//		assertClass(String.class, om.get("f1"));
+//		assertClass(byte[].class, om.get("f2"));
+//		assertClass(GregorianCalendar.class, om.get("f4"));
+//		assertClass(byte[].class, om.get("f5"));
+//		assertClass(byte[].class, om.get("f6"));
+//		assertClass(String.class, om.get("f7"));
+//		assertClass(Integer.class, om.get("f8"));
+//		assertClass(Long.class, om.get("f9"));
+//		assertClass(Float.class, om.get("f10"));
+//		assertClass(Double.class, om.get("f11"));
+//		assertClass(Boolean.class, om.get("f12"));
+//		assertClass(Integer.class, om.get("f99"));
+//	}
+//
+//	@Test
+//	public void h05_objectType_arrayProperties() throws Exception {
+//		HttpPartSchema ps = schema("object")
+//			.property("f1", schema("array").items(schema("string")))
+//			.property("f2", schema("array").items(schema("string", "byte")))
+//			.property("f4", schema("array").items(schema("string", "date-time")))
+//			.property("f5", schema("array").items(schema("string", "binary")))
+//			.property("f6", schema("array").items(schema("string", "binary-spaced")))
+//			.property("f7", schema("array").items(schema("string", "uon")))
+//			.property("f8", schema("array").items(schema("integer")))
+//			.property("f9", schema("array").items(schema("integer", "int64")))
+//			.property("f10", schema("array").items(schema("number")))
+//			.property("f11", schema("array").items(schema("number", "double")))
+//			.property("f12", schema("array").items(schema("boolean")))
+//			.additionalProperties(schema("array").items(schema("integer")))
+//			.build();
+//
+//		byte[] foob = "foo".getBytes();
+//		String in = "(f1=foo,f2="+base64Encode(foob)+",f4=2012-12-21T12:34:56Z,f5="+toHex(foob)+",f6='"+toSpacedHex(foob)+"',f7=foo,f8=1,f9=1,f10=1,f11=1,f12=true,f99=1)";
+//
+//		H2 h2 = s.serialize(ps, in, H2.class);
+//		assertObjectEquals("{f1:['foo'],f2:[[102,111,111]],f4:['2012-12-21T12:34:56Z'],f5:[[102,111,111]],f6:[[102,111,111]],f7:['foo'],f8:[1],f9:[1],f10:[1.0],f11:[1.0],f12:[true],f99:[1]}", h2);
+//
+//		ObjectMap om = s.serialize(ps, in, ObjectMap.class);
+//		assertObjectEquals("{f1:['foo'],f2:[[102,111,111]],f4:['2012-12-21T12:34:56Z'],f5:[[102,111,111]],f6:[[102,111,111]],f7:['foo'],f8:[1],f9:[1],f10:[1.0],f11:[1.0],f12:[true],f99:[1]}", om);
+//
+//		om = (ObjectMap)s.serialize(ps, in, Object.class);
+//		assertObjectEquals("{f1:['foo'],f2:[[102,111,111]],f4:['2012-12-21T12:34:56Z'],f5:[[102,111,111]],f6:[[102,111,111]],f7:['foo'],f8:[1],f9:[1],f10:[1.0],f11:[1.0],f12:[true],f99:[1]}", om);
+//	}
+//
+//	@Test
+//	public void h06_objectType_arrayProperties_pipes() throws Exception {
+//		HttpPartSchema ps = schema("object")
+//			.property("f1", schema("array").collectionFormat("pipes").items(schema("string")))
+//			.property("f2", schema("array").collectionFormat("pipes").items(schema("string", "byte")))
+//			.property("f4", schema("array").collectionFormat("pipes").items(schema("string", "date-time")))
+//			.property("f5", schema("array").collectionFormat("pipes").items(schema("string", "binary")))
+//			.property("f6", schema("array").collectionFormat("pipes").items(schema("string", "binary-spaced")))
+//			.property("f7", schema("array").collectionFormat("pipes").items(schema("string", "uon")))
+//			.property("f8", schema("array").collectionFormat("pipes").items(schema("integer")))
+//			.property("f9", schema("array").collectionFormat("pipes").items(schema("integer", "int64")))
+//			.property("f10", schema("array").collectionFormat("pipes").items(schema("number")))
+//			.property("f11", schema("array").collectionFormat("pipes").items(schema("number", "double")))
+//			.property("f12", schema("array").collectionFormat("pipes").items(schema("boolean")))
+//			.additionalProperties(schema("array").collectionFormat("pipes").items(schema("integer")))
+//			.build();
+//
+//		byte[] foob = "foo".getBytes(), barb = "bar".getBytes();
+//		String in = "(f1=foo|bar,f2="+base64Encode(foob)+"|"+base64Encode(barb)+",f4=2012-12-21T12:34:56Z|2012-12-21T12:34:56Z,f5="+toHex(foob)+"|"+toHex(barb)+",f6='"+toSpacedHex(foob)+"|"+toSpacedHex(barb)+"',f7=foo|bar,f8=1|2,f9=1|2,f10=1|2,f11=1|2,f12=true|true,f99=1|2)";
+//
+//		H2 h2 = s.serialize(ps, in, H2.class);
+//		assertObjectEquals("{f1:['foo','bar'],f2:[[102,111,111],[98,97,114]],f4:['2012-12-21T12:34:56Z','2012-12-21T12:34:56Z'],f5:[[102,111,111],[98,97,114]],f6:[[102,111,111],[98,97,114]],f7:['foo','bar'],f8:[1,2],f9:[1,2],f10:[1.0,2.0],f11:[1.0,2.0],f12:[true,true],f99:[1,2]}", h2);
+//
+//		ObjectMap om = s.serialize(ps, in, ObjectMap.class);
+//		assertObjectEquals("{f1:['foo','bar'],f2:[[102,111,111],[98,97,114]],f4:['2012-12-21T12:34:56Z','2012-12-21T12:34:56Z'],f5:[[102,111,111],[98,97,114]],f6:[[102,111,111],[98,97,114]],f7:['foo','bar'],f8:[1,2],f9:[1,2],f10:[1.0,2.0],f11:[1.0,2.0],f12:[true,true],f99:[1,2]}", om);
+//
+//		om = (ObjectMap)s.serialize(ps, in, Object.class);
+//		assertObjectEquals("{f1:['foo','bar'],f2:[[102,111,111],[98,97,114]],f4:['2012-12-21T12:34:56Z','2012-12-21T12:34:56Z'],f5:[[102,111,111],[98,97,114]],f6:[[102,111,111],[98,97,114]],f7:['foo','bar'],f8:[1,2],f9:[1,2],f10:[1.0,2.0],f11:[1.0,2.0],f12:[true,true],f99:[1,2]}", om);
+//	}
+//
+	//-----------------------------------------------------------------------------------------------------------------
+	// Utility methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private static HttpPartSchemaBuilder schema() {
+		return HttpPartSchema.create();
+	}
+//
+//	private static HttpPartSchemaBuilder schema(String type) {
+//		return HttpPartSchema.create(type);
+//	}
+//
+//	private static HttpPartSchemaBuilder schema(String type, String format) {
+//		return HttpPartSchema.create(type, format);
+//	}
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 8c7fba9..7feb819 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -681,9 +681,8 @@ public class BeanSession extends Session {
 					return (T)((Calendar)value).getTime();
 			}
 
-			Transform t = type.getTransform(value.getClass());
-			if (t != null)
-				return (T) t.transform(value);
+			if (type.hasTransformForObject(value))
+				return type.transform(value);
 
 			if (type.isBean())
 				return newBeanMap(type.getInnerClass()).load(value.toString()).getBean();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 0a4b1c6..d420d6f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -2081,7 +2081,7 @@ public final class ClassMeta<T> implements Type {
 	 * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from a Reader.
 	 */
 	public boolean hasReaderTransform() {
-		return getTransform(Reader.class) != null;
+		return hasTransform(Reader.class);
 	}
 
 	/**
@@ -2099,7 +2099,7 @@ public final class ClassMeta<T> implements Type {
 	 * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from an InputStream.
 	 */
 	public boolean hasInputStreamTransform() {
-		return getTransform(InputStream.class) != null;
+		return hasTransform(InputStream.class);
 	}
 
 	/**
@@ -2130,6 +2130,38 @@ public final class ClassMeta<T> implements Type {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if this class can be instantiated from the specified type.
+	 *
+	 * @param c The class type to convert from.
+	 * @return <jk>true</jk> if this class can be instantiated from the specified type.
+	 */
+	public boolean hasTransform(Class<?> c) {
+		return getTransform(c) != null;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class can be instantiated from the specified object.
+	 *
+	 * @param o The object to convert from.
+	 * @return <jk>true</jk> if this class can be instantiated from the specified object.
+	 */
+	public boolean hasTransformForObject(Object o) {
+		return getTransform(o.getClass()) != null;
+	}
+
+	/**
+	 * Transforms the specified object into an instance of this class.
+	 *
+	 * @param o The object to transform.
+	 * @return The transformed object.
+	 */
+	@SuppressWarnings({"unchecked","rawtypes"})
+	public T transform(Object o) {
+		Transform t = getTransform(o.getClass());
+		return (T)(t == null ? null : t.transform(o));
+	}
+
+	/**
 	 * Returns the transform for this class for creating instances from other object types.
 	 *
 	 * @param c The transform-from class.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
index 30c7876..e7d5b14 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
@@ -1010,7 +1010,7 @@ public class HttpPartSchema {
 	 * @throws SchemaValidationException if the specified parsed output does not validate against this schema.
 	 */
 	@SuppressWarnings("rawtypes")
-	public Object validateOutput(Object o, BeanContext bc) throws SchemaValidationException {
+	public <T> T validateOutput(T o, BeanContext bc) throws SchemaValidationException {
 		if (o == null) {
 			if (! isValidRequired(o))
 				throw new SchemaValidationException("Required value not provided.");
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
index 14c07c6..d482732 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
@@ -273,25 +273,25 @@ public class OpenApiPartParser extends UonPartParser {
 			if (t == STRING) {
 				if (type.isObject()) {
 					if (f == BYTE)
-						return (T)StringUtils.base64Decode(in);
+						return (T)base64Decode(in);
 					if (f == DATE || f == DATE_TIME)
-						return (T)StringUtils.parseIsoCalendar(in);
+						return (T)parseIsoCalendar(in);
 					if (f == BINARY)
-						return (T)StringUtils.fromHex(in);
+						return (T)fromHex(in);
 					if (f == BINARY_SPACED)
-						return (T)StringUtils.fromSpacedHex(in);
+						return (T)fromSpacedHex(in);
 					if (f == HttpPartSchema.Format.UON)
 						return super.parse(partType, schema, in, type);
 					return (T)in;
 				}
 				if (f == BYTE)
-					return toType(StringUtils.base64Decode(in), type);
+					return toType(base64Decode(in), type);
 				if (f == DATE || f == DATE_TIME)
-					return toType(StringUtils.parseIsoCalendar(in), type);
+					return toType(parseIsoCalendar(in), type);
 				if (f == BINARY)
-					return toType(StringUtils.fromHex(in), type);
+					return toType(fromHex(in), type);
 				if (f == BINARY_SPACED)
-					return toType(StringUtils.fromSpacedHex(in), type);
+					return toType(fromSpacedHex(in), type);
 				if (f == HttpPartSchema.Format.UON)
 					return super.parse(partType, schema, in, type);
 				return toType(in, type);
@@ -333,7 +333,7 @@ public class OpenApiPartParser extends UonPartParser {
 				} else {
 					o = ss;
 				}
-				if (type.getTransform(schema.getParsedType().getInnerClass()) != null)
+				if (type.hasTransform(schema.getParsedType().getInnerClass()))
 					return toType(toType(o, schema.getParsedType()), type);
 				return toType(o, type);
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
index 1eda116..6aac247 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
@@ -12,6 +12,14 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
+import static org.apache.juneau.httppart.HttpPartSchema.CollectionFormat.*;
+import static org.apache.juneau.httppart.HttpPartSchema.Format.*;
+import static org.apache.juneau.httppart.HttpPartSchema.Type.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
 import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
@@ -60,6 +68,12 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	/** Reusable instance of {@link OpenApiPartSerializer}, all default settings. */
 	public static final OpenApiPartSerializer DEFAULT = new OpenApiPartSerializer(PropertyStore.DEFAULT);
 
+	// Cache these for faster lookup
+	private static final BeanContext BC = BeanContext.DEFAULT;
+	private static final ClassMeta<byte[]> CM_ByteArray = BC.getClassMeta(byte[].class);
+	private static final ClassMeta<Calendar> CM_Calendar = BC.getClassMeta(Calendar.class);
+
+	private static final HttpPartSchema DEFAULT_SCHEMA = HttpPartSchema.DEFAULT;
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
@@ -104,168 +118,116 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	// Entry point methods
 	//--------------------------------------------------------------------------------
 
+	/**
+	 * Convenience method for serializing a part.
+	 *
+	 * @param schema
+	 * 	Schema information about the part.
+	 * 	<br>May be <jk>null</jk>.
+	 * 	<br>Not all part serializers use the schema information.
+	 * @param value The value being serialized.
+	 * @return The serialized value.
+	 * @throws SerializeException If a problem occurred while trying to serialize the input.
+	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
+	 */
+	public String serialize(HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
+		return serialize(null, schema, value);
+	}
+
 	@Override /* PartSerializer */
+	@SuppressWarnings("rawtypes")
 	public String serialize(HttpPartType partType, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
-		schema = ObjectUtils.firstNonNull(schema, this.schema, HttpPartSchema.DEFAULT);
-//		ClassMeta<?> type = getClassMetaForObject(value);
-//		String out;
-//
-//		switch (schema.getType()) {
-//			case STRING: {
-//				if (type.isObject()) {
-//					switch (schema.getFormat()) {
-//						case BYTE:
-//							return (T)StringUtils.base64Decode(in);
-//						case DATE:
-//						case DATE_TIME:
-//							return (T)StringUtils.parseIsoCalendar(in);
-//						case BINARY:
-//							return (T)StringUtils.fromHex(in);
-//						case BINARY_SPACED:
-//							return (T)StringUtils.fromSpacedHex(in);
-//						case UON:
-//							return super.parse(partType, schema, in, type);
-//						default:
-//							return (T)in;
-//					}
-//				}
-//				switch (schema.getFormat()) {
-//					case BYTE:
-//						return toType(StringUtils.base64Decode(in), type);
-//					case DATE:
-//					case DATE_TIME:
-//						return toType(StringUtils.parseIsoCalendar(in), type);
-//					case BINARY:
-//						return toType(StringUtils.fromHex(in), type);
-//					case BINARY_SPACED:
-//						return toType(StringUtils.fromSpacedHex(in), type);
-//					case UON:
-//						return super.parse(partType, schema, in, type);
-//					default:
-//						return toType(in, type);
-//				}
-//			}
-//			case ARRAY: {
-//				if (type.isObject())
-//					type = (ClassMeta<T>)CM_ObjectList;
-//
-//				ClassMeta<?> eType = type.isObject() ? string() : type.getElementType();
-//				if (eType == null)
-//					eType = schema.getParsedType().getElementType();
-//
-//				String[] ss = new String[0];
-//				switch (schema.getCollectionFormat()) {
-//					case MULTI:
-//						ss = new String[]{in};
-//						break;
-//					case CSV:
-//						ss = split(in, ',');
-//						break;
-//					case PIPES:
-//						ss = split(in, '|');
-//						break;
-//					case SSV:
-//						ss = splitQuoted(in);
-//						break;
-//					case TSV:
-//						ss = split(in, '\t');
-//						break;
-//					case UON:
-//						return super.parse(partType, null, in, type);
-//					case NONE:
-//						if (firstNonWhitespaceChar(in) == '@' && lastNonWhitespaceChar(in) == ')')
-//							return super.parse(partType, null, in, type);
-//						ss = split(in, ',');
-//				}
-//				Object[] o = null;
-//				if (schema.getItems() != null) {
-//					o = new Object[ss.length];
-//					for (int i = 0; i < ss.length; i++)
-//						o[i] = parse(partType, schema.getItems(), ss[i], eType);
-//				} else {
-//					o = ss;
-//				}
-//				if (type.getTransform(schema.getParsedType().getInnerClass()) != null)
-//					return toType(toType(o, schema.getParsedType()), type);
-//				return toType(o, type);
-//			}
-//			case BOOLEAN: {
-//				if (type.isObject())
-//					type = (ClassMeta<T>)CM_Boolean;
-//				if (type.isBoolean())
-//					return super.parse(partType, schema, in, type);
-//				return toType(super.parse(partType, schema, in, CM_Boolean), type);
-//			}
-//			case INTEGER: {
-//				if (type.isObject()) {
-//					switch (schema.getFormat()) {
-//						case INT64:
-//							type = (ClassMeta<T>)CM_Long;
-//							break;
-//						default:
-//							type = (ClassMeta<T>)CM_Integer;
-//
-//					}
-//				}
-//				if (type.isNumber())
-//					return super.parse(partType, schema, in, type);
-//				return toType(super.parse(partType, schema, in, CM_Integer), type);
-//			}
-//			case NUMBER: {
-//				if (type.isObject()) {
-//					switch (schema.getFormat()) {
-//						case DOUBLE:
-//							type = (ClassMeta<T>)CM_Double;
-//							break;
-//						default:
-//							type = (ClassMeta<T>)CM_Float;
-//					}
-//				}
-//				if (type.isNumber())
-//					return super.parse(partType, schema, in, type);
-//				return toType(super.parse(partType, schema, in, CM_Integer), type);
-//			}
-//			case OBJECT: {
-//				if (type.isObject())
-//					type = (ClassMeta<T>)CM_ObjectMap;
-//				if (schema.hasProperties() && type.isMapOrBean()) {
-//					try {
-//						if (type.isBean()) {
-//							BeanMap<T> m = BC.createBeanSession().newBeanMap(type.getInnerClass());
-//							for (Map.Entry<String,Object> e : parse(partType, DEFAULT_SCHEMA, in, CM_ObjectMap).entrySet()) {
-//								String key = e.getKey();
-//								BeanPropertyMeta bpm = m.getPropertyMeta(key);
-//								m.put(key, parse(partType, schema.getProperty(key), asString(e.getValue()), bpm == null ? object() : bpm.getClassMeta()));
-//							}
-//							return m.getBean();
-//						}
-//						Map<String,Object> m = (Map<String,Object>)type.newInstance();
-//						for (Map.Entry<String,Object> e : parse(partType, DEFAULT_SCHEMA, in, CM_ObjectMap).entrySet()) {
-//							String key = e.getKey();
-//							m.put(key, parse(partType, schema.getProperty(key), asString(e.getValue()), object()));
-//						}
-//						return (T)m;
-//					} catch (Exception e1) {
-//						throw new ParseException(e1, "Could not instantiate type ''{0}''.", type);
-//					}
-//				}
-//				return super.parse(partType, schema, in, type);
-//			}
-//			case FILE: {
-//				throw new ParseException("File part not supported.");
-//			}
-//			case NONE: {
-//				// This should never be returned by HttpPartSchema.getType(ClassMeta).
-//				throw new ParseException("Invalid type.");
-//			}
-//		}
-//	}
-
-
-
-
-		String out = super.serialize(partType, schema, value);
+
+		schema = ObjectUtils.firstNonNull(schema, this.schema, DEFAULT_SCHEMA);
+		ClassMeta<?> type = getClassMetaForObject(value);
+		if (type == null)
+			type = object();
+		HttpPartSchema.Type t = schema.getType(type);
+		HttpPartSchema.Format f = schema.getFormat();
+
+		String out = null;
+
+		schema.validateOutput(value, this);
+
+		if (t == STRING) {
+
+			if (f == BYTE)
+				out = base64Encode(toType(value, CM_ByteArray));
+			else if (f == BINARY)
+				out = toHex(toType(value, CM_ByteArray));
+			else if (f == BINARY_SPACED)
+				out = toSpacedHex(toType(value, CM_ByteArray));
+			else if (f == DATE)
+				out = toIsoDate(toType(value, CM_Calendar));
+			else if (f == DATE_TIME)
+				out = toIsoDateTime(toType(value, CM_Calendar));
+			else if (f == HttpPartSchema.Format.UON)
+				out = super.serialize(partType, schema, value);
+			else
+				out = toType(value, string());
+
+		} else if (t == ARRAY) {
+
+			List<String> l = new ArrayList<>();
+			HttpPartSchema items = schema.getItems();
+			if (type.isArray()) {
+				for (int i = 0; i < Array.getLength(value); i++)
+					l.add(serialize(partType, items, Array.get(value, i)));
+			} else if (type.isCollection()) {
+				for (Object o : (Collection<?>)value)
+					l.add(serialize(partType, items, o));
+			} else {
+				l.add(serialize(partType, items, value));
+			}
+
+			HttpPartSchema.CollectionFormat cf = schema.getCollectionFormat();
+
+			if (cf == MULTI || cf == CSV)
+				out = join(l, ',');
+			else if (cf == PIPES)
+				out = join(l, '|');
+			else if (cf == SSV)
+				out = join(l, ' ');
+			else if (cf == TSV)
+				out = join(l, '\t');
+			else
+				out = super.serialize(partType, null, l);
+
+		} else if (t == BOOLEAN || t == INTEGER || t == NUMBER) {
+			out = super.serialize(partType, null, value);
+
+		} else if (t == OBJECT) {
+			if (schema.hasProperties() && type.isMapOrBean()) {
+				ObjectMap m = new ObjectMap();
+				if (type.isBean()) {
+					for (Map.Entry<String,Object> e : BC.createBeanSession().toBeanMap(value).entrySet())
+						m.put(e.getKey(), serialize(partType, schema.getProperty(e.getKey()), e.getValue()));
+				} else {
+					for (Map.Entry e : (Set<Map.Entry>)((Map)value).entrySet())
+						m.put(asString(e.getKey()), serialize(partType, schema.getProperty(asString(e.getKey())), e.getValue()));
+				}
+				out = super.serialize(m);
+			} else {
+				out = super.serialize(partType, schema, value);
+			}
+
+		} else if (t == FILE) {
+			throw new SerializeException("File part not supported.");
+
+		} else if (t == NO_TYPE) {
+			// This should never be returned by HttpPartSchema.getType(ClassMeta).
+			throw new SerializeException("Invalid type.");
+		}
+
 		schema.validateInput(out);
 		return out;
 	}
+
+	private <T> T toType(Object in, ClassMeta<T> type) throws SerializeException {
+		try {
+			return createBeanSession().convertToType(in, type);
+		} catch (InvalidDataConversionException e) {
+			throw new SerializeException(e.getMessage());
+		}
+	}
 }
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 0c157c3..452fccf 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
@@ -1227,6 +1227,26 @@ public final class StringUtils {
 	}
 
 	/**
+	 * Converts the specified object to an ISO8601 date string.
+	 *
+	 * @param c The object to convert.
+	 * @return The converted object.
+	 */
+	public static String toIsoDate(Calendar c) {
+		return DatatypeConverter.printDate(c);
+	}
+
+	/**
+	 * Converts the specified object to an ISO8601 date-time string.
+	 *
+	 * @param c The object to convert.
+	 * @return The converted object.
+	 */
+	public static String toIsoDateTime(Calendar c) {
+		return DatatypeConverter.printDateTime(c);
+	}
+
+	/**
 	 * Simple utility for replacing variables of the form <js>"{key}"</js> with values in the specified map.
 	 *
 	 * <p>
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 341a600..a9f9c7c 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
@@ -287,6 +287,13 @@ public class BasicRestCallHandler implements RestCallHandler {
 	 */
 	@Override /* RestCallHandler */
 	public synchronized void handleError(HttpServletRequest req, HttpServletResponse res, RestException e) throws IOException {
+		if (context.isDebug()) {
+			String qs = req.getQueryString();
+			int c = e.getOccurrence();
+			String msg = '[' + Integer.toHexString(e.hashCode()) + '.' + e.getStatus() + '.' + c + "] HTTP " + req.getMethod() + " " + e.getStatus() + " " + req.getRequestURI() + (qs == null ? "" : "?" + qs);
+			System.err.println(msg);
+			e.printStackTrace(System.err);
+		}
 		e.setOccurrence(context == null ? 0 : context.getStackTraceOccurrence(e));
 		logger.onError(req, res, e);
 		renderError(req, res, e);
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 1ceebd1..dd36625 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
@@ -811,6 +811,34 @@ public final class RestContext extends BeanContext {
 	public static final String REST_converters = PREFIX + "converters.lo";
 
 	/**
+	 * Configuration property:  Debug mode.
+	 *
+	 * <h5 class='section'>Property:</h5>
+	 * <ul>
+	 * 	<li><b>Name:</b>  <js>"RestContext.debug.b"</js>
+	 * 	<li><b>Data type:</b>  <code>Boolean</code>
+	 * 	<li><b>Default:</b>  <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b>  <jk>false</jk>
+	 * 	<li><b>Annotations:</b>
+	 * 		<ul>
+	 * 			<li class='ja'>{@link RestResource#debug()}
+	 * 		</ul>
+	 * 	<li><b>Methods:</b>
+	 * 		<ul>
+	 * 			<li class='jm'>{@link RestContextBuilder#debug(boolean)}
+	 * 		</ul>
+	 * </ul>
+	 *
+	 * <h5 class='section'>Description:</h5>
+	 * <p>
+	 * Enables the following:
+	 * <ul>
+	 * 	<li>A message and stack trace is printed to STDERR when {@link BasicRestCallHandler#handleError(HttpServletRequest, HttpServletResponse, RestException)} is called.
+	 * </ul>
+	 */
+	public static final String REST_debug = PREFIX + "debug.b";
+
+	/**
 	 * Configuration property:  Default character encoding.
 	 *
 	 * <h5 class='section'>Property:</h5>
@@ -2749,7 +2777,8 @@ public final class RestContext extends BeanContext {
 		allowBodyParam,
 		renderResponseStackTraces,
 		useStackTraceHashes,
-		useClasspathResourceCaching;
+		useClasspathResourceCaching,
+		debug;
 	private final String
 		defaultCharset,
 		clientVersionHeader,
@@ -2874,6 +2903,7 @@ public final class RestContext extends BeanContext {
 			allowedMethodParams = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(StringUtils.split(getStringProperty(REST_allowedMethodParams, "HEAD,OPTIONS")))));
 			renderResponseStackTraces = getBooleanProperty(REST_renderResponseStackTraces, false);
 			useStackTraceHashes = getBooleanProperty(REST_useStackTraceHashes, true);
+			debug = getBooleanProperty(REST_debug, false);
 			defaultCharset = getStringProperty(REST_defaultCharset, "utf-8");
 			maxInput = getLongProperty(REST_maxInput, 100_000_000l);
 			clientVersionHeader = getStringProperty(REST_clientVersionHeader, "X-Client-Version");
@@ -3900,6 +3930,20 @@ public final class RestContext extends BeanContext {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if debug mode is enabled on this resource.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_debug}
+	 * </ul>
+	 *
+	 * @return <jk>true</jk> if setting is enabled.
+	 */
+	public boolean isDebug() {
+		return debug;
+	}
+
+	/**
 	 * Returns the default charset to use on requests and responses when not specified on the request.
 	 *
 	 * <h5 class='section'>See Also:</h5>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index e7c5cbc..a7c9d6b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -223,6 +223,8 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 					defaultCharset(vr.resolve(r.defaultCharset()));
 				if (! r.maxInput().isEmpty())
 					maxInput(vr.resolve(r.maxInput()));
+				if (! r.debug().isEmpty())
+					debug(Boolean.valueOf(vr.resolve(r.debug())));
 				mimeTypes(resolveVars(vr, r.mimeTypes()));
 
 				HtmlDoc hd = r.htmldoc();
@@ -773,6 +775,24 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	}
 
 	/**
+	 * Configuration property:  Debug mode.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_debug}
+	 * 	<li class='jf'>{@link BeanContext#BEAN_debug}
+	 * </ul>
+	 *
+	 * @param value The new value for this setting.
+	 * @return This object (for method chaining).
+	 */
+	@Override
+	public RestContextBuilder debug(boolean value) {
+		super.debug(value);
+		return set(REST_debug, value);
+	}
+
+	/**
 	 * Configuration property:  Default character encoding.
 	 *
 	 * <p>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
index 9337288..adec8b1 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
@@ -17,6 +17,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import javax.servlet.http.*;
+
 import org.apache.juneau.*;
 import org.apache.juneau.config.*;
 import org.apache.juneau.encoders.*;
@@ -943,4 +945,27 @@ public @interface RestResource {
 	 * </ul>
 	 */
 	String useStackTraceHashes() default "";
+
+	/**
+	 * Enable debug mode.
+	 *
+	 * <p>
+	 * Enables the following:
+	 * <ul>
+	 * 	<li>A message and stack trace is printed to STDERR when {@link BasicRestCallHandler#handleError(HttpServletRequest, HttpServletResponse, RestException)} is called.
+	 * </ul>
+	 *
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		Supports <a class="doclink" href="../../../../../overview-summary.html#DefaultRestSvlVariables">initialization-time variables</a>
+	 * 		(e.g. <js>"$L{my.localized.variable}"</js>).
+	 * </ul>
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_debug}
+	 * </ul>
+	 */
+	String debug() default "";
 }


Mime
View raw message