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 2018/05/10 18:45:42 UTC

[juneau] branch master updated: Add support for q-values for matching against multiple serializers.

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 699c7d6  Add support for q-values for matching against multiple serializers.
699c7d6 is described below

commit 699c7d6dad40129e3e1352827295c17160086e40
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu May 10 14:45:28 2018 -0400

    Add support for q-values for matching against multiple serializers.
---
 .../juneau/serializer/SerializerGroupTest.java     | 10 ++---
 .../java/org/apache/juneau/jena/RdfSerializer.java | 19 ++++-----
 .../java/org/apache/juneau/csv/CsvSerializer.java  |  2 +-
 .../org/apache/juneau/html/HtmlDocSerializer.java  |  8 ++--
 .../org/apache/juneau/html/HtmlSerializer.java     |  8 ++--
 .../juneau/html/HtmlStrippedDocSerializer.java     |  6 ++-
 .../juneau/htmlschema/HtmlSchemaDocSerializer.java |  6 ++-
 .../main/java/org/apache/juneau/http/Accept.java   | 41 +++++++++++++++++++
 .../java/org/apache/juneau/http/MediaType.java     | 25 +++++++-----
 .../org/apache/juneau/http/MediaTypeRange.java     | 38 ++++++++++-------
 .../java/org/apache/juneau/jso/JsoSerializer.java  |  2 +-
 .../org/apache/juneau/json/JsonSerializer.java     | 11 ++---
 .../juneau/jsonschema/JsonSchemaSerializer.java    |  3 +-
 .../apache/juneau/msgpack/MsgPackSerializer.java   |  2 +-
 .../juneau/plaintext/PlainTextSerializer.java      |  8 ++--
 .../juneau/serializer/OutputStreamSerializer.java  |  8 ++--
 .../org/apache/juneau/serializer/Serializer.java   | 47 ++++++++++++++++------
 .../apache/juneau/serializer/SerializerGroup.java  | 24 ++++++-----
 .../apache/juneau/serializer/WriterSerializer.java |  8 ++--
 .../java/org/apache/juneau/uon/UonSerializer.java  |  8 ++--
 .../juneau/urlencoding/UrlEncodingSerializer.java  |  8 ++--
 .../java/org/apache/juneau/utils/StringObject.java |  2 +-
 .../java/org/apache/juneau/xml/XmlSerializer.java  |  8 ++--
 .../apache/juneau/yaml/proto/YamlSerializer.java   |  8 ++--
 juneau-doc/src/main/javadoc/overview.html          |  9 +++++
 .../juneau/examples/rest/PhotosResource.java       |  2 +-
 .../juneau/rest/test/AcceptCharsetResource.java    |  2 +-
 .../juneau/rest/test/CharsetEncodingsResource.java |  2 +-
 .../rest/test/DefaultContentTypesResource.java     |  2 +-
 .../apache/juneau/rest/test/GroupsResource.java    |  2 +-
 .../juneau/rest/test/InheritanceResource.java      |  2 +-
 .../juneau/rest/test/NlsPropertyResource.java      |  2 +-
 .../juneau/rest/test/OnPostCallResource.java       |  2 +-
 .../juneau/rest/test/SerializersResource.java      |  8 ++--
 .../apache/juneau/rest/BasicRestInfoProvider.java  |  2 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  2 +-
 .../rest/{util => mock}/MockHttpSession.java       |  9 ++++-
 .../juneau/rest/{util => mock}/MockRest.java       | 33 ++++++++++++++-
 .../rest/{util => mock}/MockServletRequest.java    | 10 ++++-
 .../rest/{util => mock}/MockServletResponse.java   | 12 ++++--
 .../juneau/rest/widget/ContentTypeMenuItem.java    |  2 +-
 .../juneau/rest/BasicRestInfoProviderTest.java     |  2 +-
 .../apache/juneau/rest/annotation/BodyTest.java    |  2 +-
 43 files changed, 287 insertions(+), 130 deletions(-)

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 6732e14..a443d6d 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 ps) {
-			super(ps, "application/json", "text/foo+*", "text/foo_a+*");
+			super(ps, "application/json", "text/foo+*,text/foo_a+*");
 		}
 	}
 
 	public static class SA2 extends JsonSerializer {
 		public SA2(PropertyStore ps) {
-			super(ps, "application/json", "text/foo+bar+*", "text/foo+bar_a+*");
+			super(ps, "application/json", "text/foo+bar+*,text/foo+bar_a+*");
 		}
 	}
 
 	public static class SA3 extends JsonSerializer {
 		public SA3(PropertyStore ps) {
-			super(ps, "application/json", "text/baz+*", "text/baz_a+*");
+			super(ps, "application/json", "text/baz+*,text/baz_a+*");
 		}
 	}
 
@@ -97,7 +97,7 @@ public class SerializerGroupTest {
 
 	public static class SB2 extends JsonSerializer {
 		public SB2(PropertyStore ps) {
-			super(ps, "application/json", "text/2", "text/2a");
+			super(ps, "application/json", "text/2,text/2a");
 		}
 	}
 
@@ -109,7 +109,7 @@ public class SerializerGroupTest {
 
 	public static class SB4 extends JsonSerializer {
 		public SB4(PropertyStore ps) {
-			super(ps, "application/json", "text/4", "text/4a");
+			super(ps, "application/json", "text/4,text/4a");
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
index 0771783..1b6b349 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
@@ -213,7 +213,7 @@ public class RdfSerializer extends WriterSerializer implements RdfCommon {
 				ps.builder()
 					.set(RDF_language, LANG_RDF_XML)
 					.build(), 
-				"text/xml+rdf"
+				"text/xml+rdf", "text/xml+rdf,text/xml+rdf+abbrev;q=0.9"
 			);
 		}
 	}
@@ -231,8 +231,7 @@ public class RdfSerializer extends WriterSerializer implements RdfCommon {
 				ps.builder()
 					.set(RDF_language, LANG_RDF_XML_ABBREV)
 					.build(), 
-				"text/xml+rdf", 
-				"text/xml+rdf+abbrev"
+				"text/xml+rdf", "text/xml+rdf+abbrev,text/xml+rdf;q=0.9"
 			);
 		}
 	}
@@ -250,7 +249,7 @@ public class RdfSerializer extends WriterSerializer implements RdfCommon {
 				ps.builder()
 					.set(RDF_language, LANG_NTRIPLE)
 					.build(), 
-				"text/n-triple"
+				"text/n-triple", null
 			);
 		}
 	}
@@ -268,7 +267,7 @@ public class RdfSerializer extends WriterSerializer implements RdfCommon {
 				ps.builder()
 					.set(RDF_language, LANG_TURTLE)
 					.build(), 
-				"text/turtle"
+				"text/turtle", null
 			);
 		}
 	}
@@ -286,7 +285,7 @@ public class RdfSerializer extends WriterSerializer implements RdfCommon {
 				ps.builder()
 					.set(RDF_language, LANG_N3)
 					.build(), 
-				"text/n3"
+				"text/n3", null
 			);
 		}
 	}
@@ -328,14 +327,16 @@ public class RdfSerializer extends WriterSerializer implements RdfCommon {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public RdfSerializer(PropertyStore ps, String produces, String...accept) {
+	public RdfSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		addLiteralTypes = getBooleanProperty(RDF_addLiteralTypes, false);
 		addRootProperty = getBooleanProperty(RDF_addRootProperty, false);
@@ -363,7 +364,7 @@ public class RdfSerializer extends WriterSerializer implements RdfCommon {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public RdfSerializer(PropertyStore ps) {
-		this(ps, "text/xml+rdf");
+		this(ps, "text/xml+rdf", null);
 	}
 	
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializer.java
index 5239dfc..7bf040c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializer.java
@@ -38,7 +38,7 @@ public final class CsvSerializer extends WriterSerializer {
 	 * @param ps The property store containing all the settings for this object.
 	 */
 	public CsvSerializer(PropertyStore ps) {
-		super(ps, "text/csv");
+		super(ps, "text/csv", null);
 	}
 
 	@Override /* Context */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
index 48abe4d..b5da3e4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
@@ -530,7 +530,7 @@ public class HtmlDocSerializer extends HtmlStrippedDocSerializer {
 	 * @param ps The property store containing all the settings for this object.
 	 */
 	public HtmlDocSerializer(PropertyStore ps) {
-		this(ps, "text/html");
+		this(ps, "text/html", null);
 	}
 
 	/**
@@ -551,14 +551,16 @@ public class HtmlDocSerializer extends HtmlStrippedDocSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json",text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public HtmlDocSerializer(PropertyStore ps, String produces, String...accept) {
+	public HtmlDocSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		style = getArrayProperty(HTMLDOC_style, String.class);
 		stylesheet = getArrayProperty(HTMLDOC_stylesheet, String.class);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
index a463138..eff57f5 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
@@ -645,7 +645,7 @@ public class HtmlSerializer extends XmlSerializer {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public HtmlSerializer(PropertyStore ps) {
-		this(ps, "text/html");
+		this(ps, "text/html", null);
 	}
 
 	/**
@@ -666,14 +666,16 @@ public class HtmlSerializer extends XmlSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public HtmlSerializer(PropertyStore ps, String produces, String...accept) {
+	public HtmlSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		uriAnchorText = getProperty(HTML_uriAnchorText, AnchorText.class, AnchorText.TO_STRING);
 		lookForLabelParameters = getBooleanProperty(HTML_detectLabelParameters, true);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
index 7af5da5..cc68f8a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlStrippedDocSerializer.java
@@ -59,14 +59,16 @@ public class HtmlStrippedDocSerializer extends HtmlSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public HtmlStrippedDocSerializer(PropertyStore ps, String produces, String...accept) {
+	public HtmlStrippedDocSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/htmlschema/HtmlSchemaDocSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/htmlschema/HtmlSchemaDocSerializer.java
index b521d36..3200ec7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/htmlschema/HtmlSchemaDocSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/htmlschema/HtmlSchemaDocSerializer.java
@@ -66,14 +66,16 @@ public final class HtmlSchemaDocSerializer extends HtmlDocSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public HtmlSchemaDocSerializer(PropertyStore ps, String produces, String...accept) {
+	public HtmlSchemaDocSerializer(PropertyStore ps, String produces, String accept) {
 		super(
 			ps.builder()
 				.set(SERIALIZER_detectRecursions, true)
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 ca94279..7f87704 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
@@ -230,6 +230,47 @@ public final class Accept {
 	}
 
 	/**
+	 * Same as {@link #findMatch(MediaType[])} but matching against media type ranges.
+	 * 
+	 * <p>
+	 * Note that the q-types on both the <code>mediaTypeRanges</code> parameter and this header
+	 * are taken into account when trying to find the best match.
+	 * <br>When both this header and the matching range have q-values, the q-value for the match is the result of multiplying them.
+	 * <br>(e.g. Accept=<js>"text/html;q=0.9"</js> and mediaTypeRange=<js>"text/html;q=0.9"</js> ==>, q-value=<code>0.81</code>).
+	 * 
+	 * @param mediaTypeRanges The media type ranges to match against.
+	 * @return The index into the array of the best match, or <code>-1</code> if no suitable matches could be found.
+	 */
+	public int findMatch(MediaTypeRange[] mediaTypeRanges) {
+		float matchQuant = 0;
+		int matchIndex = -1;
+		float q = 0f;
+
+		// Media ranges are ordered by 'q'.
+		// So we only need to search until we've found a match.
+		for (MediaTypeRange mr : mediaRanges) {
+			float q2 = mr.getQValue();
+
+			if (q2 < q || q2 == 0)
+				break;
+
+			for (int i = 0; i < mediaTypeRanges.length; i++) {
+				MediaTypeRange mt = mediaTypeRanges[i];
+				float matchQuant2 = mr.getMediaType().match(mt.getMediaType(), false) * mt.getQValue();
+
+				if (matchQuant2 > matchQuant) {
+					matchIndex = i;
+					matchQuant = matchQuant2;
+					q = q2;
+				}
+			}
+		}
+
+		return matchIndex;
+	}
+	
+	
+	/**
 	 * Convenience method for searching through all of the subtypes of all the media ranges in this header for the
 	 * presence of a subtype fragment.
 	 * 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaType.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaType.java
index f09eeba..05a7c05 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaType.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaType.java
@@ -35,8 +35,8 @@ import org.apache.juneau.json.*;
 @BeanIgnore
 public class MediaType implements Comparable<MediaType> {
 
-	private static final boolean nocache = Boolean.getBoolean("juneau.nocache");
-	private static final ConcurrentHashMap<String,MediaType> cache = new ConcurrentHashMap<>();
+	private static final boolean NOCACHE = Boolean.getBoolean("juneau.nocache");
+	private static final ConcurrentHashMap<String,MediaType> CACHE = new ConcurrentHashMap<>();
 
 	/** Reusable predefined media type */
 	@SuppressWarnings("javadoc")
@@ -92,14 +92,14 @@ public class MediaType implements Comparable<MediaType> {
 	public static MediaType forString(String s) {
 		if (isEmpty(s))
 			return null;
-		MediaType mt = cache.get(s);
-		if (mt == null) {
-			mt = new MediaType(s);
-			if (nocache)
-				return mt;
-			cache.putIfAbsent(s, mt);
-		}
-		return cache.get(s);
+		MediaType mt = CACHE.get(s);
+		if (mt != null)
+			return mt;
+		mt = new MediaType(s);
+		if (NOCACHE)
+			return mt;
+		CACHE.putIfAbsent(s, mt);
+		return CACHE.get(s);
 	}
 
 	/**
@@ -139,8 +139,11 @@ public class MediaType implements Comparable<MediaType> {
 
 		Builder(String mt) {
 			mt = mt.trim();
+			int i = mt.indexOf(',');
+			if (i != -1)
+				mt = mt.substring(0, i);
 
-			int i = mt.indexOf(';');
+			i = mt.indexOf(';');
 			if (i == -1) {
 				this.parameters = Collections.EMPTY_MAP;
 			} else {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaTypeRange.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaTypeRange.java
index ccbfd01..96249f1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaTypeRange.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/MediaTypeRange.java
@@ -16,6 +16,7 @@ import static org.apache.juneau.internal.CollectionUtils.*;
 
 import java.util.*;
 import java.util.Map.*;
+import java.util.concurrent.*;
 
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.internal.*;
@@ -33,6 +34,8 @@ import org.apache.juneau.internal.*;
 public final class MediaTypeRange implements Comparable<MediaTypeRange>  {
 
 	private static final MediaTypeRange[] DEFAULT = new MediaTypeRange[]{new MediaTypeRange("*/*")};
+	private static final boolean NOCACHE = Boolean.getBoolean("juneau.nocache");
+	private static final ConcurrentHashMap<String,MediaTypeRange[]> CACHE = new ConcurrentHashMap<>();
 
 	private final MediaType mediaType;
 	private final Float qValue;
@@ -72,22 +75,27 @@ public final class MediaTypeRange implements Comparable<MediaTypeRange>  {
 
 		if (value == null || value.length() == 0)
 			return DEFAULT;
-
-		if (value.indexOf(',') == -1)
-			return new MediaTypeRange[]{new MediaTypeRange(value)};
-
-		Set<MediaTypeRange> ranges = new TreeSet<>();
-
-		for (String r : StringUtils.split(value)) {
-			r = r.trim();
-
-			if (r.isEmpty())
-				continue;
-
-			ranges.add(new MediaTypeRange(r));
+		
+		MediaTypeRange[] mtr = CACHE.get(value);
+		if (mtr != null)
+			return mtr;
+		
+		if (value.indexOf(',') == -1) {
+			mtr = new MediaTypeRange[]{new MediaTypeRange(value)};
+		} else {
+			Set<MediaTypeRange> ranges = new TreeSet<>();
+			for (String r : StringUtils.split(value)) {
+				r = r.trim();
+				if (r.isEmpty())
+					continue;
+				ranges.add(new MediaTypeRange(r));
+			}
+			mtr = ranges.toArray(new MediaTypeRange[ranges.size()]);
 		}
-
-		return ranges.toArray(new MediaTypeRange[ranges.size()]);
+		if (NOCACHE)
+			return mtr;
+		CACHE.putIfAbsent(value, mtr);
+		return CACHE.get(value);
 	}
 
 	private MediaTypeRange(String token) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoSerializer.java
index c6820dc..8416b99 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jso/JsoSerializer.java
@@ -46,7 +46,7 @@ public class JsoSerializer extends OutputStreamSerializer {
 	 * @param ps The property store containing all the settings for this object.
 	 */
 	public JsoSerializer(PropertyStore ps) {
-		super(ps, "application/x-java-serialized-object");
+		super(ps, "application/x-java-serialized-object", null);
 	}
 
 	@Override /* Context */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
index a0bad2b..290090a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
@@ -306,8 +306,7 @@ public class JsonSerializer extends WriterSerializer {
 					.set(JSON_simpleMode, true)
 					.set(WSERIALIZER_quoteChar, '\'')
 					.build(),
-				"application/json",
-				"application/json+simple", "text/json+simple"
+				"application/json", "application/json+simple,text/json+simple,application/json;q=0.9,text/json;q=0.9"
 			);
 		}
 	}
@@ -373,7 +372,7 @@ public class JsonSerializer extends WriterSerializer {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public JsonSerializer(PropertyStore ps) {
-		this(ps, "application/json", "application/json", "text/json");
+		this(ps, "application/json", "application/json,text/json");
 	}
 
 	/**
@@ -394,14 +393,16 @@ public class JsonSerializer extends WriterSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public JsonSerializer(PropertyStore ps, String produces, String...accept) {
+	public JsonSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		
 		simpleMode = getBooleanProperty(JSON_simpleMode, false);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java
index 89bca6a..b586c0d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java
@@ -338,8 +338,7 @@ public class JsonSchemaSerializer extends JsonSerializer {
 				.set(SERIALIZER_detectRecursions, true)
 				.set(SERIALIZER_ignoreRecursions, true)
 				.build(),
-			"application/json",
-			"application/json+schema", "text/json+schema"
+			"application/json", "application/json+schema,text/json+schema"
 		);
 		
 		useBeanDefs = getBooleanProperty(JSONSCHEMA_useBeanDefs, false);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
index 7a06304..4ca9988 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializer.java
@@ -119,7 +119,7 @@ public class MsgPackSerializer extends OutputStreamSerializer {
 	 * @param ps The property store containing all the settings for this object.
 	 */
 	public MsgPackSerializer(PropertyStore ps) {
-		super(ps, "octal/msgpack");
+		super(ps, "octal/msgpack", null);
 		this.addBeanTypes = getBooleanProperty(MSGPACK_addBeanTypes, getBooleanProperty(SERIALIZER_addBeanTypes, false));
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextSerializer.java
index e64437d..39c8b45 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/plaintext/PlainTextSerializer.java
@@ -54,7 +54,7 @@ public class PlainTextSerializer extends WriterSerializer {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public PlainTextSerializer(PropertyStore ps) {
-		this(ps, "text/plain");
+		this(ps, "text/plain", null);
 	}
 
 	/**
@@ -75,14 +75,16 @@ public class PlainTextSerializer extends WriterSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public PlainTextSerializer(PropertyStore ps, String produces, String...accept) {
+	public PlainTextSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializer.java
index 4240531..ef2c984 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializer.java
@@ -69,7 +69,7 @@ public abstract class OutputStreamSerializer extends Serializer {
 	 */
 	public static final String OSSERIALIZER_binaryFormat = PREFIX + "binaryFormat.s";
 
-	static final OutputStreamSerializer DEFAULT = new OutputStreamSerializer(PropertyStore.create().build(), "") {
+	static final OutputStreamSerializer DEFAULT = new OutputStreamSerializer(PropertyStore.create().build(), "", "") {
 		@Override
 		public OutputStreamSerializerSession createSession(SerializerSessionArgs args) {
 			throw new NoSuchMethodError();
@@ -100,14 +100,16 @@ public abstract class OutputStreamSerializer extends Serializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	protected OutputStreamSerializer(PropertyStore ps, String produces, String...accept) {
+	protected OutputStreamSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 	
 		binaryFormat = getProperty(OSSERIALIZER_binaryFormat, BinaryFormat.class, BinaryFormat.HEX);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
index 83445e5..4567a68 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
@@ -17,6 +17,7 @@ import java.io.*;
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 
 /**
@@ -831,7 +832,7 @@ public abstract class Serializer extends BeanContext {
 	public static final String SERIALIZER_uriResolution = PREFIX + "uriResolution.s";
 
 	
-	static final Serializer DEFAULT = new Serializer(PropertyStore.create().build(), "") {
+	static final Serializer DEFAULT = new Serializer(PropertyStore.create().build(), "", "") {
 		@Override
 		public SerializerSession createSession(SerializerSessionArgs args) {
 			throw new NoSuchMethodError();
@@ -859,11 +860,12 @@ public abstract class Serializer extends BeanContext {
 	final UriRelativity uriRelativity;
 	final Class<? extends SerializerListener> listener;
 
-	private final MediaType[] accept;
+	private final MediaTypeRange[] accept;
+	private final MediaType[] accepts;
 	private final MediaType produces;
 
 	// Hidden constructors to force subclass from OuputStreamSerializer or WriterSerializer.
-	Serializer(PropertyStore ps, String produces, String...accept) {
+	Serializer(PropertyStore ps, String produces, String accept) {
 		super(ps);
 		
 		maxDepth = getIntegerProperty(SERIALIZER_maxDepth, 100);
@@ -884,14 +886,8 @@ public abstract class Serializer extends BeanContext {
 		listener = getClassProperty(SERIALIZER_listener, SerializerListener.class, null);
 
 		this.produces = MediaType.forString(produces);
-		if (accept.length == 0) {
-			this.accept = new MediaType[]{this.produces};
-		} else {
-			this.accept = new MediaType[accept.length];
-			for (int i = 0; i < accept.length; i++) {
-				this.accept[i] = MediaType.forString(accept[i]);
-			}
-		}
+		this.accept = accept == null ? MediaTypeRange.parse(produces) : MediaTypeRange.parse(accept);
+		this.accepts = accept == null ? new MediaType[] {this.produces} : MediaType.forStrings(StringUtils.split(accept, ',')); 
 	}
 
 	@Override /* Context */
@@ -1005,11 +1001,38 @@ public abstract class Serializer extends BeanContext {
 	/**
 	 * Returns the media types handled based on the value of the <code>accept</code> parameter passed into the constructor.
 	 * 
+	 * <p>
+	 * Note that the order of these ranges are from high to low q-value.
+	 * 
 	 * @return The list of media types.  Never <jk>null</jk>.
 	 */
-	public final MediaType[] getMediaTypes() {
+	public final MediaTypeRange[] getMediaTypeRanges() {
 		return accept;
 	}
+	
+	/**
+	 * Returns the first entry in the <code>accept</code> parameter passed into the constructor.
+	 * 
+	 * <p>
+	 * This signifies the 'primary' media type for this serializer.
+	 * 
+	 * @return The media type.  Never <jk>null</jk>.
+	 */
+	public final MediaType getPrimaryMediaType() {
+		return accepts[0];
+	}
+
+	/**
+	 * Returns the media types handled based on the value of the <code>accept</code> parameter passed into the constructor.
+	 * 
+	 * <p>
+	 * The order of the media types are the same as those in the <code>accept</code> parameter.
+	 * 
+	 * @return The list of media types.  Never <jk>null</jk>.
+	 */
+	public final MediaType[] getAcceptMediaTypes() {
+		return accepts;
+	}
 
 	/**
 	 * Optional method that returns the response <code>Content-Type</code> for this serializer if it is different from
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
index 98fb82b..073fbe8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
@@ -68,9 +68,10 @@ public final class SerializerGroup extends BeanContext {
 	// Maps Accept headers to matching serializers.
 	private final ConcurrentHashMap<String,SerializerMatch> cache = new ConcurrentHashMap<>();
 
-	private final MediaType[] mediaTypes;
+	private final MediaTypeRange[] mediaTypeRanges;
+	private final Serializer[] mediaTypeRangeSerializers;
+
 	private final List<MediaType> mediaTypesList;
-	private final Serializer[] mediaTypeSerializers;
 	private final List<Serializer> serializers;
 
 	/**
@@ -110,18 +111,21 @@ public final class SerializerGroup extends BeanContext {
 		super(ps);
 		this.serializers = immutableList(serializers);
 
-		List<MediaType> lmt = new ArrayList<>();
+		List<MediaTypeRange> lmtr = new ArrayList<>();
+		LinkedHashSet<MediaType> lmt = new LinkedHashSet<>();
 		List<Serializer> l = new ArrayList<>();
 		for (Serializer s : serializers) {
-			for (MediaType m: s.getMediaTypes()) {
-				lmt.add(m);
+			for (MediaTypeRange m: s.getMediaTypeRanges()) {
+				lmtr.add(m);
 				l.add(s);
 			}
+			for (MediaType mt : s.getAcceptMediaTypes())
+				lmt.add(mt);
 		}
 
-		this.mediaTypes = lmt.toArray(new MediaType[lmt.size()]);
-		this.mediaTypesList = unmodifiableList(lmt);
-		this.mediaTypeSerializers = l.toArray(new Serializer[l.size()]);
+		this.mediaTypeRanges = lmtr.toArray(new MediaTypeRange[lmt.size()]);
+		this.mediaTypesList = unmodifiableList(new ArrayList<>(lmt));
+		this.mediaTypeRangeSerializers = l.toArray(new Serializer[l.size()]);
 	}
 
 	/**
@@ -153,9 +157,9 @@ public final class SerializerGroup extends BeanContext {
 			return sm;
 
 		Accept a = Accept.forString(acceptHeader);
-		int match = a.findMatch(mediaTypes);
+		int match = a.findMatch(mediaTypeRanges);
 		if (match >= 0) {
-			sm = new SerializerMatch(mediaTypes[match], mediaTypeSerializers[match]);
+			sm = new SerializerMatch(mediaTypeRanges[match].getMediaType(), mediaTypeRangeSerializers[match]);
 			cache.putIfAbsent(acceptHeader, sm);
 		}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
index 03f3eb5..c706abd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
@@ -146,7 +146,7 @@ public abstract class WriterSerializer extends Serializer {
 	 */
 	public static final String WSERIALIZER_useWhitespace = PREFIX + "useWhitespace.b";
 
-	static final WriterSerializer DEFAULT = new WriterSerializer(PropertyStore.create().build(), "") {
+	static final WriterSerializer DEFAULT = new WriterSerializer(PropertyStore.create().build(), "", "") {
 		@Override
 		public WriterSerializerSession createSession(SerializerSessionArgs args) {
 			throw new NoSuchMethodError();
@@ -179,14 +179,16 @@ public abstract class WriterSerializer extends Serializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	protected WriterSerializer(PropertyStore ps, String produces, String...accept) {
+	protected WriterSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		
 		useWhitespace = getBooleanProperty(WSERIALIZER_useWhitespace, false);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java
index 8fb6d47..9bca5f7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java
@@ -317,7 +317,7 @@ public class UonSerializer extends WriterSerializer {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public UonSerializer(PropertyStore ps) {
-		this(ps, "text/uon");
+		this(ps, "text/uon", null);
 	}
 
 	/**
@@ -338,14 +338,16 @@ public class UonSerializer extends WriterSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public UonSerializer(PropertyStore ps, String produces, String...accept) {
+	public UonSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		encodeChars = getBooleanProperty(UON_encoding, false);
 		addBeanTypes = getBooleanProperty(UON_addBeanTypes, getBooleanProperty(SERIALIZER_addBeanTypes, false));
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index ee8f811..11a58bb 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -256,7 +256,7 @@ public class UrlEncodingSerializer extends UonSerializer {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public UrlEncodingSerializer(PropertyStore ps) {
-		this(ps, "application/x-www-form-urlencoded");
+		this(ps, "application/x-www-form-urlencoded", null);
 	}
 
 	/**
@@ -277,14 +277,16 @@ public class UrlEncodingSerializer extends UonSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public UrlEncodingSerializer(PropertyStore ps, String produces, String...accept) {
+	public UrlEncodingSerializer(PropertyStore ps, String produces, String accept) {
 		super(
 			ps.builder()
 				.set(UON_encoding, true)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/StringObject.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/StringObject.java
index 18546ab..56f3ba7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/StringObject.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/StringObject.java
@@ -94,6 +94,6 @@ public class StringObject implements CharSequence, Writable {
 
 	@Override /* Writable */
 	public MediaType getMediaType() {
-		return s.getMediaTypes()[0];
+		return s.getPrimaryMediaType();
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
index cee7b90..17dcf8c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -472,7 +472,7 @@ public class XmlSerializer extends WriterSerializer {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public XmlSerializer(PropertyStore ps) {
-		this(ps, "text/xml");
+		this(ps, "text/xml", null);
 	}
 
 	/**
@@ -493,14 +493,16 @@ public class XmlSerializer extends WriterSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public XmlSerializer(PropertyStore ps, String produces, String...accept) {
+	public XmlSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		autoDetectNamespaces = getBooleanProperty(XML_autoDetectNamespaces, true);
 		enableNamespaces = getBooleanProperty(XML_enableNamespaces, false);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java
index 2dc7618..b561a2f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/proto/YamlSerializer.java
@@ -265,7 +265,7 @@ public class YamlSerializer extends WriterSerializer {
 	 * 	The property store containing all the settings for this object.
 	 */
 	public YamlSerializer(PropertyStore ps) {
-		this(ps, "application/yaml", "application/yaml", "text/yaml");
+		this(ps, "application/yaml", "application/yaml,text/yaml");
 	}
 
 	/**
@@ -286,14 +286,16 @@ public class YamlSerializer extends WriterSerializer {
 	 * 	For example, if this serializer produces <js>"application/json"</js> but should handle media types of
 	 * 	<js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
 	 * 	<p class='bcode'>
-	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
+	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
 	 * 	</p>
 	 * 	<br>...or...
 	 * 	<p class='bcode'>
 	 * 	<jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
 	 * 	</p>
+	 * <p>
+	 * The accept value can also contain q-values.
 	 */
-	public YamlSerializer(PropertyStore ps, String produces, String...accept) {
+	public YamlSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 		simpleMode = getBooleanProperty(YAML_simpleMode, false);
 		escapeSolidus = getBooleanProperty(YAML_escapeSolidus, false);
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index c4f0d2a..4d88d55 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -21263,6 +21263,10 @@
 					<li class='jf'>{@link org.apache.juneau.html.annotation.HtmlFormat#HTML_CDC} - Format collections as comma-delimited lists.
 					<li class='jf'>{@link org.apache.juneau.html.annotation.HtmlFormat#HTML_SDC} - Format collections as space-delimited lists.
 				</ul> 
+			<li>
+				Serializers now allow for q-values on the media types they handle.
+				<br>For example, the accept media type on <code>JsonSerializer.Simple</code> is <js>"application/json+simple,application/json;q=0.9"</js>.
+				<br>This means the serializer CAN handle requests for <js>"application/json"</js> if no other serializers provide a better match.
 		</ul>
 		
 		<h5 class='topic w800'>juneau-dto</h5>
@@ -21385,6 +21389,11 @@
 				<br>Having it as a string allows us to differentiate between a set and unset value so that it can be overridden in subclasses.
 			<li>
 				The {@link org.apache.juneau.rest.annotation.Path#name()} annotation parameter is now required.
+			<li>
+				New class for mock unit testing of REST resources:
+				<ul>
+					<li class='jc'>{@link org.apache.juneau.rest.mock.MockRest}
+				</ul>
 		</ul>
 	
 		<h5 class='topic w800'>juneau-rest-client</h5>
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
index eb5a66e..f8511b8 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
@@ -141,7 +141,7 @@ public class PhotosResource extends BasicRestServlet {
 		 * @param ps The property store containing all the settings for this object.
 		 */
 		public ImageSerializer(PropertyStore ps) {
-			super(ps, null, "image/png", "image/jpeg");
+			super(ps, null, "image/png,image/jpeg");
 		}
 
 		@Override /* Serializer */ 
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
index 148616a..9f474fa 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java
@@ -73,7 +73,7 @@ public class AcceptCharsetResource extends RestServlet {
 	public static class TestSerializer extends OutputStreamSerializer {
 
 		public TestSerializer(PropertyStore ps) {
-			super(ps, "text/plain");
+			super(ps, "text/plain", null);
 		}
 
 		@Override /* Serializer */
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
index af3ff65..d386ee7 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java
@@ -54,7 +54,7 @@ public class CharsetEncodingsResource extends RestServlet {
 	public static class ASerializer extends WriterSerializer {
 
 		public ASerializer(PropertyStore ps) {
-			super(ps, "text/s");
+			super(ps, "text/s", null);
 		}
 
 		@Override /* Serializer */
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
index db4250a..c15a0d7 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
@@ -122,7 +122,7 @@ public class DefaultContentTypesResource extends RestServlet {
 		private String name;
 
 		private DummySerializer(PropertyStore ps, String name, String produces) {
-			super(ps, produces);
+			super(ps, produces, null);
 			this.name = name;
 		}
 
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
index f9cca1a..d049c30 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java
@@ -39,7 +39,7 @@ public class GroupsResource extends RestServlet {
 	public static class SSerializer extends WriterSerializer {
 
 		public SSerializer(PropertyStore ps) {
-			super(ps, "text/s1", "text/s1", "text/s2");
+			super(ps, "text/s1", "text/s1,text/s2");
 		}
 
 		@Override /* Serializer */
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
index 3d25407..797ff7e 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java
@@ -240,7 +240,7 @@ public class InheritanceResource extends RestServlet {
 	public static class DummySerializer extends WriterSerializer {
 
 		public DummySerializer(String produces) {
-			super(PropertyStore.DEFAULT, produces);
+			super(PropertyStore.DEFAULT, produces, null);
 		}
 
 		@Override /* Serializer */
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
index 98f78c9..d8e4f5d 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java
@@ -56,7 +56,7 @@ public class NlsPropertyResource extends RestServlet {
 	public static class TestSerializer extends WriterSerializer {
 
 		public TestSerializer(PropertyStore ps) {
-			super(ps, "text/plain");
+			super(ps, "text/plain", null);
 		}
 
 		@Override /* Serializer */
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
index c55b1ed..6ec2414 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java
@@ -43,7 +43,7 @@ public class OnPostCallResource extends RestServlet {
 	public static class TestSerializer extends WriterSerializer {
 
 		public TestSerializer(PropertyStore ps) {
-			super(ps, "test/s1", "text/s1", "text/s2", "text/s3");
+			super(ps, "test/s1", "text/s1,text/s2,text/s3");
 		}
 
 		@Override /* Serializer */
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
index 25ce7f9..5a67893 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java
@@ -32,7 +32,7 @@ public class SerializersResource extends BasicRestServlet {
 	public static class TestSerializerA extends WriterSerializer {
 
 		public TestSerializerA(PropertyStore ps) {
-			super(ps, "text/a");
+			super(ps, "text/a", null);
 		}
 
 		@Override /* Serializer */
@@ -50,7 +50,7 @@ public class SerializersResource extends BasicRestServlet {
 	public static class TestSerializerB extends WriterSerializer {
 
 		public TestSerializerB(PropertyStore ps) {
-			super(ps, "text/b");
+			super(ps, "text/b", null);
 		}
 
 		@Override /* Serializer */
@@ -92,7 +92,7 @@ public class SerializersResource extends BasicRestServlet {
 	public static class TestSerializerC extends WriterSerializer {
 
 		public TestSerializerC(PropertyStore ps) {
-			super(ps, "text/a");
+			super(ps, "text/a", null);
 		}
 
 		@Override /* Serializer */
@@ -118,7 +118,7 @@ public class SerializersResource extends BasicRestServlet {
 	public static class TestSerializerD extends WriterSerializer {
 
 		public TestSerializerD(PropertyStore ps) {
-			super(ps, "text/d", "text/a", "text/d");
+			super(ps, "text/d", "text/a,text/d");
 		}
 
 		@Override /* Serializer */
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
index 8c9cc6f..4481961 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
@@ -644,7 +644,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 						SerializerSessionArgs args = new SerializerSessionArgs(sprops, req.getJavaMethod(), req.getLocale(), null, mt, req.getUriContext());
 						try {
 							String eVal = s2.createSession(args).serializeToString(example);
-							examples.put(s2.getMediaTypes()[0].toString(), eVal);
+							examples.put(s2.getPrimaryMediaType().toString(), eVal);
 						} catch (Exception e) {
 							System.err.println("Could not serialize to media type ["+mt+"]: " + e.getLocalizedMessage());
 						}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index b81705d..097138a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -2221,7 +2221,7 @@ public final class RestContext extends BeanContext {
 	 * <br>The serializer selected is based on the request <code>Accept</code> header matched against the values returned by the following method
 	 * using a best-match algorithm:
 	 * <ul>
-	 * 	<li class='jm'>{@link Serializer#getMediaTypes()}
+	 * 	<li class='jm'>{@link Serializer#getMediaTypeRanges()}
 	 * </ul>
 	 * 
 	 * <h5 class='section'>Example:</h5>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockHttpSession.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockHttpSession.java
similarity index 94%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockHttpSession.java
rename to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockHttpSession.java
index 9184df0..5e4be3c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockHttpSession.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockHttpSession.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.util;
+package org.apache.juneau.rest.mock;
 
 import java.util.*;
 
@@ -18,7 +18,12 @@ import javax.servlet.*;
 import javax.servlet.http.*;
 
 /**
- * An implementation of {@link HttpSession} for testing purposes.
+ * An implementation of {@link HttpSession} for mocking purposes.
+ * 
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * 	<li class='link'>TODO
+ * </ul>
  */
 public class MockHttpSession implements HttpSession {
 	
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockRest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
similarity index 69%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockRest.java
rename to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
index 452e6fa..1199068 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockRest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockRest.java
@@ -10,17 +10,46 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.util;
+package org.apache.juneau.rest.mock;
 
 import java.util.*;
+import java.util.concurrent.*;
 
 import org.apache.juneau.rest.*;
 
 /**
  * Creates a mocked interface against a REST resource class.
+ * 
+ * <p>
+ * Allows you to test your REST resource classes without a running servlet container.
+ * 
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ *  <jk>public class</jk> MockTest {
+ *  	
+ *  	<jc>// Our REST resource to test.</jc>
+ *  	<ja>@RestResource</ja>(serializers=JsonSerializer.Simple.<jk>class</jk>, parsers=JsonParser.<jk>class</jk>)
+ *  	<jk>public static class</jk> M {
+ *  		
+ *  		<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/String"</js>)
+ *  		<jk>public</jk> String echo(<ja>@Body</ja> String b) {
+ *  			<jk>return</jk> b;
+ *  		}
+ *  	}
+ *  
+ *  <ja>@Test</js>
+ *  <jk>public void</jk> testEcho() <jk>throws</jk> Exception {
+ *  	<jsm>assertEquals</jsm>(<js>"'foo'"</js>, MockRest.<jsf>create</jsf>(M.<jk>class</jk>).request(<js>"PUT"</js>, <js>"/String"</js>).body(<js>"'foo'"</js>).execute().getBodyAsString());
+ *  }
+ * </p>
+ * 
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * 	<li class='link'>TODO
+ * </ul>
  */
 public class MockRest {
-	private static Map<Class<?>,RestContext> CONTEXTS = new HashMap<>();
+	private static Map<Class<?>,RestContext> CONTEXTS = new ConcurrentHashMap<>();
 
 	private final RestContext rc;
 	
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockServletRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
similarity index 98%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockServletRequest.java
rename to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
index 54da1c2..4730eb6 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockServletRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.util;
+package org.apache.juneau.rest.mock;
 
 import java.io.*;
 import java.security.*;
@@ -21,9 +21,15 @@ import javax.servlet.http.*;
 
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.util.*;
 
 /**
- * An implementation of {@link HttpServletRequest} for testing purposes.
+ * An implementation of {@link HttpServletRequest} for mocking purposes.
+ * 
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * 	<li class='link'>TODO
+ * </ul>
  */
 public class MockServletRequest implements HttpServletRequest {
 	
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockServletResponse.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
similarity index 96%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockServletResponse.java
rename to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
index 374f524..0e5efb2 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/MockServletResponse.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.rest.util;
+package org.apache.juneau.rest.mock;
 
 import java.io.*;
 import java.util.*;
@@ -19,10 +19,16 @@ import javax.servlet.*;
 import javax.servlet.http.*;
 
 import org.apache.juneau.internal.*;
+import org.apache.juneau.rest.util.*;
 
 /**
- * An implementation of {@link HttpServletResponse} for testing purposes.
- */
+ * An implementation of {@link HttpServletResponse} for mocking purposes.
+ * 
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * 	<li class='link'>TODO
+ * </ul>
+*/
 public class MockServletResponse implements HttpServletResponse {
 
 	private String characterEncoding = "UTF-8";
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
index cf31d83..d6173ff 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
@@ -74,7 +74,7 @@ public class ContentTypeMenuItem extends MenuItemWidget {
 		Div div = div();
 		Set<MediaType> l = new TreeSet<>();
 		for (Serializer s : req.getSerializers().getSerializers())
-			l.add(s.getMediaTypes()[0]);
+			l.add(s.getPrimaryMediaType());
 		for (MediaType mt : l) {
 			URI uri = req.getUri(true, new AMap<String,String>().append("plainText","true").append("Accept",mt.toString()));
 			div.children(a(uri, mt), br());
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
index 17867f8..7d2b17c 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
@@ -25,7 +25,7 @@ import org.apache.juneau.xml.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.util.*;
+import org.apache.juneau.rest.mock.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyTest.java
index 40a070f..5147f11 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyTest.java
@@ -21,7 +21,7 @@ import java.util.*;
 
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
-import org.apache.juneau.rest.util.*;
+import org.apache.juneau.rest.mock.*;
 import org.junit.*;
 import org.junit.runners.*;
 

-- 
To stop receiving notification emails like this one, please contact
jamesbognar@apache.org.