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/08/02 17:28:32 UTC

[juneau] branch master updated: JUNEAU-128 Code improvements around DynamicSwaps

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 5420870  JUNEAU-128 Code improvements around DynamicSwaps
5420870 is described below

commit 5420870b6994d1ae0521314c3b6334d96d7bbd48
Author: JamesBognar <ja...@apache.org>
AuthorDate: Fri Aug 2 13:28:17 2019 -0400

    JUNEAU-128 Code improvements around DynamicSwaps
---
 .../apache/juneau/reflection/ClassInfoTest.java    |   2 +-
 .../juneau/reflection/ExecutableInfoTest.java      |  32 +-
 .../apache/juneau/transform/AutoListSwapTest.java  | 360 ++++++++++
 .../apache/juneau/transform/AutoMapSwapTest.java   | 360 ++++++++++
 .../juneau/transform/AutoNumberSwapTest.java       | 797 +++++++++++++++++++++
 .../juneau/transform/AutoObjectSwapTest.java       | 353 +++++++++
 .../juneau/transform/AutoStringSwapTest.java       | 271 +++++++
 .../apache/juneau/BeanProxyInvocationHandler.java  |   2 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |  25 +-
 .../org/apache/juneau/annotation/BeanIgnore.java   |   2 +-
 .../org/apache/juneau/internal/ClassUtils.java     |  29 +-
 .../apache/juneau/internal/CollectionUtils.java    |  11 +
 .../org/apache/juneau/parser/ParseException.java   |  21 +
 .../java/org/apache/juneau/reflect/ClassInfo.java  |  33 +-
 .../org/apache/juneau/reflect/ExecutableInfo.java  |  73 +-
 .../java/org/apache/juneau/reflect/MethodInfo.java |  22 +-
 .../juneau/serializer/SerializeException.java      |  22 +-
 .../org/apache/juneau/transform/AutoListSwap.java  | 182 +++++
 .../org/apache/juneau/transform/AutoMapSwap.java   | 182 +++++
 .../apache/juneau/transform/AutoNumberSwap.java    | 222 ++++++
 .../apache/juneau/transform/AutoObjectSwap.java    | 183 +++++
 .../apache/juneau/transform/AutoStringSwap.java    | 147 ++++
 .../org/apache/juneau/transform/DynamicSwaps.java  | 129 ----
 .../11.Transforms/02.DefaultPojoSwaps.html         |   2 +-
 24 files changed, 3290 insertions(+), 172 deletions(-)

diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
index cb909e1..30c51a2 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ClassInfoTest.java
@@ -1898,7 +1898,7 @@ public class ClassInfoTest {
 
 	@Test
 	public void isChildOf_null() {
-		assertFalse(ka.isChildOf(null));
+		assertFalse(ka.isChildOf((Class<?>)null));
 	}
 
 	@Test
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
index 64d8287..dd90556 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/reflection/ExecutableInfoTest.java
@@ -472,30 +472,30 @@ public class ExecutableInfoTest {
 
 	@Test
 	public void hasArgs() {
-		assertTrue(e_hasParams.hasArgs(int.class));
-		assertFalse(e_hasParams.hasArgs());
-		assertFalse(e_hasParams.hasArgs(long.class));
-		assertTrue(e_hasNoParams.hasArgs());
-		assertFalse(e_hasNoParams.hasArgs(long.class));
+		assertTrue(e_hasParams.hasParamTypes(int.class));
+		assertFalse(e_hasParams.hasParamTypes(new Class[0]));
+		assertFalse(e_hasParams.hasParamTypes(long.class));
+		assertTrue(e_hasNoParams.hasParamTypes(new Class[0]));
+		assertFalse(e_hasNoParams.hasParamTypes(long.class));
 	}
 
 	@Test
 	public void hasArgParents() {
-		assertTrue(e_hasStringParam.hasArgParents(String.class));
-		assertTrue(e_hasStringParam.hasArgParents(CharSequence.class));
-		assertFalse(e_hasStringParam.hasArgParents(StringBuilder.class));
-		assertFalse(e_hasStringParam.hasArgParents());
-		assertFalse(e_hasStringParam.hasArgParents(String.class, String.class));
-		assertFalse(e_hasStringParam.hasArgParents(long.class));
+		assertTrue(e_hasStringParam.hasParamTypeParents(String.class));
+		assertTrue(e_hasStringParam.hasParamTypeParents(CharSequence.class));
+		assertFalse(e_hasStringParam.hasParamTypeParents(StringBuilder.class));
+		assertFalse(e_hasStringParam.hasParamTypeParents(new Class[0]));
+		assertFalse(e_hasStringParam.hasParamTypeParents(String.class, String.class));
+		assertFalse(e_hasStringParam.hasParamTypeParents(long.class));
 	}
 
 	@Test
 	public void hasFuzzyArgs() {
-		assertTrue(e_hasParams.hasFuzzyArgs(int.class));
-		assertTrue(e_hasParams.hasFuzzyArgs(int.class, long.class));
-		assertFalse(e_hasParams.hasFuzzyArgs(long.class));
-		assertTrue(e_hasNoParams.hasFuzzyArgs());
-		assertTrue(e_hasNoParams.hasFuzzyArgs(long.class));
+		assertTrue(e_hasParams.hasFuzzyParamTypes(int.class));
+		assertTrue(e_hasParams.hasFuzzyParamTypes(int.class, long.class));
+		assertFalse(e_hasParams.hasFuzzyParamTypes(long.class));
+		assertTrue(e_hasNoParams.hasFuzzyParamTypes(new Class[0]));
+		assertTrue(e_hasNoParams.hasFuzzyParamTypes(long.class));
 	}
 
 	@Test
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java
new file mode 100644
index 0000000..3655367
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoListSwapTest.java
@@ -0,0 +1,360 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.junit.Assert.*;
+import static org.apache.juneau.testutils.TestUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoListSwapTest {
+
+	private static final List<String> STRINGLIST = AList.create("foo");
+	private static final ObjectList OBJECTLIST = new ObjectList().append("foo");
+
+	private static PojoSwap find(Class<?> c) {
+		return AutoListSwap.find(ClassInfo.of(c));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Swap methods
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class A01 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+	public static class A02 {
+		public ObjectList toObjectList() {
+			return OBJECTLIST;
+		}
+	}
+	public static class A03 {
+		public ObjectList toObjectList() throws SerializeException {
+			throw new SerializeException("foo");
+		}
+	}
+	public static class A04 {
+		public ObjectList toObjectList() {
+			throw new RuntimeException("foo");
+		}
+	}
+
+	@Test
+	public void a01_swap_toList() throws Exception {
+		assertObjectEquals("['foo']", find(A01.class).swap(null, new A01()));
+	}
+
+	@Test
+	public void a02_swap_toObjectList() throws Exception {
+		assertObjectEquals("['foo']", find(A02.class).swap(null, new A02()));
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a03_swap_serializeException() throws Exception {
+		find(A03.class).swap(null, null);
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a04_swap_runtimeException() throws Exception {
+		find(A04.class).swap(null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap methods
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class B01 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		public static B01 fromList(List<String> o) {
+			assertObjectEquals("['foo']", o);
+			return new B01();
+		}
+	}
+	public static class B02 {
+		public ObjectList toObjectList() {
+			return OBJECTLIST;
+		}
+		public static B02 fromObjectList(ObjectList o) {
+			assertObjectEquals("['foo']", o);
+			return new B02();
+		}
+	}
+	public static class B03 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		public static B03 create(List<String> o) {
+			assertObjectEquals("['foo']", o);
+			return new B03();
+		}
+	}
+	public static class B04 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+
+	@Test
+	public void b01_unswap_fromList() throws Exception {
+		assertNotNull(find(B01.class).unswap(null, STRINGLIST, null));
+	}
+
+	@Test
+	public void b02_unswap_fromObjectList() throws Exception {
+		assertNotNull(find(B02.class).unswap(null, OBJECTLIST, null));
+	}
+
+	@Test
+	public void b03_unswap_create() throws Exception {
+		assertNotNull(find(B03.class).unswap(null, STRINGLIST, null));
+	}
+
+	@Test(expected = ParseException.class)
+	public void b04_unswap_noMethod() throws Exception {
+		find(B04.class).unswap(null, STRINGLIST, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class C01 {
+		public C01() {}
+		public C01(List<String> o) {
+			assertObjectEquals("['foo']", o);
+		}
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+
+	@Test
+	public void c01_unswap_constructor() throws Exception {
+		assertNotNull(find(C01.class).unswap(null, STRINGLIST, null));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore class
+	//------------------------------------------------------------------------------------------------------------------
+
+	@BeanIgnore
+	public static class D01 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+	public static class D02 {
+		public class D02A {
+			public List<String> toList() {
+				return STRINGLIST;
+			}
+		}
+	}
+
+	@Test
+	public void d01_ignoreClass_beanIgnore() throws Exception {
+		assertNull(find(D01.class));
+	}
+
+	@Test
+	public void d02_ignoreClass_memberClass() throws Exception {
+		assertNull(find(D02.D02A.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore swap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class E01 {
+		@BeanIgnore
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+	public static class E02 {
+		@Deprecated
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+	public static class E03 {
+		public Object toList() {
+			return STRINGLIST;
+		}
+	}
+	public static class E04 {
+		public List<String> toList(List<String> foo) {
+			return STRINGLIST;
+		}
+	}
+	public static class E05 {
+		public static List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+
+	@Test
+	public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+		assertNull(find(E01.class));
+	}
+
+	@Test
+	public void e02_ignoreSwapMethod_deprecated() throws Exception {
+		assertNull(find(E02.class));
+	}
+
+	@Test
+	public void e03_ignoreSwapMethod_wrongReturnType() throws Exception {
+		assertNull(find(E03.class));
+	}
+
+	@Test
+	public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+		assertNull(find(E04.class));
+	}
+
+	@Test
+	public void e05_ignoreSwapMethod_notStatic() throws Exception {
+		assertNull(find(E05.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore unswap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class F01 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		@BeanIgnore
+		public static F01 create(List<String> o) {
+			return null;
+		}
+	}
+	public static class F02 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		@Deprecated
+		public static F02 create(List<String> o) {
+			return null;
+		}
+	}
+	public static class F03 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		public static Object create(List<String> o) {
+			return null;
+		}
+	}
+	public static class F04 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		public static F04 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F05 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		public F05 create(List<String> o) {
+			return null;
+		}
+	}
+	public static class F06 {
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+		public static F06 createx(List<String> o) {
+			return null;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+		find(F01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+		find(F02.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+		find(F03.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+		find(F04.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+		find(F05.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+		find(F06.class).unswap(null, null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class G01 {
+		@BeanIgnore
+		public G01(List<String> o) {}
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+
+	public static class G02 {
+		@Deprecated
+		public G02(List<String> o) {}
+		public List<String> toList() {
+			return STRINGLIST;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+		find(G01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+		find(G02.class).unswap(null, null, null);
+	}
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java
new file mode 100644
index 0000000..c32fa0f
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoMapSwapTest.java
@@ -0,0 +1,360 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoMapSwapTest {
+
+	private static final Map<String,String> STRINGMAP = AMap.<String,String>create().append("foo","bar");
+	private static final ObjectMap OBJECTMAP = new ObjectMap().append("foo","bar");
+
+	private static PojoSwap find(Class<?> c) {
+		return AutoMapSwap.find(ClassInfo.of(c));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Swap methods
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class A01 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+	public static class A02 {
+		public ObjectMap toObjectMap() {
+			return OBJECTMAP;
+		}
+	}
+	public static class A03 {
+		public ObjectMap toObjectMap() throws SerializeException {
+			throw new SerializeException("foo");
+		}
+	}
+	public static class A04 {
+		public ObjectMap toObjectMap() {
+			throw new RuntimeException("foo");
+		}
+	}
+
+	@Test
+	public void a01_swap_toMap() throws Exception {
+		assertObjectEquals("{foo:'bar'}", find(A01.class).swap(null, new A01()));
+	}
+
+	@Test
+	public void a02_swap_toObjectMap() throws Exception {
+		assertObjectEquals("{foo:'bar'}", find(A02.class).swap(null, new A02()));
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a03_swap_serializeException() throws Exception {
+		find(A03.class).swap(null, null);
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a04_swap_runtimeException() throws Exception {
+		find(A04.class).swap(null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap methods
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class B01 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		public static B01 fromMap(Map<String,String> o) {
+			assertObjectEquals("{foo:'bar'}", o);
+			return new B01();
+		}
+	}
+	public static class B02 {
+		public ObjectMap toObjectMap() {
+			return OBJECTMAP;
+		}
+		public static B02 fromObjectMap(ObjectMap o) {
+			assertObjectEquals("{foo:'bar'}", o);
+			return new B02();
+		}
+	}
+	public static class B03 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		public static B03 create(Map<String,String> o) {
+			assertObjectEquals("{foo:'bar'}", o);
+			return new B03();
+		}
+	}
+	public static class B04 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test
+	public void b01_unswap_fromMap() throws Exception {
+		assertNotNull(find(B01.class).unswap(null, STRINGMAP, null));
+	}
+
+	@Test
+	public void b02_unswap_fromObjectMap() throws Exception {
+		assertNotNull(find(B02.class).unswap(null, OBJECTMAP, null));
+	}
+
+	@Test
+	public void b03_unswap_create() throws Exception {
+		assertNotNull(find(B03.class).unswap(null, STRINGMAP, null));
+	}
+
+	@Test(expected = ParseException.class)
+	public void b04_unswap_noMethod() throws Exception {
+		find(B04.class).unswap(null, STRINGMAP, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class C01 {
+		public C01() {}
+		public C01(Map<String,String> o) {
+			assertObjectEquals("{foo:'bar'}", o);
+		}
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test
+	public void c01_unswap_constructor() throws Exception {
+		assertNotNull(find(C01.class).unswap(null, STRINGMAP, null));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore class
+	//------------------------------------------------------------------------------------------------------------------
+
+	@BeanIgnore
+	public static class D01 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+	public static class D02 {
+		public class D02A {
+			public Map<String,String> toMap() {
+				return STRINGMAP;
+			}
+		}
+	}
+
+	@Test
+	public void d01_ignoreClass_beanIgnore() throws Exception {
+		assertNull(find(D01.class));
+	}
+
+	@Test
+	public void d02_ignoreClass_memberClass() throws Exception {
+		assertNull(find(D02.D02A.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore swap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class E01 {
+		@BeanIgnore
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+	public static class E02 {
+		@Deprecated
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+	public static class E03 {
+		public Object toMap() {
+			return STRINGMAP;
+		}
+	}
+	public static class E04 {
+		public Map<String,String> toMap(Map<String,String> foo) {
+			return STRINGMAP;
+		}
+	}
+	public static class E05 {
+		public static Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test
+	public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+		assertNull(find(E01.class));
+	}
+
+	@Test
+	public void e02_ignoreSwapMethod_deprecated() throws Exception {
+		assertNull(find(E02.class));
+	}
+
+	@Test
+	public void e03_ignoreSwapMethod_wrongReturnType() throws Exception {
+		assertNull(find(E03.class));
+	}
+
+	@Test
+	public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+		assertNull(find(E04.class));
+	}
+
+	@Test
+	public void e05_ignoreSwapMethod_notStatic() throws Exception {
+		assertNull(find(E05.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore unswap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class F01 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		@BeanIgnore
+		public static F01 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F02 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		@Deprecated
+		public static F02 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F03 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		public static Object create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F04 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		public static F04 create(List<String> o) {
+			return null;
+		}
+	}
+	public static class F05 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		public F05 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F06 {
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+		public static F06 createx(Map<String,String> o) {
+			return null;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+		find(F01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+		find(F02.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+		find(F03.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+		find(F04.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+		find(F05.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+		find(F06.class).unswap(null, null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class G01 {
+		@BeanIgnore
+		public G01(Map<String,String> o) {}
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+
+	public static class G02 {
+		@Deprecated
+		public G02(Map<String,String> o) {}
+		public Map<String,String> toMap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+		find(G01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+		find(G02.class).unswap(null, null, null);
+	}
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java
new file mode 100644
index 0000000..4415e78
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoNumberSwapTest.java
@@ -0,0 +1,797 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoNumberSwapTest {
+
+	private static PojoSwap find(Class<?> c) {
+		return AutoNumberSwap.find(ClassInfo.of(c));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Swap methods
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class A01 {
+		public Number toNumber() {
+			return 1;
+		}
+	}
+	public static class A02 {
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+	public static class A03 {
+		public int toInt() {
+			return 1;
+		}
+	}
+	public static class A04 {
+		public Long toLong() {
+			return 1l;
+		}
+	}
+	public static class A05 {
+		public long toLong() {
+			return 1l;
+		}
+	}
+	public static class A06 {
+		public Float toFloat() {
+			return 1f;
+		}
+	}
+	public static class A07 {
+		public float toFloat() {
+			return 1f;
+		}
+	}
+	public static class A08 {
+		public Double toDouble() {
+			return 1d;
+		}
+	}
+	public static class A09 {
+		public double toDouble() {
+			return 1d;
+		}
+	}
+	public static class A10 {
+		public Short toShort() {
+			return 1;
+		}
+	}
+	public static class A11 {
+		public short toShort() {
+			return 1;
+		}
+	}
+	public static class A12 {
+		public Byte toByte() {
+			return 1;
+		}
+	}
+	public static class A13 {
+		public byte toByte() {
+			return 1;
+		}
+	}
+	public static class A14 {
+		public Integer toInteger() throws SerializeException {
+			throw new SerializeException("foo");
+		}
+	}
+	public static class A15 {
+		public Integer toInteger() {
+			throw new RuntimeException("foo");
+		}
+	}
+
+	@Test
+	public void a01_swap_toNumber() throws Exception {
+		assertObjectEquals("1", find(A01.class).swap(null, new A01()));
+	}
+
+	@Test
+	public void a02_swap_toInteger() throws Exception {
+		assertObjectEquals("1", find(A02.class).swap(null, new A02()));
+	}
+
+	@Test
+	public void a03_swap_toIntPrimitive() throws Exception {
+		assertObjectEquals("1", find(A03.class).swap(null, new A03()));
+	}
+
+	@Test
+	public void a04_swap_toLong() throws Exception {
+		assertObjectEquals("1", find(A04.class).swap(null, new A04()));
+	}
+
+	@Test
+	public void a05_swap_toLongPrimitive() throws Exception {
+		assertObjectEquals("1", find(A05.class).swap(null, new A05()));
+	}
+
+	@Test
+	public void a06_swap_toFloat() throws Exception {
+		assertObjectEquals("1.0", find(A06.class).swap(null, new A06()));
+	}
+
+	@Test
+	public void a07_swap_toFloatPrimitive() throws Exception {
+		assertObjectEquals("1.0", find(A07.class).swap(null, new A07()));
+	}
+
+	@Test
+	public void a08_swap_toDouble() throws Exception {
+		assertObjectEquals("1.0", find(A08.class).swap(null, new A08()));
+	}
+
+	@Test
+	public void a09_swap_toDoublePrimitive() throws Exception {
+		assertObjectEquals("1.0", find(A09.class).swap(null, new A09()));
+	}
+
+	@Test
+	public void a10_swap_toShort() throws Exception {
+		assertObjectEquals("1", find(A10.class).swap(null, new A10()));
+	}
+
+	@Test
+	public void a11_swap_toShortPrimitive() throws Exception {
+		assertObjectEquals("1", find(A11.class).swap(null, new A11()));
+	}
+
+	@Test
+	public void a12_swap_toByte() throws Exception {
+		assertObjectEquals("1", find(A12.class).swap(null, new A12()));
+	}
+
+	@Test
+	public void a13_swap_toBytePrimitive() throws Exception {
+		assertObjectEquals("1", find(A13.class).swap(null, new A13()));
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a14_swap_serializeException() throws Exception {
+		find(A14.class).swap(null, null);
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a15_swap_runtimeException() throws Exception {
+		find(A15.class).swap(null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap methods
+	//------------------------------------------------------------------------------------------------------------------
+//	UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromInteger", "fromInt", "fromLong", "fromFloat", "fromDouble", "fromShort", "fromByte", "create", "valueOf");
+
+	public static class B01 {
+		public Integer toInteger() {
+			return 1;
+		}
+		public static B01 fromInteger(Integer o) {
+			assertObjectEquals("1", o);
+			return new B01();
+		}
+	}
+	public static class B02 {
+		public int toInt() {
+			return 1;
+		}
+		public static B02 fromInt(int o) {
+			assertObjectEquals("1", o);
+			return new B02();
+		}
+	}
+	public static class B03 {
+		public Long toLong() {
+			return 1l;
+		}
+		public static B03 fromLong(Long o) {
+			assertObjectEquals("1", o);
+			return new B03();
+		}
+	}
+	public static class B04 {
+		public long toLong() {
+			return 1;
+		}
+		public static B04 fromLong(long o) {
+			assertObjectEquals("1", o);
+			return new B04();
+		}
+	}
+	public static class B05 {
+		public Float toFloat() {
+			return 1f;
+		}
+		public static B05 fromFloat(Float o) {
+			assertObjectEquals("1.0", o);
+			return new B05();
+		}
+	}
+	public static class B06 {
+		public float toFloat() {
+			return 1;
+		}
+		public static B06 fromFloat(float o) {
+			assertObjectEquals("1.0", o);
+			return new B06();
+		}
+	}
+	public static class B07 {
+		public Double toDouble() {
+			return 1d;
+		}
+		public static B07 fromDouble(Double o) {
+			assertObjectEquals("1.0", o);
+			return new B07();
+		}
+	}
+	public static class B08 {
+		public double toDouble() {
+			return 1d;
+		}
+		public static B08 fromDouble(double o) {
+			assertObjectEquals("1.0", o);
+			return new B08();
+		}
+	}
+	public static class B09 {
+		public Short toShort() {
+			return 1;
+		}
+		public static B09 fromShort(Short o) {
+			assertObjectEquals("1", o);
+			return new B09();
+		}
+	}
+	public static class B10 {
+		public short toShort() {
+			return 1;
+		}
+		public static B10 fromShort(short o) {
+			assertObjectEquals("1", o);
+			return new B10();
+		}
+	}
+	public static class B11 {
+		public Byte toByte() {
+			return 1;
+		}
+		public static B11 fromByte(Byte o) {
+			assertObjectEquals("1", o);
+			return new B11();
+		}
+	}
+	public static class B12 {
+		public byte toByte() {
+			return 1;
+		}
+		public static B12 fromByte(byte o) {
+			assertObjectEquals("1", o);
+			return new B12();
+		}
+	}
+	public static class B13 {
+		public int toInt() {
+			return 1;
+		}
+		public static B13 create(int o) {
+			assertObjectEquals("1", o);
+			return new B13();
+		}
+	}
+	public static class B14 {
+		public int toInt() {
+			return 1;
+		}
+		public static B14 valueOf(int o) {
+			assertObjectEquals("1", o);
+			return new B14();
+		}
+	}
+	public static class B15 {
+		public int toInt() {
+			return 1;
+		}
+	}
+
+	@Test
+	public void b01_unswap_fromInteger() throws Exception {
+		assertNotNull(find(B01.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b02_unswap_fromInt() throws Exception {
+		assertNotNull(find(B02.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b03_unswap_fromLong() throws Exception {
+		assertNotNull(find(B03.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b04_unswap_fromLongPrimitive() throws Exception {
+		assertNotNull(find(B04.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b05_unswap_fromFloat() throws Exception {
+		assertNotNull(find(B05.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b06_unswap_fromFloatPrimitive() throws Exception {
+		assertNotNull(find(B06.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b07_unswap_fromDouble() throws Exception {
+		assertNotNull(find(B07.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b08_unswap_fromDoublePrimitive() throws Exception {
+		assertNotNull(find(B08.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b09_unswap_fromShort() throws Exception {
+		assertNotNull(find(B09.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b10_unswap_fromShortPrimitive() throws Exception {
+		assertNotNull(find(B10.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b11_unswap_fromByte() throws Exception {
+		assertNotNull(find(B11.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b12_unswap_fromBytePrimitive() throws Exception {
+		assertNotNull(find(B12.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b13_unswap_create() throws Exception {
+		assertNotNull(find(B13.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void b14_unswap_valueOf() throws Exception {
+		assertNotNull(find(B14.class).unswap(null, 1, null));
+	}
+
+	@Test(expected = ParseException.class)
+	public void b15_unswap_noMethod() throws Exception {
+		find(B15.class).unswap(null, 1, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class C01 {
+		public C01() {}
+		public C01(Integer o) {
+			assertObjectEquals("1", o);
+		}
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+	public static class C02 {
+		public C02() {}
+		public C02(int o) {
+			assertObjectEquals("1", o);
+		}
+		public int toInt() {
+			return 1;
+		}
+	}
+	public static class C03 {
+		public C03() {}
+		public C03(Long o) {
+			assertObjectEquals("1", o);
+		}
+		public Long toLong() {
+			return 1l;
+		}
+	}
+	public static class C04 {
+		public C04() {}
+		public C04(long o) {
+			assertObjectEquals("1", o);
+		}
+		public long toLong() {
+			return 1l;
+		}
+	}
+	public static class C05 {
+		public C05() {}
+		public C05(Float o) {
+			assertObjectEquals("1.0", o);
+		}
+		public Float toFloat() {
+			return 1f;
+		}
+	}
+	public static class C06 {
+		public C06() {}
+		public C06(float o) {
+			assertObjectEquals("1.0", o);
+		}
+		public float toFloat() {
+			return 1f;
+		}
+	}
+	public static class C07 {
+		public C07() {}
+		public C07(Double o) {
+			assertObjectEquals("1.0", o);
+		}
+		public Double toDouble() {
+			return 1d;
+		}
+	}
+	public static class C08 {
+		public C08() {}
+		public C08(double o) {
+			assertObjectEquals("1.0", o);
+		}
+		public double toDouble() {
+			return 1d;
+		}
+	}
+	public static class C09 {
+		public C09() {}
+		public C09(Short o) {
+			assertObjectEquals("1", o);
+		}
+		public Short toShort() {
+			return 1;
+		}
+	}
+	public static class C10 {
+		public C10() {}
+		public C10(short o) {
+			assertObjectEquals("1", o);
+		}
+		public short toShort() {
+			return 1;
+		}
+	}
+	public static class C11 {
+		public C11() {}
+		public C11(Byte o) {
+			assertObjectEquals("1", o);
+		}
+		public Byte toByte() {
+			return 1;
+		}
+	}
+	public static class C12 {
+		public C12() {}
+		public C12(byte o) {
+			assertObjectEquals("1", o);
+		}
+		public byte toByte() {
+			return 1;
+		}
+	}
+	public static class C13 {
+		public C13() {}
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+
+	@Test
+	public void c01_unswapConstructor_Integer() throws Exception {
+		assertNotNull(find(C01.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c02_unswapConstructor_int() throws Exception {
+		assertNotNull(find(C02.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c03_unswapConstructor_Long() throws Exception {
+		assertNotNull(find(C03.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c04_unswapConstructor_long() throws Exception {
+		assertNotNull(find(C04.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c05_unswapConstructor_Float() throws Exception {
+		assertNotNull(find(C05.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c06_unswapConstructor_float() throws Exception {
+		assertNotNull(find(C06.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c07_unswapConstructor_Double() throws Exception {
+		assertNotNull(find(C07.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c08_unswapConstructor_double() throws Exception {
+		assertNotNull(find(C08.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c09_unswapConstructor_Short() throws Exception {
+		assertNotNull(find(C09.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c10_unswapConstructor_short() throws Exception {
+		assertNotNull(find(C10.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c11_unswapConstructor_Byte() throws Exception {
+		assertNotNull(find(C11.class).unswap(null, 1, null));
+	}
+
+	@Test
+	public void c12_unswapConstructor_byte() throws Exception {
+		assertNotNull(find(C12.class).unswap(null, 1, null));
+	}
+
+	@Test(expected = ParseException.class)
+	public void c13_unswapConstructor_noConstructor() throws Exception {
+		find(C13.class).unswap(null, 1, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore class
+	//------------------------------------------------------------------------------------------------------------------
+
+	@BeanIgnore
+	public static class D01 {
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+	public static class D02 {
+		public class D02A {
+			public Integer toInteger() {
+				return 1;
+			}
+		}
+	}
+
+	@Test
+	public void d01_ignoreClass_beanIgnore() throws Exception {
+		assertNull(find(D01.class));
+	}
+
+	@Test
+	public void d02_ignoreClass_memberClass() throws Exception {
+		assertNull(find(D02.D02A.class));
+	}
+
+	@Test
+	public void d03_ignoreClass_numberSubclass() throws Exception {
+		assertNull(find(Integer.class));
+		assertNull(find(Number.class));
+		assertNull(find(int.class));
+	}
+
+	@Test
+	public void d04_ignoreClass_primitive() throws Exception {
+		assertNull(find(char.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore swap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class E01 {
+		@BeanIgnore
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+	public static class E02 {
+		@Deprecated
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+	public static class E03 {
+		public Object toInteger() {
+			return 1;
+		}
+	}
+	public static class E04 {
+		public Integer toInteger(List<String> foo) {
+			return 1;
+		}
+	}
+	public static class E05 {
+		public static Integer toInteger() {
+			return 1;
+		}
+	}
+
+	@Test
+	public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+		assertNull(find(E01.class));
+	}
+
+	@Test
+	public void e02_ignoreSwapMethod_deprecated() throws Exception {
+		assertNull(find(E02.class));
+	}
+
+	@Test
+	public void e03_ignoreSwapMethod_wrongReturnType() throws Exception {
+		assertNull(find(E03.class));
+	}
+
+	@Test
+	public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+		assertNull(find(E04.class));
+	}
+
+	@Test
+	public void e05_ignoreSwapMethod_notStatic() throws Exception {
+		assertNull(find(E05.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore unswap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class F01 {
+		public Integer toInteger() {
+			return 1;
+		}
+		@BeanIgnore
+		public static F01 create(Integer o) {
+			return null;
+		}
+	}
+	public static class F02 {
+		public Integer toInteger() {
+			return 1;
+		}
+		@Deprecated
+		public static F02 create(Integer o) {
+			return null;
+		}
+	}
+	public static class F03 {
+		public Integer toInteger() {
+			return 1;
+		}
+		public static Object create(Integer o) {
+			return null;
+		}
+	}
+	public static class F04 {
+		public Integer toInteger() {
+			return 1;
+		}
+		public static F04 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F05 {
+		public Integer toInteger() {
+			return 1;
+		}
+		public F05 create(Integer o) {
+			return null;
+		}
+	}
+	public static class F06 {
+		public Integer toInteger() {
+			return 1;
+		}
+		public static F06 createx(Integer o) {
+			return null;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+		find(F01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+		find(F02.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+		find(F03.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+		find(F04.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+		find(F05.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+		find(F06.class).unswap(null, null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class G01 {
+		@BeanIgnore
+		public G01(Integer o) {}
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+
+	public static class G02 {
+		@Deprecated
+		public G02(Integer o) {}
+		public Integer toInteger() {
+			return 1;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+		find(G01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+		find(G02.class).unswap(null, null, null);
+	}
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java
new file mode 100644
index 0000000..a0eda02
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoObjectSwapTest.java
@@ -0,0 +1,353 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.testutils.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoObjectSwapTest {
+
+
+	private static final Map<String,String> STRINGMAP = AMap.<String,String>create().append("foo","bar");
+	private static final ObjectMap OBJECTMAP = new ObjectMap().append("foo","bar");
+
+	private static PojoSwap find(Class<?> c) {
+		return AutoObjectSwap.find(ClassInfo.of(c));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Swap methods
+	//------------------------------------------------------------------------------------------------------------------
+	//SWAP_METHOD_NAMES = newUnmodifiableHashSet("swap", "toObject"),
+
+	public static class A01 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+	public static class A02 {
+		public ObjectMap toObject() {
+			return OBJECTMAP;
+		}
+	}
+	public static class A03 {
+		public ObjectMap toObject() throws SerializeException {
+			throw new SerializeException("foo");
+		}
+	}
+	public static class A04 {
+		public ObjectMap toObject() {
+			throw new RuntimeException("foo");
+		}
+	}
+
+	@Test
+	public void a01_swap_swap() throws Exception {
+		assertObjectEquals("{foo:'bar'}", find(A01.class).swap(null, new A01()));
+	}
+
+	@Test
+	public void a02_swap_toObject() throws Exception {
+		assertObjectEquals("{foo:'bar'}", find(A02.class).swap(null, new A02()));
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a03_swap_serializeException() throws Exception {
+		find(A03.class).swap(null, null);
+	}
+
+	@Test(expected = SerializeException.class)
+	public void a04_swap_runtimeException() throws Exception {
+		find(A04.class).swap(null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap methods
+	//------------------------------------------------------------------------------------------------------------------
+	//UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("unswap", "create", "fromObject");
+
+	public static class B01 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		public static B01 unswap(Map<String,String> o) {
+			assertObjectEquals("{foo:'bar'}", o);
+			return new B01();
+		}
+	}
+	public static class B02 {
+		public ObjectMap swap() {
+			return OBJECTMAP;
+		}
+		public static B02 create(ObjectMap o) {
+			assertObjectEquals("{foo:'bar'}", o);
+			return new B02();
+		}
+	}
+	public static class B03 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		public static B03 fromObject(Map<String,String> o) {
+			assertObjectEquals("{foo:'bar'}", o);
+			return new B03();
+		}
+	}
+	public static class B04 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test
+	public void b01_unswap_unswap() throws Exception {
+		assertNotNull(find(B01.class).unswap(null, STRINGMAP, null));
+	}
+
+	@Test
+	public void b02_unswap_create() throws Exception {
+		assertNotNull(find(B02.class).unswap(null, OBJECTMAP, null));
+	}
+
+	@Test
+	public void b03_unswap_fromObject() throws Exception {
+		assertNotNull(find(B03.class).unswap(null, STRINGMAP, null));
+	}
+
+	@Test(expected = ParseException.class)
+	public void b04_unswap_noMethod() throws Exception {
+		find(B04.class).unswap(null, STRINGMAP, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class C01 {
+		public C01() {}
+		public C01(Map<String,String> o) {
+			assertObjectEquals("{foo:'bar'}", o);
+		}
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test
+	public void c01_unswap_constructor() throws Exception {
+		assertNotNull(find(C01.class).unswap(null, STRINGMAP, null));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore class
+	//------------------------------------------------------------------------------------------------------------------
+
+	@BeanIgnore
+	public static class D01 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+	public static class D02 {
+		public class D02A {
+			public Map<String,String> swap() {
+				return STRINGMAP;
+			}
+		}
+	}
+
+	@Test
+	public void d01_ignoreClass_beanIgnore() throws Exception {
+		assertNull(find(D01.class));
+	}
+
+	@Test
+	public void d02_ignoreClass_memberClass() throws Exception {
+		assertNull(find(D02.D02A.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore swap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class E01 {
+		@BeanIgnore
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+	public static class E02 {
+		@Deprecated
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+	public static class E04 {
+		public Map<String,String> swap(Map<String,String> foo) {
+			return STRINGMAP;
+		}
+	}
+	public static class E05 {
+		public static Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test
+	public void e01_ignoreSwapMethod_beanIgnore() throws Exception {
+		assertNull(find(E01.class));
+	}
+
+	@Test
+	public void e02_ignoreSwapMethod_deprecated() throws Exception {
+		assertNull(find(E02.class));
+	}
+
+	@Test
+	public void e04_ignoreSwapMethod_wrongParameters() throws Exception {
+		assertNull(find(E04.class));
+	}
+
+	@Test
+	public void e05_ignoreSwapMethod_notStatic() throws Exception {
+		assertNull(find(E05.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore unswap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class F01 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		@BeanIgnore
+		public static F01 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F02 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		@Deprecated
+		public static F02 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F03 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		public static Object create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F04 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		public static F04 create(List<String> o) {
+			return null;
+		}
+	}
+	public static class F05 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		public F05 create(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F06 {
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+		public static F06 createx(Map<String,String> o) {
+			return null;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+		find(F01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+		find(F02.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+		find(F03.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+		find(F04.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+		find(F05.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+		find(F06.class).unswap(null, null, null);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class G01 {
+		@BeanIgnore
+		public G01(Map<String,String> o) {}
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+
+	public static class G02 {
+		@Deprecated
+		public G02(Map<String,String> o) {}
+		public Map<String,String> swap() {
+			return STRINGMAP;
+		}
+	}
+
+	@Test(expected = ParseException.class)
+	public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+		find(G01.class).unswap(null, null, null);
+	}
+
+	@Test(expected = ParseException.class)
+	public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+		find(G02.class).unswap(null, null, null);
+	}
+}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoStringSwapTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoStringSwapTest.java
new file mode 100644
index 0000000..87e2e73
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/transform/AutoStringSwapTest.java
@@ -0,0 +1,271 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@SuppressWarnings({"unchecked","rawtypes"})
+public class AutoStringSwapTest {
+
+	private static PojoSwap find(Class<?> c) {
+		return AutoStringSwap.find(ClassInfo.of(c));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap methods
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class B01 {
+		public static B01 fromString(String o) {
+			assertEquals("foo", o);
+			return new B01();
+		}
+	}
+	public static class B02 {
+		public static B02 fromValue(String o) {
+			assertEquals("foo", o);
+			return new B02();
+		}
+	}
+	public static class B03 {
+		public static B03 valueOf(String o) {
+			assertEquals("foo", o);
+			return new B03();
+		}
+	}
+	public static class B04 {
+		public static B04 parse(String o) {
+			assertEquals("foo", o);
+			return new B04();
+		}
+	}
+	public static class B05 {
+		public static B05 parseString(String o) {
+			assertEquals("foo", o);
+			return new B05();
+		}
+	}
+	public static class B06 {
+		public static B06 forName(String o) {
+			assertEquals("foo", o);
+			return new B06();
+		}
+	}
+	public static class B07 {
+		public static B07 forString(String o) {
+			assertEquals("foo", o);
+			return new B07();
+		}
+	}
+
+	@Test
+	public void b01_unswap_fromString() throws Exception {
+		assertNotNull(find(B01.class).unswap(null, "foo", null));
+	}
+
+	@Test
+	public void b02_unswap_fromValue() throws Exception {
+		assertNotNull(find(B02.class).unswap(null, "foo", null));
+	}
+
+	@Test
+	public void b03_unswap_valueOf() throws Exception {
+		assertNotNull(find(B03.class).unswap(null, "foo", null));
+	}
+
+	@Test
+	public void b04_unswap_parse() throws Exception {
+		assertNotNull(find(B04.class).unswap(null, "foo", null));
+	}
+
+	@Test
+	public void b05_unswap_parseString() throws Exception {
+		assertNotNull(find(B05.class).unswap(null, "foo", null));
+	}
+
+	@Test
+	public void b06_unswap_forName() throws Exception {
+		assertNotNull(find(B06.class).unswap(null, "foo", null));
+	}
+
+	@Test
+	public void b07_unswap_forString() throws Exception {
+		assertNotNull(find(B07.class).unswap(null, "foo", null));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Unswap constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class C01 {
+		public C01() {}
+		public C01(String o) {
+			assertEquals("foo", o);
+		}
+	}
+	public static class C02 {
+		public C02() {}
+		public C02(String o) {
+			throw new RuntimeException("foo");
+		}
+	}
+	public static class C03 {
+		public C03() {}
+		public C03(String o) throws ParseException {
+			throw new ParseException("foo");
+		}
+	}
+
+	@Test
+	public void c01_unswapConstructor() throws Exception {
+		assertNotNull(find(C01.class).unswap(null, "foo", null));
+	}
+
+	@Test(expected = ParseException.class)
+	public void c02_unswapConstructor_runtimeException() throws Exception {
+		assertNotNull(find(C02.class).unswap(null, "foo", null));
+	}
+
+	@Test(expected = ParseException.class)
+	public void c03_unswapConstructor_parseException() throws Exception {
+		assertNotNull(find(C03.class).unswap(null, "foo", null));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore class
+	//------------------------------------------------------------------------------------------------------------------
+
+	@BeanIgnore
+	public static class D01 {
+		public static D01 fromString(String s) {
+			return new D01();
+		}
+	}
+	public static class D02 {
+		public class D02A {
+			public D02A fromString(String s) {
+				return new D02A();
+			}
+		}
+	}
+
+	@Test
+	public void d01_ignoreClass_beanIgnore() throws Exception {
+		assertNull(find(D01.class));
+	}
+
+	@Test
+	public void d02_ignoreClass_memberClass() throws Exception {
+		assertNull(find(D02.D02A.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore unswap method
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class F01 {
+		@BeanIgnore
+		public static F01 fromString(String o) {
+			return null;
+		}
+	}
+	public static class F02 {
+		@Deprecated
+		public static F02 fromString(String o) {
+			return null;
+		}
+	}
+	public static class F03 {
+		public static Object fromString(String o) {
+			return null;
+		}
+	}
+	public static class F04 {
+		public static F04 fromString(Map<String,String> o) {
+			return null;
+		}
+	}
+	public static class F05 {
+		public F05 fromString(String o) {
+			return null;
+		}
+	}
+	public static class F06 {
+		public static F06 createx(String o) {
+			return null;
+		}
+	}
+
+	@Test
+	public void f01_ignoreUnswapMethod_beanIgnore() throws Exception {
+		assertNull(find(F01.class));
+	}
+
+	@Test
+	public void f02_ignoreUnswapMethod_deprecated() throws Exception {
+		assertNull(find(F02.class));
+	}
+
+	@Test
+	public void f03_ignoreUnswapMethod_wrongReturnType() throws Exception {
+		assertNull(find(F03.class));
+	}
+
+	@Test
+	public void f04_ignoreUnswapMethod_wrongParameters() throws Exception {
+		assertNull(find(F04.class));
+	}
+
+	@Test
+	public void f05_ignoreUnswapMethod_notStatic() throws Exception {
+		assertNull(find(F05.class));
+	}
+
+	@Test
+	public void f06_ignoreUnswapMethod_wrongName() throws Exception {
+		assertNull(find(F06.class));
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Ignore constructor
+	//------------------------------------------------------------------------------------------------------------------
+
+	public static class G01 {
+		@BeanIgnore
+		public G01(String o) {}
+	}
+
+	public static class G02 {
+		@Deprecated
+		public G02(String o) {}
+	}
+
+	@Test
+	public void g01_ignoreUnswapConstructor_beanIgnore() throws Exception {
+		assertNull(find(G01.class));
+	}
+
+	@Test
+	public void g02_ignoreUnswapConstructor_deprecated() throws Exception {
+		assertNull(find(G02.class));
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
index e2e5157..bd8d1b3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
@@ -48,7 +48,7 @@ public class BeanProxyInvocationHandler<T> implements InvocationHandler {
 	@Override /* InvocationHandler */
 	public Object invoke(Object proxy, Method method, Object[] args) {
 		MethodInfo mi = MethodInfo.of(method);
-		if (mi.hasName("equals") && mi.hasArgs(java.lang.Object.class)) {
+		if (mi.hasName("equals") && mi.hasParamTypes(java.lang.Object.class)) {
 			Object arg = args[0];
 			if (arg == null)
 				return false;
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 88be006..de10c27 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
@@ -441,7 +441,7 @@ public final class ClassMeta<T> implements Type {
 			for (String methodName : new String[]{"fromString","fromValue","valueOf","parse","parseString","forName","forString"}) {
 				if (fromStringMethod == null) {
 					for (MethodInfo m : ci.getPublicMethods()) {
-						if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasName(methodName) && m.hasReturnType(c) && m.hasArgs(String.class)) {
+						if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasName(methodName) && m.hasReturnType(c) && m.hasParamTypes(String.class)) {
 							fromStringMethod = m.inner();
 							break;
 						}
@@ -451,7 +451,7 @@ public final class ClassMeta<T> implements Type {
 
 			// Find example() method if present.
 			for (MethodInfo m : ci.getPublicMethods()) {
-				if (m.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && m.hasName("example") && m.hasFuzzyArgs(BeanSession.class)) {
+				if (m.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && m.hasName("example") && m.hasFuzzyParamTypes(BeanSession.class)) {
 					exampleMethod = m.inner();
 					break;
 				}
@@ -499,7 +499,7 @@ public final class ClassMeta<T> implements Type {
 
 			for (MethodInfo m : ci.getDeclaredMethods()) {
 				if (m.hasAnnotation(Example.class)) {
-					if (! (m.isStatic() && m.hasFuzzyArgs(BeanSession.class) && ci.isParentOf(m.getReturnType().inner())))
+					if (! (m.isStatic() && m.hasFuzzyParamTypes(BeanSession.class) && ci.isParentOf(m.getReturnType().inner())))
 						throw new ClassMetaRuntimeException("@Example used on invalid method ''{0}''.  Must be static and return an instance of the declaring class.", m);
 					m.setAccessible();
 					exampleMethod = m.inner();
@@ -702,7 +702,16 @@ public final class ClassMeta<T> implements Type {
 
 			PojoSwap defaultSwap = DefaultSwaps.find(ci);
 			if (defaultSwap == null)
-				defaultSwap = DynamicSwaps.find(ci);
+				defaultSwap = AutoObjectSwap.find(ci);
+			if (defaultSwap == null)
+				defaultSwap = AutoNumberSwap.find(ci);
+			if (defaultSwap == null)
+				defaultSwap = AutoMapSwap.find(ci);
+			if (defaultSwap == null)
+				defaultSwap = AutoListSwap.find(ci);
+			// TODO
+			//if (defaultSwap == null)
+			//	defaultSwap = AutoStringSwap.find(ci);
 			if (defaultSwap != null)
 				l.add(defaultSwap);
 		}
@@ -1545,7 +1554,7 @@ public final class ClassMeta<T> implements Type {
 	 */
 	public boolean canCreateNewInstance(Object outer) {
 		if (isMemberClass)
-			return outer != null && noArgConstructor != null && noArgConstructor.hasArgs(outer.getClass());
+			return outer != null && noArgConstructor != null && noArgConstructor.hasParamTypes(outer.getClass());
 		return canCreateNewInstance();
 	}
 
@@ -1565,7 +1574,7 @@ public final class ClassMeta<T> implements Type {
 		if (beanMeta.constructor == null)
 			return false;
 		if (isMemberClass)
-			return outer != null && beanMeta.constructor.hasArgs(outer.getClass());
+			return outer != null && beanMeta.constructor.hasParamTypes(outer.getClass());
 		return true;
 	}
 
@@ -1582,7 +1591,7 @@ public final class ClassMeta<T> implements Type {
 			return true;
 		if (stringConstructor != null) {
 			if (isMemberClass)
-				return outer != null && stringConstructor.hasArgs(outer.getClass(), String.class);
+				return outer != null && stringConstructor.hasParamTypes(outer.getClass(), String.class);
 			return true;
 		}
 		return false;
@@ -1599,7 +1608,7 @@ public final class ClassMeta<T> implements Type {
 	public boolean canCreateNewInstanceFromNumber(Object outer) {
 		if (numberConstructor != null) {
 			if (isMemberClass)
-				return outer != null && numberConstructor.hasArgs(outer.getClass());
+				return outer != null && numberConstructor.hasParamTypes(outer.getClass());
 			return true;
 		}
 		return false;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
index e90583a..e9a2b7d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/BeanIgnore.java
@@ -37,7 +37,7 @@ import java.lang.annotation.*;
  * </ul>
  */
 @Documented
-@Target({FIELD,METHOD,TYPE})
+@Target({FIELD,METHOD,TYPE,CONSTRUCTOR})
 @Retention(RUNTIME)
 @Inherited
 public @interface BeanIgnore {}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
index 083dab1..4c69fb4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -56,8 +56,8 @@ public final class ClassUtils {
 
 	/**
 	 * Shortcut for calling {@link MethodInfo#of(ClassInfo, Method)}.
-	 * 
-	 * @param c 
+	 *
+	 * @param c
 	 * 	The class containing the method.
 	 * 	<br>Note that this isn't necessarily the declaring class, but could be a subclass
 	 * 	of the declaring class.
@@ -165,6 +165,29 @@ public final class ClassUtils {
 	 * @param argTypes The class types of the arguments being passed to the method.
 	 * @return The number of matching arguments, or <c>-1</c> a parameter was found that isn't in the list of args.
 	 */
+	public static int fuzzyArgsMatch(Class<?>[] paramTypes, ClassInfo... argTypes) {
+		int matches = 0;
+		outer: for (Class<?> p : paramTypes) {
+			ClassInfo pi = getClassInfo(p).getWrapperInfoIfPrimitive();
+			for (ClassInfo a : argTypes) {
+				ClassInfo ai = a.getWrapperInfoIfPrimitive();
+				if (pi.isParentOf(ai.inner())) {
+					matches++;
+					continue outer;
+				}
+			}
+			return -1;
+		}
+		return matches;
+	}
+
+	/**
+	 * Returns a number representing the number of arguments that match the specified parameters.
+	 *
+	 * @param paramTypes The parameters types specified on a method.
+	 * @param argTypes The class types of the arguments being passed to the method.
+	 * @return The number of matching arguments, or <c>-1</c> a parameter was found that isn't in the list of args.
+	 */
 	public static int fuzzyArgsMatch(List<ClassInfo> paramTypes, Class<?>... argTypes) {
 		int matches = 0;
 		outer: for (ClassInfo p : paramTypes) {
@@ -313,7 +336,7 @@ public final class ClassUtils {
 		for (int i = 0; i < paramTypes.length; i++) {
 			ClassInfo pt = getClassInfo(paramTypes[i]).getWrapperInfoIfPrimitive();
 			for (int j = 0; j < args.length; j++) {
-				if (pt.isParentOf(args[j].getClass())) {
+				if (args[j] != null && pt.isParentOf(args[j].getClass())) {
 					params[i] = args[j];
 					break;
 				}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
index 96538d7..9e102ae 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/CollectionUtils.java
@@ -474,4 +474,15 @@ public final class CollectionUtils {
 		m.put(key, value);
 		return m;
 	}
+
+	/**
+	 * Converts the specified arguments into an unmodifiable {@link HashSet}.
+	 *
+	 * @param values The entries to populate the hashset with.
+	 * @return A new {@link HashSet} populated with the specified arguments.
+	 */
+	@SafeVarargs
+	public static <T> Set<T> newUnmodifiableHashSet(T...values) {
+		return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(values)));
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java
index d8e0c8c..4087f8a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParseException.java
@@ -14,11 +14,13 @@ package org.apache.juneau.parser;
 
 import static org.apache.juneau.internal.StringUtils.*;
 
+import java.lang.reflect.*;
 import java.text.*;
 import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.serializer.*;
 
 /**
  * Exception that indicates invalid syntax encountered during parsing.
@@ -28,6 +30,25 @@ public class ParseException extends FormattedException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Creator method.
+	 *
+	 * <p>
+	 * If the throwable is already a {@link ParseException}, we simply return that exception as-is.
+	 * If the throwable is an {@link InvocationTargetException}, we unwrap the thrown exception.
+	 * Otherwise we create a new {@link ParseException}.
+	 *
+	 * @param e The exception being wrapped or unwrapped.
+	 * @return A new {@link SerializeException}.
+	 */
+	public static ParseException create(Throwable e) {
+		if (e instanceof InvocationTargetException)
+			e = ((InvocationTargetException)e).getCause();
+		if (e instanceof ParseException)
+			return (ParseException)e;
+		return new ParseException(e);
+	}
+
+	/**
 	 * Constructor.
 	 *
 	 * @param message The {@link MessageFormat}-style message.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index 1610486..6ab9fee 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -325,7 +325,7 @@ public final class ClassInfo {
 	 */
 	public MethodInfo getPublicMethod(String name, Class<?>...args) {
 		for (MethodInfo mi : getPublicMethods())
-			if (mi.hasName(name) && mi.hasArgs(args))
+			if (mi.hasName(name) && mi.hasParamTypes(args))
 				return mi;
 		return null;
 	}
@@ -340,7 +340,7 @@ public final class ClassInfo {
 	 */
 	public MethodInfo getMethod(String name, Class<?>...args) {
 		for (MethodInfo mi : getAllMethods())
-			if (mi.hasName(name) && mi.hasArgs(args))
+			if (mi.hasName(name) && mi.hasParamTypes(args))
 				return mi;
 		return null;
 	}
@@ -431,7 +431,7 @@ public final class ClassInfo {
 			for (MethodInfo m : getPublicMethods())
 				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED)
 						&& m.hasReturnType(c)
-						&& m.hasArgs(String.class)
+						&& m.hasParamTypes(String.class)
 						&& isOneOf(m.getSimpleName(), "create","fromString","fromValue","valueOf","parse","parseString","forName","forString"))
 					return m;
 		return null;
@@ -454,7 +454,7 @@ public final class ClassInfo {
 	public MethodInfo getStaticCreateMethod(Class<?> ic) {
 		if (c != null) {
 			for (MethodInfo m : getPublicMethods()) {
-				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && m.hasArgs(ic)) {
+				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && m.hasParamTypes(ic)) {
 					String n = m.getSimpleName();
 					if (isOneOf(n, "create","from") || (n.startsWith("from") && n.substring(4).equals(ic.getSimpleName()))) {
 						return m;
@@ -476,7 +476,7 @@ public final class ClassInfo {
 	public MethodInfo getStaticPublicMethod(String name, Class<?> rt, Class<?>...args) {
 		if (c != null)
 			for (MethodInfo m : getPublicMethods())
-				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && name.equals(m.getSimpleName()) && m.hasReturnType(rt) && m.hasArgs(args))
+				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && name.equals(m.getSimpleName()) && m.hasReturnType(rt) && m.hasParamTypes(args))
 					return m;
 		return null;
 	}
@@ -548,7 +548,7 @@ public final class ClassInfo {
 	 */
 	public ConstructorInfo getPublicConstructor(Class<?>...args) {
 		for (ConstructorInfo ci : getPublicConstructors())
-			if (ci.hasArgs(args))
+			if (ci.hasParamTypes(args))
 				return ci;
 		return null;
 	}
@@ -562,7 +562,7 @@ public final class ClassInfo {
 	 */
 	public ConstructorInfo getDeclaredConstructor(Class<?>...args) {
 		for (ConstructorInfo ci : getDeclaredConstructors())
-			if (ci.hasArgs(args))
+			if (ci.hasParamTypes(args))
 				return ci;
 		return null;
 	}
@@ -1444,6 +1444,15 @@ public final class ClassInfo {
 	}
 
 	/**
+	 * Returns <jk>false</jk> if this class is a member class and not static.
+	 *
+	 * @return <jk>false</jk> if this class is a member class and not static.
+	 */
+	public boolean isNotNonStaticMemberClass() {
+		return ! isNonStaticMemberClass();
+	}
+
+	/**
 	 * Returns <jk>true</jk> if this class is a local class.
 	 *
 	 * @return <jk>true</jk> if this class is a local class.
@@ -1823,6 +1832,16 @@ public final class ClassInfo {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>.
+	 *
+	 * @param parent The parent class.
+	 * @return <jk>true</jk> if this class is a parent or the same as <c>parent</c>.
+	 */
+	public boolean isChildOf(ClassInfo parent) {
+		return isChildOf(parent.inner());
+	}
+
+	/**
 	 * Checks for equality with the specified class.
 	 *
 	 * @param c The class to check equality with.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
index 36373fe..df1d89c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
@@ -512,7 +512,7 @@ public abstract class ExecutableInfo {
 	 * @param args The arguments to test for.
 	 * @return <jk>true</jk> if this method has this arguments in the exact order.
 	 */
-	public final boolean hasArgs(Class<?>...args) {
+	public final boolean hasParamTypes(Class<?>...args) {
 		Class<?>[] pt = rawParamTypes();
 		if (pt.length == args.length) {
 			for (int i = 0; i < pt.length; i++)
@@ -524,12 +524,29 @@ public abstract class ExecutableInfo {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if this method has the specified arguments.
+	 *
+	 * @param args The arguments to test for.
+	 * @return <jk>true</jk> if this method has this arguments in the exact order.
+	 */
+	public final boolean hasParamTypes(ClassInfo...args) {
+		Class<?>[] pt = rawParamTypes();
+		if (pt.length == args.length) {
+			for (int i = 0; i < pt.length; i++)
+				if (! pt[i].equals(args[i].inner()))
+					return false;
+			return true;
+		}
+		return false;
+	}
+
+	/**
 	 * Returns <jk>true</jk> if this method has the specified argument parent classes.
 	 *
 	 * @param args The arguments to test for.
 	 * @return <jk>true</jk> if this method has this arguments in the exact order.
 	 */
-	public final boolean hasArgParents(Class<?>...args) {
+	public final boolean hasParamTypeParents(Class<?>...args) {
 		Class<?>[] pt = rawParamTypes();
 		if (pt.length == args.length) {
 			for (int i = 0; i < pt.length; i++)
@@ -541,12 +558,39 @@ public abstract class ExecutableInfo {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if this method has the specified argument parent classes.
+	 *
+	 * @param args The arguments to test for.
+	 * @return <jk>true</jk> if this method has this arguments in the exact order.
+	 */
+	public final boolean hasParamTypeParents(ClassInfo...args) {
+		Class<?>[] pt = rawParamTypes();
+		if (pt.length == args.length) {
+			for (int i = 0; i < pt.length; i++)
+				if (! args[i].inner().isAssignableFrom(pt[i]))
+					return false;
+			return true;
+		}
+		return false;
+	}
+
+	/**
 	 * Returns <jk>true</jk> if this method has at most only this arguments in any order.
 	 *
 	 * @param args The arguments to test for.
 	 * @return <jk>true</jk> if this method has at most only this arguments in any order.
 	 */
-	public final boolean hasFuzzyArgs(Class<?>...args) {
+	public final boolean hasFuzzyParamTypes(Class<?>...args) {
+		return ClassUtils.fuzzyArgsMatch(rawParamTypes(), args) != -1;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this method has at most only this arguments in any order.
+	 *
+	 * @param args The arguments to test for.
+	 * @return <jk>true</jk> if this method has at most only this arguments in any order.
+	 */
+	public boolean hasFuzzyParamTypes(ClassInfo...args) {
 		return ClassUtils.fuzzyArgsMatch(rawParamTypes(), args) != -1;
 	}
 
@@ -667,6 +711,29 @@ public abstract class ExecutableInfo {
 		return getSimpleName().equals(name);
 	}
 
+	/**
+	 * Returns <jk>true</jk> if this method has a name in the specified list.
+	 *
+	 * @param names The names to test for.
+	 * @return <jk>true</jk> if this method has one of the names.
+	 */
+	public final boolean hasName(String...names) {
+		for (String n : names)
+			if (getSimpleName().equals(n))
+				return true;
+		return false;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this method has a name in the specified set.
+	 *
+	 * @param names The names to test for.
+	 * @return <jk>true</jk> if this method has one of the names.
+	 */
+	public final boolean hasName(Set<String> names) {
+		return names.contains(getSimpleName());
+	}
+
 	//-----------------------------------------------------------------------------------------------------------------
 	// Labels
 	//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
index c0fb331..9f7776a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
@@ -20,7 +20,7 @@ import java.lang.reflect.*;
 import java.util.*;
 import java.util.function.*;
 
-import org.apache.juneau.ExecutableException;
+import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.internal.*;
 
@@ -380,6 +380,16 @@ public final class MethodInfo extends ExecutableInfo implements Comparable<Metho
 	}
 
 	/**
+	 * Returns <jk>true</jk> if this method has this return type.
+	 *
+	 * @param ci The return type to test for.
+	 * @return <jk>true</jk> if this method has this return type.
+	 */
+	public boolean hasReturnType(ClassInfo ci) {
+		return hasReturnType(ci.inner());
+	}
+
+	/**
 	 * Returns <jk>true</jk> if this method has this parent return type.
 	 *
 	 * @param c The return type to test for.
@@ -389,6 +399,16 @@ public final class MethodInfo extends ExecutableInfo implements Comparable<Metho
 		return ClassInfo.of(c).isParentOf(m.getReturnType());
 	}
 
+	/**
+	 * Returns <jk>true</jk> if this method has this parent return type.
+	 *
+	 * @param ci The return type to test for.
+	 * @return <jk>true</jk> if this method has this parent return type.
+	 */
+	public boolean hasReturnTypeParent(ClassInfo ci) {
+		return hasReturnTypeParent(ci.inner());
+	}
+
 	//-----------------------------------------------------------------------------------------------------------------
 	// Other methods
 	//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java
index e6242fe..9050d39 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializeException.java
@@ -14,6 +14,7 @@ package org.apache.juneau.serializer;
 
 import static org.apache.juneau.internal.StringUtils.*;
 
+import java.lang.reflect.*;
 import java.text.*;
 import java.util.*;
 
@@ -28,6 +29,25 @@ public class SerializeException extends FormattedException {
 	private static final long serialVersionUID = 1L;
 
 	/**
+	 * Creator method.
+	 *
+	 * <p>
+	 * If the throwable is already a {@link SerializeException}, we simply return that exception as-is.
+	 * If the throwable is an {@link InvocationTargetException}, we unwrap the thrown exception.
+	 * Otherwise we create a new {@link SerializeException}.
+	 *
+	 * @param e The exception being wrapped or unwrapped.
+	 * @return A new {@link SerializeException}.
+	 */
+	public static SerializeException create(Throwable e) {
+		if (e instanceof InvocationTargetException)
+			e = ((InvocationTargetException)e).getCause();
+		if (e instanceof SerializeException)
+			return (SerializeException)e;
+		return new SerializeException(e);
+	}
+
+	/**
 	 * Constructor.
 	 *
 	 * @param session The serializer session to extract information from.
@@ -63,7 +83,7 @@ public class SerializeException extends FormattedException {
 	 *
 	 * @param causedBy The inner exception.
 	 */
-	public SerializeException(Exception causedBy) {
+	public SerializeException(Throwable causedBy) {
 		super(causedBy, getMessage(null, causedBy.getMessage()));
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
new file mode 100644
index 0000000..2602c4f
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
@@ -0,0 +1,182 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to Lists.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate List objects before serialization and swap-out
+ * surrogate List objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * 	<li class='jc'>Any subclass of {@link List}
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public</jk> S toList()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toList(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toObjectList()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toObjectList(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public static</jk> N fromList(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromList(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromObjectList(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromObjectList(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoListSwap<T> extends PojoSwap<T,List<?>> {
+
+	private static final Set<String>
+		SWAP_METHOD_NAMES = newUnmodifiableHashSet("toList", "toObjectList"),
+		UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromList", "fromObjectList", "create", "valueOf");
+
+	/**
+	 * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+	 *
+	 * @param ci The class to try to constructor a dynamic swap on.
+	 * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+	 */
+	@SuppressWarnings({ "rawtypes" })
+	public static PojoSwap<?,?> find(ClassInfo ci) {
+
+		if (shouldIgnore(ci))
+			return null;
+
+		// Find swap() method if present.
+		for (MethodInfo m : ci.getPublicMethods()) {
+			if (isSwapMethod(m)) {
+
+				ClassInfo rt = m.getReturnType();
+
+				for (MethodInfo m2 : ci.getPublicMethods())
+					if (isUnswapMethod(m2, ci, rt))
+						return new AutoListSwap(ci, m, m2, null);
+
+				for (ConstructorInfo cs : ci.getPublicConstructors())
+					if (isUnswapConstructor(cs, rt))
+						return new AutoListSwap(ci, m, null, cs);
+
+				return new AutoListSwap(ci, m, null, null);
+			}
+		}
+
+		return null;
+	}
+
+	private static boolean shouldIgnore(ClassInfo ci) {
+		return
+			ci.hasAnnotation(BeanIgnore.class)
+			|| ci.isNonStaticMemberClass();
+	}
+
+	private static boolean isSwapMethod(MethodInfo mi) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isNotStatic()
+			&& mi.hasName(SWAP_METHOD_NAMES)
+			&& mi.hasReturnTypeParent(List.class)
+			&& mi.hasFuzzyParamTypes(BeanSession.class)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isStatic()
+			&& mi.hasName(UNSWAP_METHOD_NAMES)
+			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+			&& mi.hasReturnTypeParent(ci)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+		return
+			cs.isNotDeprecated()
+			&& cs.hasParamTypeParents(rt)
+			&& ! cs.hasAnnotation(BeanIgnore.class);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+
+	private final Method swapMethod, unswapMethod;
+	private final Constructor<?> unswapConstructor;
+
+	private AutoListSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+		super(ci.inner(), swapMethod.getReturnType().inner());
+		this.swapMethod = swapMethod.inner();
+		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+	}
+
+	@Override /* PojoSwap */
+	public List<?> swap(BeanSession session, Object o) throws SerializeException {
+		try {
+			return (List<?>)swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+		} catch (Exception e) {
+			throw SerializeException.create(e);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override /* PojoSwap */
+	public T unswap(BeanSession session, List<?> o, ClassMeta<?> hint) throws ParseException {
+		try {
+			if (unswapMethod != null)
+				return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, o));
+			if (unswapConstructor != null)
+				return (T)unswapConstructor.newInstance(o);
+			return super.unswap(session, o, hint);
+		} catch (Exception e) {
+			throw ParseException.create(e);
+		}
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
new file mode 100644
index 0000000..53dace1
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
@@ -0,0 +1,182 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to serializable Maps.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate Map objects before serialization and swap-out
+ * surrogate Map objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * 	<li class='jc'>Any subclass of {@link Map}
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public</jk> S toMap()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toMap(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toObjectMap()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toObjectMap(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public static</jk> N fromMap(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromMap(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromObjectMap(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromObjectMap(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoMapSwap<T> extends PojoSwap<T,Map<?,?>> {
+
+	private static final Set<String>
+		SWAP_METHOD_NAMES = newUnmodifiableHashSet("toMap", "toObjectMap"),
+		UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromMap", "fromObjectMap", "create", "valueOf");
+
+	/**
+	 * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+	 *
+	 * @param ci The class to try to constructor a dynamic swap on.
+	 * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+	 */
+	@SuppressWarnings({ "rawtypes" })
+	public static PojoSwap<?,?> find(ClassInfo ci) {
+
+		if (shouldIgnore(ci))
+			return null;
+
+		// Find swap() method if present.
+		for (MethodInfo m : ci.getPublicMethods()) {
+			if (isSwapMethod(m)) {
+
+				ClassInfo rt = m.getReturnType();
+
+				for (MethodInfo m2 : ci.getPublicMethods())
+					if (isUnswapMethod(m2, ci, rt))
+						return new AutoMapSwap(ci, m, m2, null);
+
+				for (ConstructorInfo cs : ci.getPublicConstructors())
+					if (isUnswapConstructor(cs, rt))
+						return new AutoMapSwap(ci, m, null, cs);
+
+				return new AutoMapSwap(ci, m, null, null);
+			}
+		}
+
+		return null;
+	}
+
+	private static boolean shouldIgnore(ClassInfo ci) {
+		return
+			ci.hasAnnotation(BeanIgnore.class)
+			|| ci.isNonStaticMemberClass();
+	}
+
+	private static boolean isSwapMethod(MethodInfo mi) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isNotStatic()
+			&& mi.hasName(SWAP_METHOD_NAMES)
+			&& mi.hasReturnTypeParent(Map.class)
+			&& mi.hasFuzzyParamTypes(BeanSession.class)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isStatic()
+			&& mi.hasName(UNSWAP_METHOD_NAMES)
+			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+			&& mi.hasReturnTypeParent(ci)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+		return
+			cs.isNotDeprecated()
+			&& cs.hasParamTypeParents(rt)
+			&& ! cs.hasAnnotation(BeanIgnore.class);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+
+	private final Method swapMethod, unswapMethod;
+	private final Constructor<?> unswapConstructor;
+
+	private AutoMapSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+		super(ci.inner(), swapMethod.inner().getReturnType());
+		this.swapMethod = swapMethod.inner();
+		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+	}
+
+	@Override /* PojoSwap */
+	public Map<?,?> swap(BeanSession session, Object o) throws SerializeException {
+		try {
+			return (Map<?,?>)swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+		} catch (Exception e) {
+			throw SerializeException.create(e);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override /* PojoSwap */
+	public T unswap(BeanSession session, Map<?,?> o, ClassMeta<?> hint) throws ParseException {
+		try {
+			if (unswapMethod != null)
+				return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, o));
+			if (unswapConstructor != null)
+				return (T)unswapConstructor.newInstance(o);
+			return super.unswap(session, o, hint);
+		} catch (Exception e) {
+			throw ParseException.create(e);
+		}
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
new file mode 100644
index 0000000..80ae1cc
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
@@ -0,0 +1,222 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to Number serializable objects.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate Number objects before serialization and swap-out
+ * surrogate Number objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * 	<li class='jc'>Any subclass of {@link Number}
+ * 	<li class='jc'>Any number primitive
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public</jk> S toNumber()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toNumber(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toInteger()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toInteger(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toInt()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toInt(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toLong()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toLong(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toFloat()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toFloat(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toDouble()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toDouble(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toShort()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toShort(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toByte()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toByte(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public static</jk> N fromInteger(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromInteger(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromInt(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromInt(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromLong(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromLong(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromFloat(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromFloat(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromDouble(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromDouble(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromShort(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromShort(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromByte(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromByte(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
+
+	private static final Set<String>
+		SWAP_METHOD_NAMES = newUnmodifiableHashSet("toNumber", "toInteger", "toInt", "toLong", "toFloat", "toDouble", "toShort", "toByte"),
+		UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromInteger", "fromInt", "fromLong", "fromFloat", "fromDouble", "fromShort", "fromByte", "create", "valueOf");
+
+	/**
+	 * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+	 *
+	 * @param ci The class to try to constructor a dynamic swap on.
+	 * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+	 */
+	@SuppressWarnings({ "rawtypes" })
+	public static PojoSwap<?,?> find(ClassInfo ci) {
+
+		if (shouldIgnore(ci))
+			return null;
+
+		// Find swap() method if present.
+		for (MethodInfo m : ci.getPublicMethods()) {
+			if (isSwapMethod(m)) {
+
+				ClassInfo rt = m.getReturnType();
+
+				for (MethodInfo m2 : ci.getPublicMethods())
+					if (isUnswapMethod(m2, ci, rt))
+						return new AutoNumberSwap(ci, m, m2, null);
+
+				for (ConstructorInfo cs : ci.getPublicConstructors())
+					if (isUnswapConstructor(cs, rt))
+						return new AutoNumberSwap(ci, m, null, cs);
+
+				return new AutoNumberSwap(ci, m, null, null);
+			}
+		}
+
+		return null;
+	}
+
+	private static boolean shouldIgnore(ClassInfo ci) {
+		return
+			ci.hasAnnotation(BeanIgnore.class)
+			|| ci.isNonStaticMemberClass()
+			|| ci.isPrimitive()
+			|| ci.isChildOf(Number.class);
+	}
+
+	private static boolean isSwapMethod(MethodInfo mi) {
+		ClassInfo rt = mi.getReturnType();
+		return
+			mi.isNotDeprecated()
+			&& mi.isNotStatic()
+			&& (rt.isChildOf(Number.class) || (rt.isPrimitive() && rt.isAny(int.class, short.class, long.class, float.class, double.class, byte.class)))
+			&& mi.hasName(SWAP_METHOD_NAMES)
+			&& mi.hasFuzzyParamTypes(BeanSession.class)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isStatic()
+			&& mi.hasName(UNSWAP_METHOD_NAMES)
+			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+			&& mi.hasReturnTypeParent(ci)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+		return
+			cs.isNotDeprecated()
+			&& cs.hasParamTypeParents(rt)
+			&& ! cs.hasAnnotation(BeanIgnore.class);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+
+	private final Method swapMethod, unswapMethod;
+	private final Constructor<?> unswapConstructor;
+	private final Class<?> unswapType;
+
+	private AutoNumberSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+		super(ci.inner(), swapMethod.inner().getReturnType());
+		this.swapMethod = swapMethod.inner();
+		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+
+		Class<?> unswapType = null;
+		if (unswapMethod != null) {
+			for (ParamInfo pi : unswapMethod.getParams())
+				if (! pi.getParameterType().is(BeanSession.class))
+					unswapType = pi.getParameterType().getWrapperIfPrimitive();
+		} else if (unswapConstructor != null) {
+			for (ParamInfo pi : unswapConstructor.getParams())
+				if (! pi.getParameterType().is(BeanSession.class))
+					unswapType = pi.getParameterType().getWrapperIfPrimitive();
+		}
+		this.unswapType = unswapType;
+	}
+
+	@Override /* PojoSwap */
+	public Number swap(BeanSession session, Object o) throws SerializeException {
+		try {
+			return (Number)swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+		} catch (Exception e) {
+			throw SerializeException.create(e);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override /* PojoSwap */
+	public T unswap(BeanSession session, Number o, ClassMeta<?> hint) throws ParseException {
+		try {
+			Object o2 = ObjectUtils.toType(o, unswapType);
+			if (unswapMethod != null)
+				return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, o2));
+			if (unswapConstructor != null)
+				return (T)unswapConstructor.newInstance(o2);
+			return super.unswap(session, o, hint);
+		} catch (Exception e) {
+			throw ParseException.create(e);
+		}
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
new file mode 100644
index 0000000..a55f700
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
@@ -0,0 +1,183 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to serializable objects.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate objects before serialization and swap-out
+ * surrogate objects after parsing.
+ *
+ * <h5 class='figure'>Valid surrogate objects</h5>
+ * <ul>
+ * 	<li class='jc'>{@link String}
+ * 	<li class='jc'>{@link Number}
+ * 	<li class='jc'>{@link Boolean}
+ * 	<li class='jc'>{@link Map}
+ * 	<li class='jc'>{@link Collection}
+ * </ul>
+ *
+ * <h5 class='figure'>Valid swap methods (S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public</jk> S swap()</c>
+ * 	<li class='jm'><c><jk>public</jk> S swap(BeanSession)</c>
+ * 	<li class='jm'><c><jk>public</jk> S toObject()</c>
+ * 	<li class='jm'><c><jk>public</jk> S toObject(BeanSession)</c>
+ * </ul>
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type, S = Swapped type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public static</jk> N unswap(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N unswap(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromObject(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromObject(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(S)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N create(BeanSession, S)</c>
+ * 	<li class='jm'><c><jk>public</jk> N(S)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoObjectSwap<T> extends PojoSwap<T,Object> {
+
+	private static final Set<String>
+		SWAP_METHOD_NAMES = newUnmodifiableHashSet("swap", "toObject"),
+		UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("unswap", "create", "fromObject");
+
+	/**
+	 * Inspects the specified class and returns a swap of this type if possible.
+	 *
+	 * @param ci The class to return a swap on.
+	 * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+	 */
+	@SuppressWarnings({ "rawtypes" })
+	public static PojoSwap<?,?> find(ClassInfo ci) {
+
+		if (shouldIgnore(ci))
+			return null;
+
+		// Find swap() method if present.
+		for (MethodInfo m : ci.getPublicMethods()) {
+			if (isSwapMethod(m)) {
+
+				ClassInfo rt = m.getReturnType();
+
+				for (MethodInfo m2 : ci.getPublicMethods())
+					if (isUnswapMethod(m2, ci, rt))
+						return new AutoObjectSwap(ci, m, m2, null);
+
+				for (ConstructorInfo cs : ci.getPublicConstructors())
+					if (isUnswapConstructor(cs, rt))
+						return new AutoObjectSwap(ci, m, null, cs);
+
+				return new AutoObjectSwap(ci, m, null, null);
+			}
+		}
+
+		return null;
+	}
+
+	private static boolean shouldIgnore(ClassInfo ci) {
+		return
+			ci.hasAnnotation(BeanIgnore.class)
+			|| ci.isNonStaticMemberClass();
+	}
+
+	private static boolean isSwapMethod(MethodInfo mi) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isNotStatic()
+			&& mi.hasName(SWAP_METHOD_NAMES)
+			&& mi.hasFuzzyParamTypes(BeanSession.class)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci, ClassInfo rt) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isStatic()
+			&& mi.hasName(UNSWAP_METHOD_NAMES)
+			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
+			&& mi.hasReturnTypeParent(ci)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapConstructor(ConstructorInfo cs, ClassInfo rt) {
+		return
+			cs.isNotDeprecated()
+			&& cs.hasParamTypeParents(rt)
+			&& ! cs.hasAnnotation(BeanIgnore.class);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+
+	private final Method swapMethod, unswapMethod;
+	private final Constructor<?> unswapConstructor;
+
+	private AutoObjectSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+		super(ci.inner(), swapMethod.inner().getReturnType());
+		this.swapMethod = swapMethod.inner();
+		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+	}
+
+	@Override /* PojoSwap */
+	public Object swap(BeanSession session, Object o) throws SerializeException {
+		try {
+			return swapMethod.invoke(o, getMatchingArgs(swapMethod.getParameterTypes(), session));
+		} catch (Exception e) {
+			throw SerializeException.create(e);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override /* PojoSwap */
+	public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
+		try {
+			if (unswapMethod != null)
+				return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, f));
+			if (unswapConstructor != null)
+				return (T)unswapConstructor.newInstance(f);
+			return super.unswap(session, f, hint);
+		} catch (Exception e) {
+			throw ParseException.create(e);
+		}
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoStringSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoStringSwap.java
new file mode 100644
index 0000000..dc8b6c2
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoStringSwap.java
@@ -0,0 +1,147 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.transform;
+
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A dynamic POJO swap based on reflection of a Java class that converts POJOs to serializable String objects.
+ *
+ * <p>
+ * Looks for methods on the class that can be called to swap-in surrogate String objects before serialization and swap-out
+ * surrogate String objects after parsing.
+ *
+ * <h5 class='figure'>Valid unswap methods (N = Normal type)</h5>
+ * <ul>
+ * 	<li class='jm'><c><jk>public static</jk> N fromString(String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromString(BeanSession, String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromValue(String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N fromValue(BeanSession, String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N valueOf(BeanSession, String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N parse(String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N parse(BeanSession, String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N parseString(String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N parseString(BeanSession, String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N forName(String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N forName(BeanSession, String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N forString(String)</c>
+ * 	<li class='jm'><c><jk>public static</jk> N forString(BeanSession, String)</c>
+ * 	<li class='jm'><c><jk>public</jk> N(String)</c>
+ * </ul>
+ *
+ * <p>
+ * Classes are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Classes annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Non-static member classes.
+ * </ul>
+ *
+ * <p>
+ * Members/constructors are ignored if any of the following are true:
+ * <ul>
+ * 	<li>Members/constructors annotated with {@link BeanIgnore @BeanIgnore}.
+ * 	<li>Deprecated members/constructors.
+ * </ul>
+ *
+ * @param <T> The normal class type.
+ */
+public class AutoStringSwap<T> extends org.apache.juneau.transform.StringSwap<T> {
+
+	private static final Set<String>
+		UNSWAP_METHOD_NAMES = newUnmodifiableHashSet("fromString", "fromValue", "valueOf", "parse", "parseString", "forName", "forString");
+
+	/**
+	 * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
+	 *
+	 * @param ci The class to try to constructor a dynamic swap on.
+	 * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
+	 */
+	@SuppressWarnings({ "rawtypes" })
+	public static PojoSwap<?,?> find(ClassInfo ci) {
+
+		if (shouldIgnore(ci))
+			return null;
+
+		for (MethodInfo m : ci.getPublicMethods())
+			if (isUnswapMethod(m, ci))
+				return new AutoStringSwap(ci, m, null);
+
+		for (ConstructorInfo cs : ci.getPublicConstructors())
+			if (isUnswapConstructor(cs))
+				return new AutoStringSwap(ci, null, cs);
+
+		return null;
+	}
+
+	private static boolean shouldIgnore(ClassInfo ci) {
+		return
+			ci.hasAnnotation(BeanIgnore.class)
+			|| ci.isNonStaticMemberClass();
+	}
+
+	private static boolean isUnswapMethod(MethodInfo mi, ClassInfo ci) {
+		return
+			mi.isNotDeprecated()
+			&& mi.isStatic()
+			&& mi.hasName(UNSWAP_METHOD_NAMES)
+			&& mi.hasFuzzyParamTypes(BeanSession.class, String.class)
+			&& mi.hasReturnTypeParent(ci)
+			&& ! mi.hasAnnotation(BeanIgnore.class);
+	}
+
+	private static boolean isUnswapConstructor(ConstructorInfo cs) {
+		return
+			cs.isNotDeprecated()
+			&& cs.hasParamTypes(String.class)
+			&& ! cs.hasAnnotation(BeanIgnore.class);
+	}
+
+	//------------------------------------------------------------------------------------------------------------------
+
+	private final Method unswapMethod;
+	private final Constructor<?> unswapConstructor;
+
+	private AutoStringSwap(ClassInfo ci, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+		super(ci.inner());
+		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
+		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+	}
+
+	@Override /* PojoSwap */
+	public String swap(BeanSession session, T o) throws SerializeException {
+		return o.toString();
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override /* PojoSwap */
+	public T unswap(BeanSession session, String f, ClassMeta<?> hint) throws ParseException {
+		try {
+			if (unswapMethod != null)
+				return (T)unswapMethod.invoke(null, getMatchingArgs(unswapMethod.getParameterTypes(), session, f));
+			return (T)unswapConstructor.newInstance(f);
+		} catch (Exception e) {
+			throw ParseException.create(e);
+		}
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DynamicSwaps.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DynamicSwaps.java
deleted file mode 100644
index 25b0242..0000000
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/DynamicSwaps.java
+++ /dev/null
@@ -1,129 +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.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.transform;
-
-import static org.apache.juneau.reflect.ReflectFlags.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.internal.*;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.reflect.*;
-import org.apache.juneau.serializer.*;
-
-/**
- * A dynamic POJO swap based on reflection of a Java class.
- */
-public class DynamicSwaps {
-
-	/**
-	 * Look for constructors and methods on this class and construct a dynamic swap if it's possible to do so.
-	 *
-	 * @param ci The class to try to constructor a dynamic swap on.
-	 * @return A POJO swap instance, or <jk>null</jk> if one could not be created.
-	 */
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	public static PojoSwap<?,?> find(ClassInfo ci) {
-
-		if (ci.hasAnnotation(BeanIgnore.class))
-			return null;
-
-		Class<?> c = ci.inner();
-		boolean isMemberClass = ci.isMemberClass() && ci.isNotStatic();
-
-		// Find swap() method if present.
-		for (MethodInfo m : ci.getPublicMethods()) {
-			if (m.isAll(PUBLIC, NOT_DEPRECATED, NOT_STATIC) && (m.hasName("swap") || m.hasName("toMap")) && m.hasFuzzyArgs(BeanSession.class)) {
-
-				Class<?> swapMethodType = m.getReturnType().inner();
-
-				for (MethodInfo m2 : ci.getPublicMethods()) {
-					if (m2.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && (m2.hasName("unswap") || m2.hasName("fromMap")) && m2.hasFuzzyArgs(BeanSession.class, swapMethodType)) {
-						return new SwapMethodsSwap(c, m, m2);
-					}
-				}
-
-				for (ConstructorInfo cs : ci.getPublicConstructors()) {
-					if (cs.isPublic() && cs.isNotDeprecated()) {
-						List<ClassInfo> pt = cs.getParamTypes();
-						if (pt.size() == (isMemberClass ? 2 : 1)) {
-							ClassInfo arg = pt.get(isMemberClass ? 1 : 0);
-							if (swapMethodType != null && arg.isChildOf(swapMethodType))
-								return new SwapMethodsSwap(c, m, cs);
-						}
-					}
-				}
-
-				return new SwapMethodsSwap(c, m);
-			}
-		}
-
-		return null;
-	}
-
-
-	//------------------------------------------------------------------------------------------------------------------
-	// POJO swap for class with swap/unswap methods.
-	//------------------------------------------------------------------------------------------------------------------
-
-	private static class SwapMethodsSwap<T> extends PojoSwap<T,Object> {
-
-		private final Method swapMethod, unswapMethod;
-		private final Constructor<?> swapConstructor;
-
-		public SwapMethodsSwap(Class<T> c, MethodInfo swapMethod, MethodInfo unswapMethod) {
-			this(c, swapMethod.inner(), unswapMethod.inner(), null);
-		}
-
-		public SwapMethodsSwap(Class<T> c, MethodInfo swapMethod, ConstructorInfo swapConstructor) {
-			this(c, swapMethod.inner(), null, swapConstructor.inner());
-		}
-
-		public SwapMethodsSwap(Class<T> c, MethodInfo swapMethod) {
-			this(c, swapMethod.inner(), null, null);
-		}
-
-		SwapMethodsSwap(Class<T> c, Method swapMethod, Method unswapMethod, Constructor<?> swapConstructor) {
-			super(c, swapMethod.getReturnType());
-			this.swapMethod = swapMethod;
-			this.unswapMethod = unswapMethod;
-			this.swapConstructor = swapConstructor;
-		}
-
-		@Override
-		public Object swap(BeanSession session, Object o) throws SerializeException {
-			try {
-				return swapMethod.invoke(o, ClassUtils.getMatchingArgs(swapMethod.getParameterTypes(), session));
-			} catch (Exception e) {
-				throw new SerializeException(e);
-			}
-		}
-
-		@SuppressWarnings("unchecked")
-		@Override
-		public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
-			try {
-				if (unswapMethod != null)
-					return (T)unswapMethod.invoke(null, ClassUtils.getMatchingArgs(swapMethod.getParameterTypes(), session, f));
-				if (swapConstructor != null)
-					return (T)swapConstructor.newInstance(f);
-				return super.unswap(session, f, hint);
-			} catch (Exception e) {
-				throw new ParseException(e);
-			}
-		}
-	}
-}
diff --git a/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html b/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html
index fad76c5..d76af81 100644
--- a/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html
+++ b/juneau-doc/docs/Topics/02.juneau-marshall/11.Transforms/02.DefaultPojoSwaps.html
@@ -13,7 +13,7 @@
  ***************************************************************************************************************************/
  -->
 
-{new} Default PojoSwaps
+{todo} Default PojoSwaps
 
 <p>
 	By default, all serializers and parsers have built in <c>PojoSwaps</c> defined for the following common data types: