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 2017/09/04 23:54:07 UTC

[2/2] incubator-juneau git commit: Add multi-swap support (part 1).

Add multi-swap support (part 1).

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

Branch: refs/heads/master
Commit: 495c648d1f8934ebb41ae93c2b9d541371de2dd6
Parents: fc1e3fc
Author: JamesBognar <ja...@apache.org>
Authored: Mon Sep 4 19:54:11 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Mon Sep 4 19:54:11 2017 -0400

----------------------------------------------------------------------
 .../java/org/apache/juneau/ClassMetaTest.java   | 148 +++---
 .../a/rttests/RoundTripTransformBeansTest.java  |   2 +-
 .../org/apache/juneau/https/AcceptTest.java     |  74 ++-
 .../juneau/serializer/SerializerGroupTest.java  |   6 +-
 .../apache/juneau/test/pojos/SwappedPojo.java   |   2 +-
 .../juneau/transforms/ReaderObjectSwapTest.java |   8 +-
 .../transforms/SwapsAnnotationComboTest.java    | 478 +++++++++++++++++++
 .../apache/juneau/jena/RdfParserSession.java    |   8 +-
 .../juneau/jena/RdfSerializerSession.java       |   7 +-
 .../org/apache/juneau/BeanPropertyMeta.java     |   2 +-
 .../java/org/apache/juneau/BeanSession.java     |  16 +-
 .../main/java/org/apache/juneau/ClassMeta.java  | 129 +++--
 .../java/org/apache/juneau/annotation/Pojo.java |  84 ----
 .../java/org/apache/juneau/annotation/Swap.java |  31 ++
 .../org/apache/juneau/annotation/Swaps.java     |  27 ++
 .../apache/juneau/html/HtmlParserSession.java   |   4 +-
 .../html/HtmlSchemaDocSerializerSession.java    |   4 +-
 .../juneau/html/HtmlSerializerSession.java      |  33 +-
 .../java/org/apache/juneau/http/Accept.java     |   3 +-
 .../org/apache/juneau/http/ContentType.java     |   2 +-
 .../java/org/apache/juneau/http/MediaType.java  | 120 +++--
 .../org/apache/juneau/http/MediaTypeRange.java  |  13 -
 .../org/apache/juneau/internal/ArrayUtils.java  |  16 +
 .../org/apache/juneau/internal/ClassUtils.java  |   8 +-
 .../apache/juneau/json/JsonParserSession.java   |   8 +-
 .../json/JsonSchemaSerializerSession.java       |   4 +-
 .../org/apache/juneau/json/JsonSerializer.java  |   4 +-
 .../juneau/json/JsonSerializerSession.java      |   5 +-
 .../juneau/msgpack/MsgPackParserSession.java    |   8 +-
 .../msgpack/MsgPackSerializerSession.java       |   5 +-
 .../org/apache/juneau/parser/ParserSession.java |   8 +-
 .../juneau/serializer/SerializerSession.java    |   6 +-
 .../org/apache/juneau/transform/PojoSwap.java   | 100 +++-
 .../org/apache/juneau/uon/UonParserSession.java |   8 +-
 .../apache/juneau/uon/UonSerializerSession.java |   5 +-
 .../urlencoding/UrlEncodingParserSession.java   |  10 +-
 .../UrlEncodingSerializerSession.java           |  14 +-
 .../org/apache/juneau/xml/XmlParserSession.java |   8 +-
 .../juneau/xml/XmlSchemaSerializerSession.java  |  14 +-
 .../apache/juneau/xml/XmlSerializerSession.java |   7 +-
 .../juneau/rest/converters/Introspectable.java  |   7 +-
 .../juneau/rest/converters/Traversable.java     |   7 +-
 .../juneau/rest/labels/BeanDescription.java     |   2 +-
 .../juneau/rest/test/pojos/SwappedPojo.java     |   2 +-
 44 files changed, 1081 insertions(+), 376 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ClassMetaTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ClassMetaTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ClassMetaTest.java
index e01e5d5..4559d78 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ClassMetaTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ClassMetaTest.java
@@ -114,8 +114,10 @@ public class ClassMetaTest {
 	public void testSwaps() throws Exception {
 		BeanContext bc;
 		ClassMeta<?> ooo, hi1, hc1, hi2, hc2;
+		BeanSession bs;
 
 		bc = PropertyStore.create().getBeanContext();
+		bs = bc.createSession();
 		ooo = bc.getClassMeta(Object.class);
 		hi1 = bc.getClassMeta(HI1.class);
 		hc1 = bc.getClassMeta(HC1.class);
@@ -126,18 +128,19 @@ public class ClassMetaTest {
 		assertFalse(hc1.hasChildPojoSwaps());
 		assertFalse(hi2.hasChildPojoSwaps());
 		assertFalse(hc2.hasChildPojoSwaps());
-		assertNull(ooo.getPojoSwap());
-		assertNull(hi1.getPojoSwap());
-		assertNull(hc1.getPojoSwap());
-		assertNull(hi2.getPojoSwap());
-		assertNull(hc2.getPojoSwap());
-		assertEquals(ooo.getSerializedClassMeta().getInnerClass(), Object.class);
-		assertEquals(hi1.getSerializedClassMeta().getInnerClass(), HI1.class);
-		assertEquals(hc1.getSerializedClassMeta().getInnerClass(), HC1.class);
-		assertEquals(hi2.getSerializedClassMeta().getInnerClass(), HI2.class);
-		assertEquals(hc2.getSerializedClassMeta().getInnerClass(), HC2.class);
+		assertNull(ooo.getPojoSwap(bs));
+		assertNull(hi1.getPojoSwap(bs));
+		assertNull(hc1.getPojoSwap(bs));
+		assertNull(hi2.getPojoSwap(bs));
+		assertNull(hc2.getPojoSwap(bs));
+		assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), Object.class);
+		assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), HI1.class);
+		assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), HC1.class);
+		assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), HI2.class);
+		assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), HC2.class);
 
 		bc = PropertyStore.create().setPojoSwaps(HI1Swap.class).getBeanContext();
+		bs = bc.createSession();
 		ooo = bc.getClassMeta(Object.class);
 		hi1 = bc.getClassMeta(HI1.class);
 		hc1 = bc.getClassMeta(HC1.class);
@@ -148,18 +151,19 @@ public class ClassMetaTest {
 		assertFalse(hc1.hasChildPojoSwaps());
 		assertFalse(hi2.hasChildPojoSwaps());
 		assertFalse(hc2.hasChildPojoSwaps());
-		assertNull(ooo.getPojoSwap());
-		assertEquals(hi1.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(hc1.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(hi2.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(hc2.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(ooo.getSerializedClassMeta().getInnerClass(), Object.class);
-		assertEquals(hi1.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hc1.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hi2.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hc2.getSerializedClassMeta().getInnerClass(), Map.class);
+		assertNull(ooo.getPojoSwap(bs));
+		assertEquals(hi1.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(hc1.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(hi2.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(hc2.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), Object.class);
+		assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
 
 		bc = PropertyStore.create().setPojoSwaps(HC1Swap.class).getBeanContext();
+		bs = bc.createSession();
 		ooo = bc.getClassMeta(Object.class);
 		hi1 = bc.getClassMeta(HI1.class);
 		hc1 = bc.getClassMeta(HC1.class);
@@ -170,18 +174,19 @@ public class ClassMetaTest {
 		assertTrue(hc1.hasChildPojoSwaps());
 		assertFalse(hi2.hasChildPojoSwaps());
 		assertFalse(hc2.hasChildPojoSwaps());
-		assertNull(ooo.getPojoSwap());
-		assertNull(hi1.getPojoSwap());
-		assertEquals(hc1.getPojoSwap().getClass(), HC1Swap.class);
-		assertNull(hi2.getPojoSwap());
-		assertEquals(hc2.getPojoSwap().getClass(), HC1Swap.class);
-		assertEquals(ooo.getSerializedClassMeta().getInnerClass(), Object.class);
-		assertEquals(hi1.getSerializedClassMeta().getInnerClass(), HI1.class);
-		assertEquals(hc1.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hi2.getSerializedClassMeta().getInnerClass(), HI2.class);
-		assertEquals(hc2.getSerializedClassMeta().getInnerClass(), Map.class);
+		assertNull(ooo.getPojoSwap(bs));
+		assertNull(hi1.getPojoSwap(bs));
+		assertEquals(hc1.getPojoSwap(bs).getClass(), HC1Swap.class);
+		assertNull(hi2.getPojoSwap(bs));
+		assertEquals(hc2.getPojoSwap(bs).getClass(), HC1Swap.class);
+		assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), Object.class);
+		assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), HI1.class);
+		assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), HI2.class);
+		assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
 
 		bc = PropertyStore.create().setPojoSwaps(HI2Swap.class).getBeanContext();
+		bs = bc.createSession();
 		ooo = bc.getClassMeta(Object.class);
 		hi1 = bc.getClassMeta(HI1.class);
 		hc1 = bc.getClassMeta(HC1.class);
@@ -192,18 +197,19 @@ public class ClassMetaTest {
 		assertFalse(hc1.hasChildPojoSwaps());
 		assertTrue(hi2.hasChildPojoSwaps());
 		assertFalse(hc2.hasChildPojoSwaps());
-		assertNull(ooo.getPojoSwap());
-		assertNull(hi1.getPojoSwap());
-		assertNull(hc1.getPojoSwap());
-		assertEquals(hi2.getPojoSwap().getClass(), HI2Swap.class);
-		assertEquals(hc2.getPojoSwap().getClass(), HI2Swap.class);
-		assertEquals(ooo.getSerializedClassMeta().getInnerClass(), Object.class);
-		assertEquals(hi1.getSerializedClassMeta().getInnerClass(), HI1.class);
-		assertEquals(hc1.getSerializedClassMeta().getInnerClass(), HC1.class);
-		assertEquals(hi2.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hc2.getSerializedClassMeta().getInnerClass(), Map.class);
+		assertNull(ooo.getPojoSwap(bs));
+		assertNull(hi1.getPojoSwap(bs));
+		assertNull(hc1.getPojoSwap(bs));
+		assertEquals(hi2.getPojoSwap(bs).getClass(), HI2Swap.class);
+		assertEquals(hc2.getPojoSwap(bs).getClass(), HI2Swap.class);
+		assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), Object.class);
+		assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), HI1.class);
+		assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), HC1.class);
+		assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
 
 		bc = PropertyStore.create().setPojoSwaps(HC2Swap.class).getBeanContext();
+		bs = bc.createSession();
 		ooo = bc.getClassMeta(Object.class);
 		hi1 = bc.getClassMeta(HI1.class);
 		hc1 = bc.getClassMeta(HC1.class);
@@ -214,18 +220,19 @@ public class ClassMetaTest {
 		assertTrue(hc1.hasChildPojoSwaps());
 		assertTrue(hi2.hasChildPojoSwaps());
 		assertTrue(hc2.hasChildPojoSwaps());
-		assertNull(ooo.getPojoSwap());
-		assertNull(hi1.getPojoSwap());
-		assertNull(hc1.getPojoSwap());
-		assertNull(hi2.getPojoSwap());
-		assertEquals(hc2.getPojoSwap().getClass(), HC2Swap.class);
-		assertEquals(ooo.getSerializedClassMeta().getInnerClass(), Object.class);
-		assertEquals(hi1.getSerializedClassMeta().getInnerClass(), HI1.class);
-		assertEquals(hc1.getSerializedClassMeta().getInnerClass(), HC1.class);
-		assertEquals(hi2.getSerializedClassMeta().getInnerClass(), HI2.class);
-		assertEquals(hc2.getSerializedClassMeta().getInnerClass(), Map.class);
+		assertNull(ooo.getPojoSwap(bs));
+		assertNull(hi1.getPojoSwap(bs));
+		assertNull(hc1.getPojoSwap(bs));
+		assertNull(hi2.getPojoSwap(bs));
+		assertEquals(hc2.getPojoSwap(bs).getClass(), HC2Swap.class);
+		assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), Object.class);
+		assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), HI1.class);
+		assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), HC1.class);
+		assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), HI2.class);
+		assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
 
 		bc = PropertyStore.create().setPojoSwaps(HI1Swap.class,HC1Swap.class,HI2Swap.class,HC2Swap.class).getBeanContext();
+		bs = bc.createSession();
 		ooo = bc.getClassMeta(Object.class);
 		hi1 = bc.getClassMeta(HI1.class);
 		hc1 = bc.getClassMeta(HC1.class);
@@ -236,18 +243,19 @@ public class ClassMetaTest {
 		assertTrue(hc1.hasChildPojoSwaps());
 		assertTrue(hi2.hasChildPojoSwaps());
 		assertTrue(hc2.hasChildPojoSwaps());
-		assertNull(ooo.getPojoSwap());
-		assertEquals(hi1.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(hc1.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(hi2.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(hc2.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(ooo.getSerializedClassMeta().getInnerClass(), Object.class);
-		assertEquals(hi1.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hc1.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hi2.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hc2.getSerializedClassMeta().getInnerClass(), Map.class);
+		assertNull(ooo.getPojoSwap(bs));
+		assertEquals(hi1.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(hc1.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(hi2.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(hc2.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), Object.class);
+		assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
 
 		bc = PropertyStore.create().setPojoSwaps(HC2Swap.class,HI2Swap.class,HC1Swap.class,HI1Swap.class).getBeanContext();
+		bs = bc.createSession();
 		ooo = bc.getClassMeta(Object.class);
 		hi1 = bc.getClassMeta(HI1.class);
 		hc1 = bc.getClassMeta(HC1.class);
@@ -258,16 +266,16 @@ public class ClassMetaTest {
 		assertTrue(hc1.hasChildPojoSwaps());
 		assertTrue(hi2.hasChildPojoSwaps());
 		assertTrue(hc2.hasChildPojoSwaps());
-		assertNull(ooo.getPojoSwap());
-		assertEquals(hi1.getPojoSwap().getClass(), HI1Swap.class);
-		assertEquals(hc1.getPojoSwap().getClass(), HC1Swap.class);
-		assertEquals(hi2.getPojoSwap().getClass(), HI2Swap.class);
-		assertEquals(hc2.getPojoSwap().getClass(), HC2Swap.class);
-		assertEquals(ooo.getSerializedClassMeta().getInnerClass(), Object.class);
-		assertEquals(hi1.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hc1.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hi2.getSerializedClassMeta().getInnerClass(), Map.class);
-		assertEquals(hc2.getSerializedClassMeta().getInnerClass(), Map.class);
+		assertNull(ooo.getPojoSwap(bs));
+		assertEquals(hi1.getPojoSwap(bs).getClass(), HI1Swap.class);
+		assertEquals(hc1.getPojoSwap(bs).getClass(), HC1Swap.class);
+		assertEquals(hi2.getPojoSwap(bs).getClass(), HI2Swap.class);
+		assertEquals(hc2.getPojoSwap(bs).getClass(), HC2Swap.class);
+		assertEquals(ooo.getSerializedClassMeta(bs).getInnerClass(), Object.class);
+		assertEquals(hi1.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hc1.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hi2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
+		assertEquals(hc2.getSerializedClassMeta(bs).getInnerClass(), Map.class);
 	}
 
 	public interface HI1 {}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
index 7ea011c..f05026c 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
@@ -224,7 +224,7 @@ public class RoundTripTransformBeansTest extends RoundTripTest {
 		assertEquals("bar", t.f1);
 	}
 
-	@Pojo(swap=BSwap.class)
+	@Swap(BSwap.class)
 	public static class B {
 		public String f1;
 	}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/https/AcceptTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/https/AcceptTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/https/AcceptTest.java
index 6f44506..d8fb3a7 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/https/AcceptTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/https/AcceptTest.java
@@ -47,17 +47,17 @@ public class AcceptTest {
 			{ "MetaMatch-1", "text/*", "['text/a','text/b+c','text/b+d+e']", 2 },
 			{ "MetaMatch-2", "text/b+*", "['text/a','text/b+c','text/b+d+e']", 2 },
 			{ "MetaMatch-3", "text/c+*", "['text/a','text/b+c','text/b+d+e']", 1 },
-			{ "MetaMatch-4", "text/b+d+e", "['text/a','text/b+c','text/b+d']", 2 },
-			{ "MetaMatch-5", "text/b+*", "['text/a','text/b+c','text/b+d']", 1 },
+			{ "MetaMatch-4", "text/b+d+e", "['text/a','text/b+c','text/b+d']", -1 },
+			{ "MetaMatch-5", "text/b+*", "['text/a','text/b+c','text/b+d+e']", 2 },
 			{ "MetaMatch-6", "text/d+e+*", "['text/a','text/b+c','text/b+d+e']", 2 },
 
-			{ "MetaMatch-7", "*/a", "['text/a','application/a']", 0 },
+			{ "MetaMatch-7", "*/a", "['text/a','application/b']", 0 },
 			{ "MetaMatch-8", "*/*", "['text/a','text/b+c']", 1 },
 			{ "MetaMatch-9", "*/*", "['text/b+c','text/a']", 0 },
 
 			// Reverse meta-character matches
 			{ "RevMetaMatch-1", "text/a", "['text/*']", 0 },
-			{ "RevMetaMatch-3", "text/a", "['*/a']", 0 },
+			{ "RevMetaMatch-2", "text/a", "['*/a']", 0 },
 			{ "RevMetaMatch-3", "text/a", "['*/*']", 0 },
 
 			// Meta-character mixture matches
@@ -72,28 +72,32 @@ public class AcceptTest {
 			{ "Fuzzy-1", "text/1+2", "['text/1+2']", 0 },
 			// Order of subtype parts shouldn't matter.
 			{ "Fuzzy-2", "text/2+1", "['text/1+2']", 0 },
+			
 			// Should match if Accept has 'extra' subtypes.
 			// For example, "Accept: text/json+activity" should match against the "text/json" serializer.
-			{ "Fuzzy-3", "text/1+2", "['text/1']", 0 },
+			{ "Fuzzy-3", "text/json+foo", "['text/json+*']", 0 },
+			
 			// Shouldn't match because the accept media type must be at least a subset of the real media type
 			// For example, "Accept: text/json" should not match against the "text/json+lax" serializer.
-			{ "Fuzzy-4", "text/1", "['text/1+2']", -1 },
-			{ "Fuzzy-5", "text/1+2", "['text/1','text/1+3']", 0 },
+			{ "Fuzzy-4", "text/json", "['text/json+lax']", -1 },
+			
+			{ "Fuzzy-5", "text/1+2", "['text/1','text/1+3']", -1 },
+			
 			// "text/1+2" should be a better match than just "text/1"
 			{ "Fuzzy-6", "text/1+2", "['text/1','text/1+2','text/1+2+3']", 1 },
 			// Same as last, but mix up the order a bit.
 			{ "Fuzzy-7", "text/1+2", "['text/1+2+3','text/1','text/1+2']", 2 },
 			// Same as last, but mix up the order of the subtypes as well.
 			{ "Fuzzy-8", "text/1+2", "['text/3+2+1','text/1','text/2+1']", 2 },
-			{ "Fuzzy-9", "text/1+2+3+4", "['text/1+2','text/1+2+3']", 1 },
-			{ "Fuzzy-10", "text/1+2+3+4", "['text/1+2+3','text/1+2']", 0 },
-			{ "Fuzzy-11", "text/4+2+3+1", "['text/1+2+3','text/1+2']", 0 },
-			{ "Fuzzy-12", "text/4+2+3+1", "['text/1+2','text/1+2+3']", 1 },
+			{ "Fuzzy-9", "text/1+2+3+4", "['text/1+2','text/1+2+3']", -1 },
+			{ "Fuzzy-10", "text/1+2+3+4", "['text/1+2+3','text/1+2']", -1 },
+			{ "Fuzzy-11", "text/4+2+3+1", "['text/1+2+3','text/1+2']", -1 },
+			{ "Fuzzy-12", "text/4+2+3+1", "['text/1+2','text/1+2+3']", -1 },
 
 			// Q metrics
 			{ "Q-1", "text/A;q=0.9,text/B;q=0.1", "['text/A','text/B']", 0 },
 			{ "Q-2", "text/A;q=0.9,text/B;q=0.1", "['text/B','text/A']", 1 },
-			{ "Q-3", "text/A+1;q=0.9,text/B;q=0.1", "['text/A','text/B']", 0 },
+			{ "Q-3", "text/A+1;q=0.9,text/B;q=0.1", "['text/A','text/B']", 1 },
 			{ "Q-4", "text/A;q=0.9,text/B+1;q=0.1", "['text/A','text/B+1']", 0 },
 			{ "Q-5", "text/A;q=0.9,text/A+1;q=0.1", "['text/A+1','text/A']", 1 },
 
@@ -104,6 +108,42 @@ public class AcceptTest {
 			// Test media types with parameters
 			{ "Parms-1", "text/A", "['text/A;foo=bar','text/B']", 0 },
 			{ "Parms-2", "text/A;foo=bar", "['text/A','text/B']", 0 },
+			
+			// Real-world JSON
+			{ "Json-1a", "text/json", "['text/json','text/json+*','text/*','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-1b", "text/json", "['text/json+*','text/*','text/json+lax','text/json+lax+*','text/foo','text/json']", 5 },
+			{ "Json-1c", "text/json", "['text/json+*','text/*','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-1d", "text/json", "['text/*','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-1e", "text/json", "['text/json+lax','text/json+lax+*','text/foo']", -1 },
+			
+			{ "Json-2a", "text/json+lax", "['text/json+lax','text/json+lax+*','text/json+*','text/lax+*','text/*','text/json','text/lax']", 0 },
+			{ "Json-2b", "text/json+lax", "['text/json+lax+*','text/json+*','text/lax+*','text/*','text/json','text/lax']", 0 },
+			{ "Json-2c", "text/json+lax", "['text/json+*','text/lax+foo+*','text/*','text/json','text/lax']", 0 },
+			{ "Json-2d", "text/json+lax", "['text/lax+*','text/*','text/json','text/lax']", 0 },
+			{ "Json-2e", "text/json+lax", "['text/*','text/json','text/lax']", 0 },
+			{ "Json-2f", "text/json+lax", "['text/json','text/lax']", -1 },
+			
+			{ "Json-3a", "text/json+activity", "['text/json+activity','text/activity+json','text/json+activity+*','text/json+*','text/*','text/json','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-3b", "text/json+activity", "['text/activity+json','text/json+activity+*','text/json+*','text/*','text/json','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-3c", "text/json+activity", "['text/json+activity+*','text/json+*','text/*','text/json','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-3d", "text/json+activity", "['text/json+*','text/*','text/json','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-3e", "text/json+activity", "['text/*','text/json','text/json+lax','text/json+lax+*','text/foo']", 0 },
+			{ "Json-3f", "text/json+activity", "['text/json','text/json+lax','text/json+lax+*','text/foo']", -1 },
+
+			// Real-world XML
+			{ "Xml-1a", "text/xml", "['text/xml','text/xml+*','text/xml+rdf','text/foo']", 0 },
+			{ "Xml-1b", "text/xml", "['text/xml+*','text/xml+rdf','text/foo']", 0 },
+			{ "Xml-1c", "text/xml", "['text/xml+rdf','text/foo']", -1 },
+			{ "Xml-1d", "text/xml", "['text/foo']", -1 },
+
+			{ "Xml-2a", "text/xml+id", "['text/xml+*','text/xml','text/xml+rdf']", 0 },
+			{ "Xml-2b", "text/xml+id", "['text/xml','text/xml+rdf']", -1 },
+			{ "Xml-2c", "text/xml+id", "['text/xml+rdf']", -1 },
+
+			// Real-world RDF
+			{ "Rdf-1a", "text/xml+rdf", "['text/xml+rdf','text/xml+*','text/xml']", 0 },
+			{ "Rdf-1b", "text/xml+rdf", "['text/xml+*','text/xml']", 0 },
+			{ "Rdf-1c", "text/xml+rdf", "['text/xml']", -1 },
 		});
 	}
 
@@ -124,4 +164,14 @@ public class AcceptTest {
 		int r = accept.findMatch(mt);
 		TestUtils.assertEquals(expected, r, "{0} failed", label);
 	}
+
+	@Test
+	public void testReversed() throws Exception {
+		Accept accept = Accept.forString(this.accept);
+		MediaType[] mt = JsonParser.DEFAULT.parse(mediaTypes, MediaType[].class);
+		Collections.reverse(Arrays.asList(mt));
+		int r = accept.findMatch(mt);
+		int expected2 = expected == -1 ? -1 : mt.length-expected-1;
+		TestUtils.assertEquals(expected2, r, "{0} failed", label);
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/serializer/SerializerGroupTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/serializer/SerializerGroupTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/serializer/SerializerGroupTest.java
index b5e2db9..a9839d4 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/serializer/SerializerGroupTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/serializer/SerializerGroupTest.java
@@ -52,19 +52,19 @@ public class SerializerGroupTest {
 
 	public static class SA1 extends JsonSerializer {
 		public SA1(PropertyStore propertyStore) {
-			super(propertyStore, "application/json", "text/foo", "text/foo_a");
+			super(propertyStore, "application/json", "text/foo+*", "text/foo_a+*");
 		}
 	}
 
 	public static class SA2 extends JsonSerializer {
 		public SA2(PropertyStore propertyStore) {
-			super(propertyStore, "application/json", "text/foo+bar", "text/foo+bar_a");
+			super(propertyStore, "application/json", "text/foo+bar+*", "text/foo+bar_a+*");
 		}
 	}
 
 	public static class SA3 extends JsonSerializer {
 		public SA3(PropertyStore propertyStore) {
-			super(propertyStore, "application/json", "text/baz", "text/baz_a");
+			super(propertyStore, "application/json", "text/baz+*", "text/baz_a+*");
 		}
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/test/pojos/SwappedPojo.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/test/pojos/SwappedPojo.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/test/pojos/SwappedPojo.java
index 605fd25..2cba47c 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/test/pojos/SwappedPojo.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/test/pojos/SwappedPojo.java
@@ -14,7 +14,7 @@ package org.apache.juneau.test.pojos;
 
 import org.apache.juneau.annotation.*;
 
-@Pojo(swap=SwappedPojoSwap.class)
+@Swap(SwappedPojoSwap.class)
 public class SwappedPojo {
 	public boolean wasUnswapped;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/ReaderObjectSwapTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/ReaderObjectSwapTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/ReaderObjectSwapTest.java
index 5bc0e65..edd1328 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/ReaderObjectSwapTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/ReaderObjectSwapTest.java
@@ -349,7 +349,7 @@ public class ReaderObjectSwapTest extends ComboSerializeTest {
 		super(comboInput);
 	}
 
-	@Pojo(swap=PojoToSimpleReaderSwap.class)
+	@Swap(PojoToSimpleReaderSwap.class)
 	public static class PojoToSimpleReader {}
 	
 	public static class PojoToSimpleReaderSwap extends PojoSwap<PojoToSimpleReader,Reader> {
@@ -358,7 +358,7 @@ public class ReaderObjectSwapTest extends ComboSerializeTest {
 		}
 	}
 	
-	@Pojo(swap=PojoToDynamicReaderSwap.class)
+	@Swap(PojoToDynamicReaderSwap.class)
 	public static class PojoToDynamicReader {
 		private String f;
 		public PojoToDynamicReader(String f) {
@@ -372,7 +372,7 @@ public class ReaderObjectSwapTest extends ComboSerializeTest {
 		}
 	}
 	
-	@Pojo(swap=SometimesSwappedBeanSwap1.class)
+	@Swap(SometimesSwappedBeanSwap1.class)
 	public static class SometimesSwappedBean1 {
 		public String f;
 		public SometimesSwappedBean1(String f) {
@@ -389,7 +389,7 @@ public class ReaderObjectSwapTest extends ComboSerializeTest {
 		}
 	}
 	
-	@Pojo(swap=SometimesSwappedBeanSwap2.class)
+	@Swap(SometimesSwappedBeanSwap2.class)
 	public static class SometimesSwappedBean2 {
 		public String f;
 		public SometimesSwappedBean2(String f) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/SwapsAnnotationComboTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/SwapsAnnotationComboTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/SwapsAnnotationComboTest.java
new file mode 100644
index 0000000..c873ebe
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/transforms/SwapsAnnotationComboTest.java
@@ -0,0 +1,478 @@
+// ***************************************************************************************************************************
+// * 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.transforms;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
+import org.junit.runner.*;
+import org.junit.runners.*;
+
+/**
+ * Exhaustive serialization tests for the CalendarSwap class.
+ */
+@RunWith(Parameterized.class)
+@SuppressWarnings({"javadoc"})
+public class SwapsAnnotationComboTest extends ComboSerializeTest {
+
+	@Parameterized.Parameters
+	public static Collection<Object[]> getParameters() {
+		return Arrays.asList(new Object[][] {
+			{ 	/* 0 */
+				new ComboInput<TestMediaTypeLiterals>(
+					"TestMediaTypeLiterals",
+					TestMediaTypeLiterals.class,
+					new TestMediaTypeLiterals(),
+					/* Json */		"'JSON'",
+					/* JsonT */		"'JSON'",
+					/* JsonR */		"'JSON'",
+					/* Xml */		"<string>XML</string>",
+					/* XmlT */		"<string>XML</string>",
+					/* XmlR */		"<string>XML</string>\n",
+					/* XmlNs */		"<string>XML</string>",
+					/* Html */		"<string>HTML</string>",
+					/* HtmlT */		"<string>HTML</string>",
+					/* HtmlR */		"<string>HTML</string>",
+					/* Uon */		"UON",
+					/* UonT */		"UON",
+					/* UonR */		"UON",
+					/* UrlEnc */	"_value=URLENCODING",
+					/* UrlEncT */	"_value=URLENCODING",
+					/* UrlEncR */	"_value=URLENCODING",
+					/* MsgPack */	"A74D53475041434B",
+					/* MsgPackT */	"A74D53475041434B",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>RDFXML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 1 */
+				new ComboInput<TestMediaTypePatterns>(
+					"TestMediaTypePatterns",
+					TestMediaTypePatterns.class,
+					new TestMediaTypePatterns(),
+					/* Json */		"'JSON'",
+					/* JsonT */		"'JSON'",
+					/* JsonR */		"'JSON'",
+					/* Xml */		"<string>XML</string>",
+					/* XmlT */		"<string>XML</string>",
+					/* XmlR */		"<string>XML</string>\n",
+					/* XmlNs */		"<string>XML</string>",
+					/* Html */		"<string>HTML</string>",
+					/* HtmlT */		"<string>HTML</string>",
+					/* HtmlR */		"<string>HTML</string>",
+					/* Uon */		"UON",
+					/* UonT */		"UON",
+					/* UonR */		"UON",
+					/* UrlEnc */	"_value=URLENCODING",
+					/* UrlEncT */	"_value=URLENCODING",
+					/* UrlEncR */	"_value=URLENCODING",
+					/* MsgPack */	"A74D53475041434B",
+					/* MsgPackT */	"A74D53475041434B",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>RDFXML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 2 */
+				new ComboInput<TestMediaTypePatternsReversed>(
+					"TestMediaTypePatternsReversed",
+					TestMediaTypePatternsReversed.class,
+					new TestMediaTypePatternsReversed(),
+					/* Json */		"'JSON'",
+					/* JsonT */		"'JSON'",
+					/* JsonR */		"'JSON'",
+					/* Xml */		"<string>XML</string>",
+					/* XmlT */		"<string>XML</string>",
+					/* XmlR */		"<string>XML</string>\n",
+					/* XmlNs */		"<string>XML</string>",
+					/* Html */		"<string>HTML</string>",
+					/* HtmlT */		"<string>HTML</string>",
+					/* HtmlR */		"<string>HTML</string>",
+					/* Uon */		"UON",
+					/* UonT */		"UON",
+					/* UonR */		"UON",
+					/* UrlEnc */	"_value=URLENCODING",
+					/* UrlEncT */	"_value=URLENCODING",
+					/* UrlEncR */	"_value=URLENCODING",
+					/* MsgPack */	"A74D53475041434B",
+					/* MsgPackT */	"A74D53475041434B",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>RDFXML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 3 */
+				new ComboInput<TestMediaTypePatternsMulti>(
+					"TestMediaTypePatternsMulti",
+					TestMediaTypePatternsMulti.class,
+					new TestMediaTypePatternsMulti(),
+					/* Json */		"'JSON'",
+					/* JsonT */		"'JSON'",
+					/* JsonR */		"'JSON'",
+					/* Xml */		"<string>XML</string>",
+					/* XmlT */		"<string>XML</string>",
+					/* XmlR */		"<string>XML</string>\n",
+					/* XmlNs */		"<string>XML</string>",
+					/* Html */		"<string>HTML</string>",
+					/* HtmlT */		"<string>HTML</string>",
+					/* HtmlR */		"<string>HTML</string>",
+					/* Uon */		"UON",
+					/* UonT */		"UON",
+					/* UonR */		"UON",
+					/* UrlEnc */	"_value=URLENCODING",
+					/* UrlEncT */	"_value=URLENCODING",
+					/* UrlEncR */	"_value=URLENCODING",
+					/* MsgPack */	"A74D53475041434B",
+					/* MsgPackT */	"A74D53475041434B",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>RDFXML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 4 */
+				// In this case, "text/xml" should NOT match "text/xml+rdf".
+				new ComboInput<TestMediaTypePatternsPartial1>(
+					"TestMediaTypePatternsPartial1",
+					TestMediaTypePatternsPartial1.class,
+					new TestMediaTypePatternsPartial1(),
+					/* Json */		"'JSON'",
+					/* JsonT */		"'JSON'",
+					/* JsonR */		"'JSON'",
+					/* Xml */		"<string>XML</string>",
+					/* XmlT */		"<string>XML</string>",
+					/* XmlR */		"<string>XML</string>\n",
+					/* XmlNs */		"<string>XML</string>",
+					/* Html */		"<string>HTML</string>",
+					/* HtmlT */		"<string>HTML</string>",
+					/* HtmlR */		"<string>HTML</string>",
+					/* Uon */		"foo",
+					/* UonT */		"foo",
+					/* UonR */		"foo",
+					/* UrlEnc */	"_value=foo",
+					/* UrlEncT */	"_value=foo",
+					/* UrlEncR */	"_value=foo",
+					/* MsgPack */	"A3666F6F",
+					/* MsgPackT */	"A3666F6F",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>foo</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>foo</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>foo</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 5 */
+				// In this case, "text/xml+rdf" should NOT match "text/xml".
+				new ComboInput<TestMediaTypePatternsPartial2>(
+					"TestMediaTypePatternsPartial2",
+					TestMediaTypePatternsPartial2.class,
+					new TestMediaTypePatternsPartial2(),
+					/* Json */		"'foo'",
+					/* JsonT */		"'foo'",
+					/* JsonR */		"'foo'",
+					/* Xml */		"<string>foo</string>",
+					/* XmlT */		"<string>foo</string>",
+					/* XmlR */		"<string>foo</string>\n",
+					/* XmlNs */		"<string>foo</string>",
+					/* Html */		"<string>foo</string>",
+					/* HtmlT */		"<string>foo</string>",
+					/* HtmlR */		"<string>foo</string>",
+					/* Uon */		"UON",
+					/* UonT */		"UON",
+					/* UonR */		"UON",
+					/* UrlEnc */	"_value=URLENCODING",
+					/* UrlEncT */	"_value=URLENCODING",
+					/* UrlEncR */	"_value=URLENCODING",
+					/* MsgPack */	"A74D53475041434B",
+					/* MsgPackT */	"A74D53475041434B",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>RDFXML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>RDFXML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 6 */
+				// In this case, "text/xml+*" should match both the XML and RDF serializers.
+				new ComboInput<TestMediaTypePatternsXmlPlus>(
+					"TestMediaTypePatternsXmlPlus",
+					TestMediaTypePatternsXmlPlus.class,
+					new TestMediaTypePatternsXmlPlus(),
+					/* Json */		"'foo'",
+					/* JsonT */		"'foo'",
+					/* JsonR */		"'foo'",
+					/* Xml */		"<string>XML</string>",
+					/* XmlT */		"<string>XML</string>",
+					/* XmlR */		"<string>XML</string>\n",
+					/* XmlNs */		"<string>XML</string>",
+					/* Html */		"<string>foo</string>",
+					/* HtmlT */		"<string>foo</string>",
+					/* HtmlR */		"<string>foo</string>",
+					/* Uon */		"foo",
+					/* UonT */		"foo",
+					/* UonR */		"foo",
+					/* UrlEnc */	"_value=foo",
+					/* UrlEncT */	"_value=foo",
+					/* UrlEncR */	"_value=foo",
+					/* MsgPack */	"A3666F6F",
+					/* MsgPackT */	"A3666F6F",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>XML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>XML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>XML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 7 */
+				// In this case, "text/*+xml" should match both the XML and RDF serializers.
+				new ComboInput<TestMediaTypePatternsXmlPlusReversed>(
+					"TestMediaTypePatternsXmlPlusReversed",
+					TestMediaTypePatternsXmlPlusReversed.class,
+					new TestMediaTypePatternsXmlPlusReversed(),
+					/* Json */		"'foo'",
+					/* JsonT */		"'foo'",
+					/* JsonR */		"'foo'",
+					/* Xml */		"<string>XML</string>",
+					/* XmlT */		"<string>XML</string>",
+					/* XmlR */		"<string>XML</string>\n",
+					/* XmlNs */		"<string>XML</string>",
+					/* Html */		"<string>foo</string>",
+					/* HtmlT */		"<string>foo</string>",
+					/* HtmlR */		"<string>foo</string>",
+					/* Uon */		"foo",
+					/* UonT */		"foo",
+					/* UonR */		"foo",
+					/* UrlEnc */	"_value=foo",
+					/* UrlEncT */	"_value=foo",
+					/* UrlEncR */	"_value=foo",
+					/* MsgPack */	"A3666F6F",
+					/* MsgPackT */	"A3666F6F",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>XML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>XML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>XML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+			{ 	/* 8 */
+				// In this case, "text/rdf+*" should match only the RDF serializer.
+				new ComboInput<TestMediaTypePatternsRdfPlus>(
+					"TestMediaTypePatternsRdfPlus",
+					TestMediaTypePatternsRdfPlus.class,
+					new TestMediaTypePatternsRdfPlus(),
+					/* Json */		"'foo'",
+					/* JsonT */		"'foo'",
+					/* JsonR */		"'foo'",
+					/* Xml */		"<string>foo</string>",
+					/* XmlT */		"<string>foo</string>",
+					/* XmlR */		"<string>foo</string>\n",
+					/* XmlNs */		"<string>foo</string>",
+					/* Html */		"<string>foo</string>",
+					/* HtmlT */		"<string>foo</string>",
+					/* HtmlR */		"<string>foo</string>",
+					/* Uon */		"foo",
+					/* UonT */		"foo",
+					/* UonR */		"foo",
+					/* UrlEnc */	"_value=foo",
+					/* UrlEncT */	"_value=foo",
+					/* UrlEncR */	"_value=foo",
+					/* MsgPack */	"A3666F6F",
+					/* MsgPackT */	"A3666F6F",
+					/* RdfXml */	"<rdf:RDF>\n<rdf:Description>\n<j:value>XML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlT */	"<rdf:RDF>\n<rdf:Description>\n<j:value>XML</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
+					/* RdfXmlR */	"<rdf:RDF>\n  <rdf:Description>\n    <j:value>XML</j:value>\n  </rdf:Description>\n</rdf:RDF>\n"
+				)
+			},
+//			{ 	/* 0 */
+//				new ComboInput<byte[]>(
+//					"ByteArray1d",
+//					byte[].class,
+//					new byte[] {1,2,3},
+//					/* Json */		"xxx",
+//					/* JsonT */		"xxx",
+//					/* JsonR */		"xxx",
+//					/* Xml */		"xxx",
+//					/* XmlT */		"xxx",
+//					/* XmlR */		"xxx",
+//					/* XmlNs */		"xxx",
+//					/* Html */		"xxx",
+//					/* HtmlT */		"xxx",
+//					/* HtmlR */		"xxx",
+//					/* Uon */		"xxx",
+//					/* UonT */		"xxx",
+//					/* UonR */		"xxx",
+//					/* UrlEnc */	"xxx",
+//					/* UrlEncT */	"xxx",
+//					/* UrlEncR */	"xxx",
+//					/* MsgPack */	"xxx",
+//					/* MsgPackT */	"xxx",
+//					/* RdfXml */	"xxx",
+//					/* RdfXmlT */	"xxx",
+//					/* RdfXmlR */	"xxx"
+//				)
+//			},
+		});
+	}
+
+	public SwapsAnnotationComboTest(ComboInput<?> comboInput) {
+		super(comboInput);
+	}
+
+	@Override
+	protected Serializer applySettings(Serializer s) throws Exception {
+		return s.builder().pojoSwaps(ByteArrayBase64Swap.class).trimNullProperties(false).build();
+	}
+
+	@Swaps(
+		{
+			@Swap(value=SwapJson.class, mediaTypes={"application/json"}),
+			@Swap(value=SwapXml.class, mediaTypes={"text/xml"}),
+			@Swap(value=SwapHtml.class, mediaTypes={"text/html"}),
+			@Swap(value=SwapUon.class, mediaTypes={"text/uon"}),
+			@Swap(value=SwapUrlEncoding.class, mediaTypes={"application/x-www-form-urlencoded"}),
+			@Swap(value=SwapMsgPack.class, mediaTypes={"octal/msgpack"}),
+			@Swap(value=SwapRdfXml.class, mediaTypes={"text/xml+rdf"}),
+		}
+	)
+	public static class TestMediaTypeLiterals {}
+
+	@Swaps(
+		{
+			@Swap(value=SwapJson.class, mediaTypes={"*/json"}),
+			@Swap(value=SwapXml.class, mediaTypes={"*/xml"}),
+			@Swap(value=SwapHtml.class, mediaTypes={"*/html"}),
+			@Swap(value=SwapUon.class, mediaTypes={"*/uon"}),
+			@Swap(value=SwapUrlEncoding.class, mediaTypes={"*/x-www-form-urlencoded"}),
+			@Swap(value=SwapMsgPack.class, mediaTypes={"*/msgpack"}),
+			@Swap(value=SwapRdfXml.class, mediaTypes={"*/xml+rdf"}),
+		}
+	)
+	public static class TestMediaTypePatterns {}
+
+	@Swaps(
+		{
+			@Swap(value=SwapRdfXml.class, mediaTypes={"*/xml+rdf"}),
+			@Swap(value=SwapMsgPack.class, mediaTypes={"*/msgpack"}),
+			@Swap(value=SwapUrlEncoding.class, mediaTypes={"*/x-www-form-urlencoded"}),
+			@Swap(value=SwapUon.class, mediaTypes={"*/uon"}),
+			@Swap(value=SwapHtml.class, mediaTypes={"*/html"}),
+			@Swap(value=SwapXml.class, mediaTypes={"*/xml"}),
+			@Swap(value=SwapJson.class, mediaTypes={"*/json"}),
+		}
+	)
+	public static class TestMediaTypePatternsReversed {}
+
+	@Swaps(
+		{
+			@Swap(value=SwapJson.class, mediaTypes={"*/foo","*/json","*/bar"}),
+			@Swap(value=SwapXml.class, mediaTypes={"*/foo","*/xml","*/bar"}),
+			@Swap(value=SwapHtml.class, mediaTypes={"*/foo","*/html","*/bar"}),
+			@Swap(value=SwapUon.class, mediaTypes={"*/foo","*/uon","*/bar"}),
+			@Swap(value=SwapUrlEncoding.class, mediaTypes={"*/foo","*/x-www-form-urlencoded","*/bar"}),
+			@Swap(value=SwapMsgPack.class, mediaTypes={"*/foo","*/msgpack","*/bar"}),
+			@Swap(value=SwapRdfXml.class, mediaTypes={"*/foo","*/xml+rdf","*/bar"}),
+		}
+	)
+	public static class TestMediaTypePatternsMulti {}
+
+	@Swaps(
+		{
+			@Swap(value=SwapJson.class, mediaTypes={"*/foo","*/json","*/bar"}),
+			@Swap(value=SwapXml.class, mediaTypes={"*/foo","*/xml","*/bar"}),
+			@Swap(value=SwapHtml.class, mediaTypes={"*/foo","*/html","*/bar"}),
+		}
+	)
+	public static class TestMediaTypePatternsPartial1 {
+		public String toString() {
+			return "foo";
+		}
+	}
+
+	@Swaps(
+		{
+			@Swap(value=SwapUon.class, mediaTypes={"*/foo","*/uon","*/bar"}),
+			@Swap(value=SwapUrlEncoding.class, mediaTypes={"*/foo","*/x-www-form-urlencoded","*/bar"}),
+			@Swap(value=SwapMsgPack.class, mediaTypes={"*/foo","*/msgpack","*/bar"}),
+			@Swap(value=SwapRdfXml.class, mediaTypes={"*/foo","*/xml+rdf","*/bar"}),
+		}
+	)
+	public static class TestMediaTypePatternsPartial2 {
+		public String toString() {
+			return "foo";
+		}
+	}
+	
+	@Swaps(
+		{
+			@Swap(value=SwapXml.class, mediaTypes={"text/xml+*"}),
+		}
+	)
+	public static class TestMediaTypePatternsXmlPlus {
+		public String toString() {
+			return "foo";
+		}
+	}
+
+	@Swaps(
+		{
+			@Swap(value=SwapXml.class, mediaTypes={"text/*+xml"}),
+		}
+	)
+	public static class TestMediaTypePatternsXmlPlusReversed {
+		public String toString() {
+			return "foo";
+		}
+	}
+
+	@Swaps(
+		{
+			@Swap(value=SwapXml.class, mediaTypes={"text/rdf+*"}),
+		}
+	)
+	public static class TestMediaTypePatternsRdfPlus {
+		public String toString() {
+			return "foo";
+		}
+	}
+
+	public static class SwapJson extends PojoSwap {
+		public Object swap(BeanSession session, Object o) throws Exception {
+			return "JSON";
+		}
+	}
+	public static class SwapXml extends PojoSwap {
+		public Object swap(BeanSession session, Object o) throws Exception {
+			return "XML";
+		}
+	}
+	public static class SwapHtml extends PojoSwap {
+		public Object swap(BeanSession session, Object o) throws Exception {
+			return "HTML";
+		}
+	}
+	public static class SwapUon extends PojoSwap {
+		public Object swap(BeanSession session, Object o) throws Exception {
+			return "UON";
+		}
+	}
+	public static class SwapUrlEncoding extends PojoSwap {
+		public Object swap(BeanSession session, Object o) throws Exception {
+			return "URLENCODING";
+		}
+	}
+	public static class SwapMsgPack extends PojoSwap {
+		public Object swap(BeanSession session, Object o) throws Exception {
+			return "MSGPACK";
+		}
+	}
+	public static class SwapRdfXml extends PojoSwap {
+		public Object swap(BeanSession session, Object o) throws Exception {
+			return "RDFXML";
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
index 267d06f..04e779f 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
@@ -228,8 +228,8 @@ public class RdfParserSession extends ReaderParserSession {
 
 		if (eType == null)
 			eType = (ClassMeta<T>)object();
-		PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap();
-		ClassMeta<?> sType = eType.getSerializedClassMeta();
+		PojoSwap<T,Object> swap = (PojoSwap<T,Object>)eType.getPojoSwap(this);
+		ClassMeta<?> sType = swap == null ? eType : swap.getSwapClassMeta(this);
 		setCurrentClass(sType);
 
 		if (! sType.canCreateNewInstance(outer)) {
@@ -341,8 +341,8 @@ public class RdfParserSession extends ReaderParserSession {
 			throw new ParseException("Class ''{0}'' could not be instantiated.  Reason: ''{1}''", sType.getInnerClass().getName(), sType.getNotABeanReason());
 		}
 
-		if (transform != null && o != null)
-			o = transform.unswap(this, o, eType);
+		if (swap != null && o != null)
+			o = swap.unswap(this, o, eType);
 
 		if (outer != null)
 			setParent(eType, o, outer);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
index 0f66237..9c0e701 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
@@ -206,12 +206,13 @@ public final class RdfSerializerSession extends WriterSerializerSession {
 				aType = ((Delegate)o).getClassMeta();
 			}
 
-			sType = aType.getSerializedClassMeta();
+			sType = aType;
 
 			// Swap if necessary
-			PojoSwap swap = aType.getPojoSwap();
+			PojoSwap swap = aType.getPojoSwap(this);
 			if (swap != null) {
 				o = swap.swap(this, o);
+				sType = swap.getSwapClassMeta(this);
 
 				// If the getSwapClass() method returns Object, we need to figure out
 				// the actual type now.
@@ -219,7 +220,7 @@ public final class RdfSerializerSession extends WriterSerializerSession {
 					sType = getClassMetaForObject(o);
 			}
 		} else {
-			sType = eType.getSerializedClassMeta();
+			sType = eType.getSerializedClassMeta(this);
 		}
 
 		String typeName = getBeanTypeName(eType, aType, bpm);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index c550408..5464f52 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -210,7 +210,7 @@ public class BeanPropertyMeta {
 				return false;
 
 			if (typeMeta == null)
-				typeMeta = (swap != null ? swap.getSwapClassMeta(beanContext) : rawTypeMeta == null ? beanContext.object() : rawTypeMeta.getSerializedClassMeta());
+				typeMeta = (swap != null ? beanContext.getClassMeta(swap.getSwapClass()) : rawTypeMeta == null ? beanContext.object() : rawTypeMeta);
 			if (typeMeta == null)
 				typeMeta = rawTypeMeta;
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index bad3d38..64d165c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -357,19 +357,19 @@ public class BeanSession extends Session {
 			if (tc == Class.class)
 				return (T)(ctx.classLoader.loadClass(value.toString()));
 
-			if (type.getPojoSwap() != null) {
-				PojoSwap f = type.getPojoSwap();
-				Class<?> nc = f.getNormalClass(), fc = f.getSwapClass();
+			PojoSwap swap = type.getPojoSwap(this);
+			if (swap != null) {
+				Class<?> nc = swap.getNormalClass(), fc = swap.getSwapClass();
 				if (isParentClass(nc, tc) && isParentClass(fc, value.getClass()))
-					return (T)f.unswap(this, value, type);
+					return (T)swap.unswap(this, value, type);
 			}
 
 			ClassMeta<?> vt = ctx.getClassMetaForObject(value);
-			if (vt.getPojoSwap() != null) {
-				PojoSwap f = vt.getPojoSwap();
-				Class<?> nc = f.getNormalClass(), fc = f.getSwapClass();
+			swap = vt.getPojoSwap(this);
+			if (swap != null) {
+				Class<?> nc = swap.getNormalClass(), fc = swap.getSwapClass();
 				if (isParentClass(nc, vt.getInnerClass()) && isParentClass(fc, tc))
-					return (T)f.swap(this, value);
+					return (T)swap.swap(this, value);
 			}
 
 			if (type.isPrimitive()) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
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 0e1bd72..036c4ae 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
@@ -22,10 +22,12 @@ import java.lang.reflect.Proxy;
 import java.net.*;
 import java.net.URI;
 import java.util.*;
+import java.util.Date;
 import java.util.concurrent.*;
 import java.util.concurrent.locks.*;
 
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.http.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.remoteable.*;
@@ -93,12 +95,11 @@ public final class ClassMeta<T> implements Type {
 	private final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
 		childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
 		childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
-	private final PojoSwap<T,?> pojoSwap;                   // The object POJO swap associated with this bean (if it has one).
+	private final PojoSwap<T,?>[] pojoSwaps;                // The object POJO swaps associated with this bean (if it has any).
 	private final BeanFilter beanFilter;                    // The bean filter associated with this bean (if it has one).
 	private final MetadataMap extMeta;                      // Extended metadata
 	private final BeanContext beanContext;                  // The bean context that created this object.
 	private final ClassMeta<?>
-		serializedClassMeta,                                 // The transformed class type (if class has swap associated with it).
 		elementType,                                         // If ARRAY or COLLECTION, the element class type.
 		keyType,                                             // If MAP, the key class type.
 		valueType;                                           // If MAP, the value class type.
@@ -167,7 +168,7 @@ public final class ClassMeta<T> implements Type {
 			this.publicMethods = builder.publicMethods;
 			this.remoteableMethods = builder.remoteableMethods;
 			this.beanFilter = beanFilter;
-			this.pojoSwap = builder.pojoSwap;
+			this.pojoSwaps = builder.pojoSwaps.isEmpty() ? null : builder.pojoSwaps.toArray(new PojoSwap[builder.pojoSwaps.size()]);
 			this.extMeta = new MetadataMap();
 			this.keyType = builder.keyType;
 			this.valueType = builder.valueType;
@@ -177,7 +178,6 @@ public final class ClassMeta<T> implements Type {
 			this.initException = builder.initException;
 			this.typePropertyName = builder.typePropertyName;
 			this.dictionaryName = builder.dictionaryName;
-			this.serializedClassMeta = builder.serializedClassMeta;
 			this.invocationHandler = builder.invocationHandler;
 			this.beanRegistry = builder.beanRegistry;
 			this.isMemberClass = builder.isMemberClass;
@@ -231,7 +231,6 @@ public final class ClassMeta<T> implements Type {
 		this.remoteableMethods = mainType.remoteableMethods;
 		this.publicMethods = mainType.publicMethods;
 		this.beanContext = mainType.beanContext;
-		this.serializedClassMeta = this;
 		this.elementType = elementType;
 		this.keyType = keyType;
 		this.valueType = valueType;
@@ -240,7 +239,7 @@ public final class ClassMeta<T> implements Type {
 		this.typePropertyName = mainType.typePropertyName;
 		this.dictionaryName = mainType.dictionaryName;
 		this.notABeanReason = mainType.notABeanReason;
-		this.pojoSwap = mainType.pojoSwap;
+		this.pojoSwaps = mainType.pojoSwaps;
 		this.beanFilter = mainType.beanFilter;
 		this.extMeta = mainType.extMeta;
 		this.initException = mainType.initException;
@@ -278,7 +277,6 @@ public final class ClassMeta<T> implements Type {
 		this.remoteableMethods = null;
 		this.publicMethods = null;
 		this.beanContext = null;
-		this.serializedClassMeta = this;
 		this.elementType = null;
 		this.keyType = null;
 		this.valueType = null;
@@ -287,7 +285,7 @@ public final class ClassMeta<T> implements Type {
 		this.typePropertyName = null;
 		this.dictionaryName = null;
 		this.notABeanReason = null;
-		this.pojoSwap = null;
+		this.pojoSwaps = null;
 		this.beanFilter = null;
 		this.extMeta = new MetadataMap();
 		this.initException = null;
@@ -334,7 +332,7 @@ public final class ClassMeta<T> implements Type {
 			dictionaryName = null;
 		Throwable initException = null;
 		BeanMeta beanMeta = null;
-		PojoSwap pojoSwap = null;
+		List<PojoSwap> pojoSwaps = new ArrayList<PojoSwap>();
 		InvocationHandler invocationHandler = null;
 		BeanRegistry beanRegistry = null;
 		PojoSwap<?,?>[] childPojoSwaps;
@@ -557,33 +555,36 @@ public final class ClassMeta<T> implements Type {
 				final Method fSwapMethod = swapMethod;
 				final Method fUnswapMethod = unswapMethod;
 				final Constructor<T> fSwapConstructor = swapConstructor;
-				this.pojoSwap = new PojoSwap<T,Object>(c, swapMethod.getReturnType()) {
-					@Override
-					public Object swap(BeanSession session, Object o) throws SerializeException {
-						try {
-							return fSwapMethod.invoke(o, session);
-						} catch (Exception e) {
-							throw new SerializeException(e);
+				this.pojoSwaps.add(
+					new PojoSwap<T,Object>(c, swapMethod.getReturnType()) {
+						@Override
+						public Object swap(BeanSession session, Object o) throws SerializeException {
+							try {
+								return fSwapMethod.invoke(o, session);
+							} catch (Exception e) {
+								throw new SerializeException(e);
+							}
 						}
-					}
-					@Override
-					public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
-						try {
-							if (fUnswapMethod != null)
-								return (T)fUnswapMethod.invoke(null, session, f);
-							if (fSwapConstructor != null)
-								return fSwapConstructor.newInstance(f);
-							return super.unswap(session, f, hint);
-						} catch (Exception e) {
-							throw new ParseException(e);
+						@Override
+						public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
+							try {
+								if (fUnswapMethod != null)
+									return (T)fUnswapMethod.invoke(null, session, f);
+								if (fSwapConstructor != null)
+									return fSwapConstructor.newInstance(f);
+								return super.unswap(session, f, hint);
+							} catch (Exception e) {
+								throw new ParseException(e);
+							}
 						}
 					}
-				};
+				);
 			}
-			if (this.pojoSwap == null)
-				this.pojoSwap = findPojoSwap();
-			if (this.pojoSwap == null)
-				this.pojoSwap = pojoSwap;
+
+			if (pojoSwap != null)
+				this.pojoSwaps.add(pojoSwap);
+
+			findPojoSwaps(this.pojoSwaps);
 
 			try {
 
@@ -644,7 +645,7 @@ public final class ClassMeta<T> implements Type {
 			if (beanMeta != null)
 				dictionaryName = beanMeta.getDictionaryName();
 
-			serializedClassMeta = (this.pojoSwap == null ? ClassMeta.this : findClassMeta(this.pojoSwap.getSwapClass()));
+			serializedClassMeta = (this.pojoSwaps.isEmpty() ? ClassMeta.this : findClassMeta(this.pojoSwaps.get(0).getSwapClass()));
 			if (serializedClassMeta == null)
 				serializedClassMeta = ClassMeta.this;
 
@@ -667,17 +668,23 @@ public final class ClassMeta<T> implements Type {
 			return null;
 		}
 
-		private PojoSwap<T,?> findPojoSwap() {
-			Pojo p = innerClass.getAnnotation(Pojo.class);
-			if (p != null) {
-				Class<?> c = p.swap();
-				if (c != Null.class) {
-					if (isParentClass(PojoSwap.class, c))
-						return ClassUtils.newInstance(PojoSwap.class, c);
-					throw new RuntimeException("TODO - Surrogate classes not yet supported.");
-				}
-			}
-			return null;
+		private void findPojoSwaps(List<PojoSwap> l) {
+			Swap swap = innerClass.getAnnotation(Swap.class);
+			if (swap != null)
+				l.add(createPojoSwap(swap));
+			Swaps swaps = innerClass.getAnnotation(Swaps.class);
+			if (swaps != null)
+				for (Swap s : swaps.value())
+					l.add(createPojoSwap(s));
+		}
+
+		private PojoSwap<T,?> createPojoSwap(Swap s) {
+			Class<?> c = s.value();
+
+			if (! isParentClass(PojoSwap.class, c))
+				throw new FormattedRuntimeException("Invalid swap class ''{0}'' specified.  Must extend from PojoSwap.", c);
+
+			return ClassUtils.newInstance(PojoSwap.class, c).forMediaTypes(MediaType.forStrings(s.mediaTypes())).withTemplate(s.template());
 		}
 
 		private ClassMeta<?> findClassMeta(Class<?> c) {
@@ -866,11 +873,15 @@ public final class ClassMeta<T> implements Type {
 	/**
 	 * Returns the serialized (swapped) form of this class if there is an {@link PojoSwap} associated with it.
 	 *
+	 * @param session
+	 * 	The bean session.
+	 * 	<br>Required because the swap used may depend on the media type being serialized or parsed.
 	 * @return The serialized class type, or this object if no swap is associated with the class.
 	 */
 	@BeanIgnore
-	public ClassMeta<?> getSerializedClassMeta() {
-		return serializedClassMeta;
+	public ClassMeta<?> getSerializedClassMeta(BeanSession session) {
+		PojoSwap<T,?> ps = getPojoSwap(session);
+		return (ps == null ? this : ps.getSwapClassMeta(session));
 	}
 
 	/**
@@ -1226,14 +1237,32 @@ public final class ClassMeta<T> implements Type {
 	}
 
 	/**
-	 * Returns the {@link PojoSwap} associated with this class.
+	 * Returns the {@link PojoSwap} associated with this class that's the best match for the specified session.
 	 *
+	 * @param session
+	 * 	The current bean session.
+	 * 	<br>If multiple swaps are associated with a class, only the first one with a matching media type will
+	 * 	be returned.
 	 * @return
-	 * 	The {@link PojoSwap} associated with this class, or <jk>null</jk> if there is no POJO swap associated with
+	 * 	The {@link PojoSwap} associated with this class, or <jk>null</jk> if there are no POJO swaps associated with
 	 * 	this class.
 	 */
-	public PojoSwap<T,?> getPojoSwap() {
-		return pojoSwap;
+	public PojoSwap<T,?> getPojoSwap(BeanSession session) {
+		if (pojoSwaps != null) {
+			int matchQuant = 0, matchIndex = -1;
+
+			for (int i = 0; i < pojoSwaps.length; i++) {
+				int q = pojoSwaps[i].match(session);
+				if (q > matchQuant) {
+					matchQuant = q;
+					matchIndex = i;
+				}
+			}
+
+			if (matchIndex > -1)
+				return pojoSwaps[matchIndex];
+		}
+		return null;
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Pojo.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Pojo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Pojo.java
deleted file mode 100644
index 0823e6d..0000000
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Pojo.java
+++ /dev/null
@@ -1,84 +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.annotation;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
-import java.lang.annotation.*;
-
-import org.apache.juneau.transform.*;
-
-/**
- * Used to tailor how POJOs get interpreted by the framework.
- */
-@Documented
-@Target(TYPE)
-@Retention(RUNTIME)
-@Inherited
-public @interface Pojo {
-
-	/**
-	 * Associate a {@link PojoSwap} or {@link SurrogateSwap} with this class type.
-	 *
-	 * <p>
-	 * Supports the following class types:
-	 * <ul>
-	 * 	<li>Subclasses of {@link PojoSwap}.
-	 * 	<li>Any other class.  Will get interpreted as a {@link SurrogateSwap}.
-	 * </ul>
-	 *
-	 * <h5 class='section'>Example:</h5>
-	 * <p>
-	 * In this case, a swap is being applied to a bean that will force it to be serialized as a <code>String</code>:
-	 * <p class='bcode'>
-	 * 	<jc>// Our bean class</jc>
-	 * 	<ja>@Pojo</ja>(swap=BSwap.<jk>class</jk>)
-	 * 	<jk>public class</jk> B {
-	 * 		<jk>public</jk> String <jf>f1</jf>;
-	 * 	}
-	 *
-	 * 	<jc>// Our POJO swap to force the bean to be serialized as a String</jc>
-	 * 	<jk>public class</jk> BSwap <jk>extends</jk> PojoSwap&lt;B,String&gt; {
-	 * 		<jk>public</jk> String swap(BeanSession s, B o) <jk>throws</jk> SerializeException {
-	 * 			<jk>return</jk> o.f1;
-	 * 		}
-	 * 		<jk>public</jk> B unswap(BeanSession s, String f) <jk>throws</jk> ParseException { {
-	 * 			B b1 = <jk>new</jk> B();
-	 * 			b1.<jf>f1</jf> = f;
-	 * 			<jk>return</jk> b1;
-	 * 		}
-	 * 	}
-	 *
-	 * 	<jk>public void</jk> test() <jk>throws</jk> Exception {
-	 * 		WriterSerializer s = JsonSerializer.<jsf>DEFAULT</jsf>;
-	 * 		B b = <jk>new</jk> B();
-	 * 		b.<jf>f1</jf> = <js>"bar"</js>;
-	 * 		String json = s.serialize(b);
-	 * 		<jsm>assertEquals</jsm>(<js>"\"bar\""</js>, json);
-	 *
-	 * 		ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
-	 * 		b = p.parse(json, B.<jk>class</jk>);
-	 * 		<jsm>assertEquals</jsm>(<js>"bar"</js>, b.<jf>f1</jf>);
-	 * 	}
-	 * </p>
-	 *
-	 * <p>
-	 * Note that using this annotation is functionally equivalent to adding swaps to the serializers and parsers:
-	 * <p class='bcode'>
-	 * 	WriterSerializer s = <jk>new</jk> JsonSerializerBuilder().pojoSwaps(BSwap.<jk>class</jk>).build();
-	 * 	ReaderParser p = <jk>new</jk> JsonParserBuilder().pojoSwaps(BSwap.<jk>class</jk>).build();
-	 * </p>
-	 */
-	Class<?> swap() default Null.class;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java
new file mode 100644
index 0000000..1daa3e9
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swap.java
@@ -0,0 +1,31 @@
+// ***************************************************************************************************************************
+// * 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.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+@Documented
+@Target({TYPE,ANNOTATION_TYPE})
+@Retention(RUNTIME)
+@Inherited
+public @interface Swap {
+
+	Class<?> value() default Null.class;
+
+	String template() default "";
+
+	String[] mediaTypes() default {};
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swaps.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swaps.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swaps.java
new file mode 100644
index 0000000..4795ce8
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Swaps.java
@@ -0,0 +1,27 @@
+// ***************************************************************************************************************************
+// * 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.annotation;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+@Documented
+@Target({TYPE,ANNOTATION_TYPE})
+@Retention(RUNTIME)
+@Inherited
+public @interface Swaps {
+
+	Swap[] value() default {};
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
index 376843a..975cae4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
@@ -83,8 +83,8 @@ public final class HtmlParserSession extends XmlParserSession {
 
 		if (eType == null)
 			eType = (ClassMeta<T>)object();
-		PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap();
-		ClassMeta<?> sType = eType.getSerializedClassMeta();
+		PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap(this);
+		ClassMeta<?> sType = transform == null ? eType : transform.getSwapClassMeta(this);
 		setCurrentClass(sType);
 
 		int event = r.getEventType();

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
index 27f020a..847b40d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSchemaDocSerializerSession.java
@@ -68,7 +68,7 @@ public class HtmlSchemaDocSerializerSession extends HtmlDocSerializerSession {
 
 		aType = push(attrName, eType, null);
 
-		sType = eType.getSerializedClassMeta();
+		sType = eType.getSerializedClassMeta(this);
 		String type = null;
 
 		if (sType.isEnum() || sType.isCharSequence() || sType.isChar())
@@ -86,7 +86,7 @@ public class HtmlSchemaDocSerializerSession extends HtmlDocSerializerSession {
 
 		out.put("type", type);
 		out.put("class", eType.toString());
-		PojoSwap t = eType.getPojoSwap();
+		PojoSwap t = eType.getPojoSwap(this);
 		if (t != null)
 			out.put("transform", t);
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index 8cbbb83..3f1f1fd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -263,15 +263,17 @@ public class HtmlSerializerSession extends XmlSerializerSession {
 				aType = ((Delegate)o).getClassMeta();
 			}
 
-			sType = aType.getSerializedClassMeta();
+			sType = aType;
+
 			String typeName = null;
 			if (isAddBeanTypeProperties() && ! eType.equals(aType))
 				typeName = aType.getDictionaryName();
 
 			// Swap if necessary
-			PojoSwap swap = aType.getPojoSwap();
+			PojoSwap swap = aType.getPojoSwap(this);
 			if (swap != null) {
 				o = swap.swap(this, o);
+				sType = swap.getSwapClassMeta(this);
 
 				// If the getSwapClass() method returns Object, we need to figure out
 				// the actual type now.
@@ -564,10 +566,10 @@ public class HtmlSerializerSession extends XmlSerializerSession {
 			for (Object o : c) {
 				ClassMeta<?> cm = getClassMetaForObject(o);
 
-				if (cm != null && cm.getPojoSwap() != null) {
-					PojoSwap f = cm.getPojoSwap();
-					o = f.swap(this, o);
-					cm = cm.getSerializedClassMeta();
+				if (cm != null && cm.getPojoSwap(this) != null) {
+					PojoSwap swap = cm.getPojoSwap(this);
+					o = swap.swap(this, o);
+					cm = swap.getSwapClassMeta(this);
 				}
 
 				out.oTag(i+1, "tr");
@@ -705,11 +707,13 @@ public class HtmlSerializerSession extends XmlSerializerSession {
 		if (o1 == null)
 			return null;
 		ClassMeta<?> cm = getClassMetaForObject(o1);
-		if (cm.getPojoSwap() != null) {
-			PojoSwap f = cm.getPojoSwap();
-			o1 = f.swap(this, o1);
-			cm = cm.getSerializedClassMeta();
+
+		PojoSwap swap = cm.getPojoSwap(this);
+		if (swap != null) {
+			o1 = swap.swap(this, o1);
+			cm = swap.getSwapClassMeta(this);
 		}
+
 		if (cm == null || ! cm.isMapOrBean())
 			return null;
 		if (cm.getInnerClass().isAnnotationPresent(HtmlLink.class))
@@ -767,10 +771,11 @@ public class HtmlSerializerSession extends XmlSerializerSession {
 			if (o == null)
 				continue;
 			cm = getClassMetaForObject(o);
-			if (cm != null && cm.getPojoSwap() != null) {
-				PojoSwap f = cm.getPojoSwap();
-				o = f.swap(this, o);
-				cm = cm.getSerializedClassMeta();
+
+			PojoSwap ps = cm == null ? null : cm.getPojoSwap(this);
+			if (ps != null) {
+				o = ps.swap(this, o);
+				cm = ps.getSwapClassMeta(this);
 			}
 			if (prevC.contains(cm))
 				continue;

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Accept.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Accept.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Accept.java
index 4ea7bec..5b5c64f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Accept.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Accept.java
@@ -219,7 +219,8 @@ public final class Accept {
 
 			for (int i = 0; i < mediaTypes.length; i++) {
 				MediaType mt = mediaTypes[i];
-				int matchQuant2 = mt.match(mr.getMediaType());
+				int matchQuant2 = mr.getMediaType().match(mt, false);
+
 				if (matchQuant2 > matchQuant) {
 					matchIndex = i;
 					matchQuant = matchQuant2;

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/495c648d/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ContentType.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ContentType.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ContentType.java
index 05a4f3e..5bcc4ed 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ContentType.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ContentType.java
@@ -95,7 +95,7 @@ public class ContentType extends MediaType {
 
 		for (int i = 0; i < mediaTypes.length; i++) {
 			MediaType mt = mediaTypes[i];
-			int matchQuant2 = mt.match(this);
+			int matchQuant2 = mt.match(this, true);
 			if (matchQuant2 > matchQuant) {
 				matchQuant = matchQuant2;
 				matchIndex = i;