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 6109582  Improvements to @Rest(messages)
6109582 is described below

commit 610958239eda54a22c7dd9bd073f7e40e2e57a82
Author: JamesBognar <[email protected]>
AuthorDate: Mon Jul 27 11:15:31 2020 -0400

    Improvements to @Rest(messages)
---
 .../apache/juneau/utils/Tuple2Function_Test.java   |  71 +++++-------
 .../java/org/apache/juneau/utils/Tuple2_Test.java  |  84 +++++++-------
 .../apache/juneau/utils/Tuple3Function_Test.java   |  71 +++++-------
 .../java/org/apache/juneau/utils/Tuple3_Test.java  |  87 +++++++-------
 .../apache/juneau/utils/Tuple4Function_Test.java   |  71 +++++-------
 .../java/org/apache/juneau/utils/Tuple4_Test.java  |  90 ++++++++-------
 .../apache/juneau/utils/Tuple5Function_Test.java   |  71 +++++-------
 .../java/org/apache/juneau/utils/Tuple5_Test.java  |  53 +++++++++
 .../java/org/apache/juneau/BeanPropertyMeta.java   |   2 +-
 .../java/org/apache/juneau/internal/HashCode.java  |  15 ++-
 .../main/java/org/apache/juneau/utils/Tuple2.java  |  73 +++++++++---
 .../org/apache/juneau/utils/Tuple2Function.java    |  39 ++++---
 .../main/java/org/apache/juneau/utils/Tuple3.java  |  88 +++++++++++---
 .../org/apache/juneau/utils/Tuple3Function.java    |  40 ++++---
 .../main/java/org/apache/juneau/utils/Tuple4.java  | 111 ++++++++++++++++++
 .../org/apache/juneau/utils/Tuple4Function.java    |  41 ++++---
 .../main/java/org/apache/juneau/utils/Tuple5.java  | 126 +++++++++++++++++++++
 .../org/apache/juneau/utils/Tuple5Function.java    |  42 ++++---
 juneau-doc/docs/ReleaseNotes/8.1.4.html            |   2 +
 .../Topics/06.juneau-rest-server/22.Messages.html  | 100 +++++++++++-----
 .../rest/annotation/RestResourceMessagesTest.java  |  70 ------------
 .../juneau/rest/annotation/Rest_Messages_Test.java | 126 +++++++++++++++++++++
 ...ourceMessagesTest1.properties => A1.properties} |   2 +-
 ...ourceMessagesTest2.properties => A2.properties} |   2 +-
 ...urceMessagesTest1.properties => B1x.properties} |   2 +-
 ...urceMessagesTest2.properties => B2x.properties} |   2 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  66 ++++++-----
 .../org/apache/juneau/rest/RestContextBuilder.java |  27 +----
 .../java/org/apache/juneau/rest/RestRequest.java   |   5 +-
 .../juneau/rest/annotation/RestConfigApply.java    |   4 +-
 .../rest/annotation/RestResourceConfigApply.java   |   2 +-
 31 files changed, 1040 insertions(+), 545 deletions(-)

diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple2Function_Test.java
similarity index 69%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple2Function_Test.java
index df16803..345723b 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple2Function_Test.java
@@ -1,40 +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.rest;
-
-/**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
- */
-public class MessageBundleLocation {
-
-       final Class<?> baseClass;
-       final String bundlePath;
-
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
-       }
-}
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple2Function_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple2Function<Integer,Integer,Integer> x = (a,b)->a+b;
+               assertInteger(x.apply(1,2)).is(3);
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple2_Test.java
similarity index 57%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple2_Test.java
index df16803..ff3878a 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple2_Test.java
@@ -1,40 +1,44 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.rest;
-
-/**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
- */
-public class MessageBundleLocation {
-
-       final Class<?> baseClass;
-       final String bundlePath;
-
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
-       }
-}
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.Assert.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple2_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple2<String,Integer> x = Tuple2.of("foo",1);
+               assertString(x.getA()).is("foo");
+               assertInteger(x.getB()).is(1);
+       }
+
+       @Test
+       public void a02_equality() throws Exception {
+               Tuple2<String,Integer> x1 = Tuple2.of("foo",1), x2 = 
Tuple2.of("foo",1), x3 = Tuple2.of(null,1), x4 = Tuple2.of("foo",null);
+               assertTrue(x1.equals(x2));
+               assertEquals(x1.hashCode(), x2.hashCode());
+               assertFalse(x1.equals(x3));
+               assertNotEquals(x1.hashCode(), x3.hashCode());
+               assertFalse(x1.equals(x4));
+               assertNotEquals(x1.hashCode(), x4.hashCode());
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple3Function_Test.java
similarity index 69%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple3Function_Test.java
index df16803..7e06aca 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple3Function_Test.java
@@ -1,40 +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.rest;
-
-/**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
- */
-public class MessageBundleLocation {
-
-       final Class<?> baseClass;
-       final String bundlePath;
-
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
-       }
-}
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple3Function_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple3Function<Integer,Integer,Integer,Integer> x = 
(a,b,c)->a+b+c;
+               assertInteger(x.apply(1,2,3)).is(6);
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple3_Test.java
similarity index 53%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple3_Test.java
index df16803..dc8ce43 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple3_Test.java
@@ -1,40 +1,47 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.rest;
-
-/**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
- */
-public class MessageBundleLocation {
-
-       final Class<?> baseClass;
-       final String bundlePath;
-
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
-       }
-}
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.Assert.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple3_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple3<String,Integer,Integer> x = Tuple3.of("foo",1,2);
+               assertString(x.getA()).is("foo");
+               assertInteger(x.getB()).is(1);
+               assertInteger(x.getC()).is(2);
+       }
+
+       @Test
+       public void a02_equality() throws Exception {
+               Tuple3<String,Integer,Integer> x1 = Tuple3.of("foo",1,2), x2 = 
Tuple3.of("foo",1,2), x3 = Tuple3.of(null,1,2), x4 = Tuple3.of("foo",null,2), 
x5 = Tuple3.of("foo",1,null);
+               assertTrue(x1.equals(x2));
+               assertEquals(x1.hashCode(), x2.hashCode());
+               assertFalse(x1.equals(x3));
+               assertNotEquals(x1.hashCode(), x3.hashCode());
+               assertFalse(x1.equals(x4));
+               assertNotEquals(x1.hashCode(), x4.hashCode());
+               assertFalse(x1.equals(x5));
+               assertNotEquals(x1.hashCode(), x5.hashCode());
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple4Function_Test.java
similarity index 69%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple4Function_Test.java
index df16803..81e203d 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple4Function_Test.java
@@ -1,40 +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.rest;
-
-/**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
- */
-public class MessageBundleLocation {
-
-       final Class<?> baseClass;
-       final String bundlePath;
-
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
-       }
-}
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple4Function_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple4Function<Integer,Integer,Integer,Integer,Integer> x = 
(a,b,c,d)->a+b+c+d;
+               assertInteger(x.apply(1,2,3,4)).is(10);
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple4_Test.java
similarity index 50%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple4_Test.java
index df16803..227e1dd 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple4_Test.java
@@ -1,40 +1,50 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.rest;
-
-/**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
- */
-public class MessageBundleLocation {
-
-       final Class<?> baseClass;
-       final String bundlePath;
-
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
-       }
-}
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.Assert.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple4_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple4<String,Integer,Integer,Integer> x = 
Tuple4.of("foo",1,2,3);
+               assertString(x.getA()).is("foo");
+               assertInteger(x.getB()).is(1);
+               assertInteger(x.getC()).is(2);
+               assertInteger(x.getD()).is(3);
+       }
+
+       @Test
+       public void a02_equality() throws Exception {
+               Tuple4<String,Integer,Integer,Integer> x1 = 
Tuple4.of("foo",1,2,3), x2 = Tuple4.of("foo",1,2,3), x3 = 
Tuple4.of(null,1,2,3), x4 = Tuple4.of("foo",null,2,3), x5 = 
Tuple4.of("foo",1,null,3), x6 = Tuple4.of("foo",1,2,null);
+               assertTrue(x1.equals(x2));
+               assertEquals(x1.hashCode(), x2.hashCode());
+               assertFalse(x1.equals(x3));
+               assertNotEquals(x1.hashCode(), x3.hashCode());
+               assertFalse(x1.equals(x4));
+               assertNotEquals(x1.hashCode(), x4.hashCode());
+               assertFalse(x1.equals(x5));
+               assertNotEquals(x1.hashCode(), x5.hashCode());
+               assertFalse(x1.equals(x6));
+               assertNotEquals(x1.hashCode(), x6.hashCode());
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple5Function_Test.java
similarity index 68%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple5Function_Test.java
index df16803..e709d39 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple5Function_Test.java
@@ -1,40 +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.rest;
-
-/**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
- */
-public class MessageBundleLocation {
-
-       final Class<?> baseClass;
-       final String bundlePath;
-
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
-       }
-}
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple5Function_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple5Function<Integer,Integer,Integer,Integer,Integer,Integer> 
x = (a,b,c,d,e)->a+b+c+d+e;
+               assertInteger(x.apply(1,2,3,4,5)).is(15);
+       }
+}
diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple5_Test.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple5_Test.java
new file mode 100644
index 0000000..5801e86
--- /dev/null
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/Tuple5_Test.java
@@ -0,0 +1,53 @@
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.Assert.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Tuple5_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//------------------------------------------------------------------------------------------------------------------
+       @Test
+       public void a01_basic() throws Exception {
+               Tuple5<String,Integer,Integer,Integer,Integer> x = 
Tuple5.of("foo",1,2,3,4);
+               assertString(x.getA()).is("foo");
+               assertInteger(x.getB()).is(1);
+               assertInteger(x.getC()).is(2);
+               assertInteger(x.getD()).is(3);
+               assertInteger(x.getE()).is(4);
+       }
+
+       @Test
+       public void a02_equality() throws Exception {
+               Tuple5<String,Integer,Integer,Integer,Integer> x1 = 
Tuple5.of("foo",1,2,3,4), x2 = Tuple5.of("foo",1,2,3,4), x3 = 
Tuple5.of(null,1,2,3,4), x4 = Tuple5.of("foo",null,2,3,4), x5 = 
Tuple5.of("foo",1,null,3,4), x6 = Tuple5.of("foo",1,2,null,4), x7 = 
Tuple5.of("foo",1,2,3,null);
+               assertTrue(x1.equals(x2));
+               assertEquals(x1.hashCode(), x2.hashCode());
+               assertFalse(x1.equals(x3));
+               assertNotEquals(x1.hashCode(), x3.hashCode());
+               assertFalse(x1.equals(x4));
+               assertNotEquals(x1.hashCode(), x4.hashCode());
+               assertFalse(x1.equals(x5));
+               assertNotEquals(x1.hashCode(), x5.hashCode());
+               assertFalse(x1.equals(x6));
+               assertNotEquals(x1.hashCode(), x6.hashCode());
+               assertFalse(x1.equals(x7));
+               assertNotEquals(x1.hashCode(), x7.hashCode());
+       }
+}
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 7a318a0..8c9dea1 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
@@ -430,7 +430,7 @@ public final class BeanPropertyMeta {
                this.canWrite = b.canWrite;
                this.readOnly = b.readOnly;
                this.writeOnly = b.writeOnly;
-               this.hashCode = 
HashCode.create().add(beanMeta.hashCode()).add(name == null ? 0 : 
name.hashCode()).get();
+               this.hashCode = HashCode.of(beanMeta,name);
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/HashCode.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/HashCode.java
index 1e83c40..d298556 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/HashCode.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/HashCode.java
@@ -35,6 +35,19 @@ public class HashCode {
        }
 
        /**
+        * Calculates a hash code over the specified objects.
+        *
+        * @param objects The objects to calculate a hashcode over.
+        * @return A numerical hashcode value.
+        */
+       public static final int of(Object...objects) {
+               HashCode x = create();
+               for (Object oo : objects)
+                       x.add(oo);
+               return x.get();
+       }
+
+       /**
         * Hashes the hashcode of the specified object into this object.
         *
         * @param o The object whose hashcode will be hashed with this object.
@@ -42,7 +55,7 @@ public class HashCode {
         */
        public HashCode add(Object o) {
                o = unswap(o);
-               add(o == null ? 1 : o.hashCode());
+               add(o == null ? 0 : o.hashCode());
                return this;
        }
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple2.java
similarity index 57%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple2.java
index df16803..08e6b30 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple2.java
@@ -10,31 +10,72 @@
 // * "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;
+package org.apache.juneau.utils;
+
+import static org.apache.juneau.internal.ObjectUtils.*;
+
+import org.apache.juneau.internal.*;
 
 /**
- * Message bundle location.
- *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
+ * Represents a simple tuple of 2 objects.
  *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
  */
-public class MessageBundleLocation {
+public class Tuple2<A,B> {
 
-       final Class<?> baseClass;
-       final String bundlePath;
+       /**
+        * Creator.
+        *
+        * @param <A> Object 1 type.
+        * @param <B> Object 2 type.
+        * @param a Object 1.
+        * @param b Object 2.
+        * @return A new tuple object.
+        */
+       public static <A,B> Tuple2<A,B> of(A a, B b) {
+               return new Tuple2<>(a,b);
+       }
+
+       private final A a;
+       private final B b;
 
        /**
         * Constructor.
         *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
+        * @param a Object 1.
+        * @param b Object 2.
+        */
+       public Tuple2(A a, B b) {
+               this.a = a;
+               this.b = b;
+       }
+
+       /**
+        * Returns the first object in this tuple.
+        *
+        * @return The first object in this tuple.
         */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
+       public A getA() {
+               return a;
+       }
+
+       /**
+        * Returns the second object in this tuple.
+        *
+        * @return The second object in this tuple.
+        */
+       public B getB() {
+               return b;
+       }
+
+       @Override /* Object */
+       public int hashCode() {
+               return HashCode.of(a,b);
+       }
+
+       @Override /* Object */
+       public boolean equals(Object o) {
+               return o instanceof Tuple2 && eq(this, (Tuple2<?,?>)o, 
(x,y)->eq(x.a,y.a) && eq(x.b,y.b));
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple2Function.java
similarity index 67%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple2Function.java
index df16803..21a6786 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple2Function.java
@@ -10,31 +10,34 @@
 // * "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;
+package org.apache.juneau.utils;
+
+import java.util.function.*;
 
 /**
- * Message bundle location.
+ * Allows you to perform a function against 2 objects.
  *
  * <p>
- * Identifies a message bundle by a base class and bundle path.
+ * Same as {@link BiFunction}.
+ *
+ * <p class='bcode w800'>
+ *     Tuple2Function&lt;A,B,R&gt; <jv>x</jv> = (<jv>a</jv>,<jv>b</jv>) -> 
<jsm>doSomething</jsm>(<jv>a</jv>,<jv>b</jv>);
+ *
+ *     R <jv>result</jv> = <jv>x</jv>.apply(<jv>xa</jv>,<jv>xb</jv>);
+ * </p>
  *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
+ * @param <R> Result type.
  */
-public class MessageBundleLocation {
+@FunctionalInterface
+public interface Tuple2Function<A,B,R> {
 
-       final Class<?> baseClass;
-       final String bundlePath;
+       @SuppressWarnings("javadoc")
+       R apply(A a, B b);
 
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
+       @SuppressWarnings("javadoc")
+       default <V> Tuple2Function<A,B,V> andThen(Function<? super R, ? extends 
V> after) {
+               return (A a, B b) -> after.apply(apply(a, b));
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple3.java
similarity index 51%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple3.java
index df16803..110d565 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple3.java
@@ -10,31 +10,87 @@
 // * "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;
+package org.apache.juneau.utils;
+
+import static org.apache.juneau.internal.ObjectUtils.*;
+
+import org.apache.juneau.internal.*;
 
 /**
- * Message bundle location.
+ * Represents a simple tuple of 3 objects.
  *
- * <p>
- * Identifies a message bundle by a base class and bundle path.
- *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
+ * @param <C> Object 3 type.
  */
-public class MessageBundleLocation {
+public class Tuple3<A,B,C> {
+
+       /**
+        * Creator.
+        *
+        * @param <A> Object 1 type.
+        * @param <B> Object 2 type.
+        * @param <C> Object 3 type.
+        * @param a Object 1.
+        * @param b Object 2.
+        * @param c Object 3.
+        * @return A new tuple object.
+        */
+       public static <A,B,C> Tuple3<A,B,C> of(A a, B b, C c) {
+               return new Tuple3<>(a,b,c);
+       }
 
-       final Class<?> baseClass;
-       final String bundlePath;
+       private final A a;
+       private final B b;
+       private final C c;
 
        /**
         * Constructor.
         *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
+        * @param a Object 1.
+        * @param b Object 2.
+        * @param c Object 3.
         */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
+       public Tuple3(A a, B b, C c) {
+               this.a = a;
+               this.b = b;
+               this.c = c;
+       }
+
+       /**
+        * Returns the first object in this tuple.
+        *
+        * @return The first object in this tuple.
+        */
+       public A getA() {
+               return a;
+       }
+
+       /**
+        * Returns the second object in this tuple.
+        *
+        * @return The second object in this tuple.
+        */
+       public B getB() {
+               return b;
+       }
+
+       /**
+        * Returns the third object in this tuple.
+        *
+        * @return The third object in this tuple.
+        */
+       public C getC() {
+               return c;
+       }
+
+       @Override /* Object */
+       public int hashCode() {
+               return HashCode.of(a,b,c);
+       }
+
+       @Override /* Object */
+       public boolean equals(Object o) {
+               return o instanceof Tuple3 && eq(this, (Tuple3<?,?,?>)o, 
(x,y)->eq(x.a,y.a) && eq(x.b,y.b) && eq(x.c,y.c));
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple3Function.java
similarity index 64%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple3Function.java
index df16803..9ec8b59 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple3Function.java
@@ -10,31 +10,35 @@
 // * "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;
+package org.apache.juneau.utils;
+
+import java.util.function.*;
 
 /**
- * Message bundle location.
+ * Allows you to perform a function against 3 objects.
  *
  * <p>
- * Identifies a message bundle by a base class and bundle path.
+ * Similar to {@link BiFunction} except for 3 parameters.
+ *
+ * <p class='bcode w800'>
+ *     Tuple3Function&lt;A,B,C,R&gt; <jv>x</jv> = 
(<jv>a</jv>,<jv>b</jv>,<jv>c</jv>) -> 
<jsm>doSomething</jsm>(<jv>a</jv>,<jv>b</jv>,<jv>c</jv>);
+ *
+ *     R <jv>result</jv> = 
<jv>x</jv>.apply(<jv>xa</jv>,<jv>xb</jv>,<jv>xc</jv>);
+ * </p>
  *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
+ * @param <C> Object 3 type.
+ * @param <R> Result type.
  */
-public class MessageBundleLocation {
+@FunctionalInterface
+public interface Tuple3Function<A,B,C,R> {
 
-       final Class<?> baseClass;
-       final String bundlePath;
+       @SuppressWarnings("javadoc")
+       R apply(A a, B b, C c);
 
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
+       @SuppressWarnings("javadoc")
+       default <V> Tuple3Function<A,B,C,V> andThen(Function<? super R, ? 
extends V> after) {
+               return (A a, B b, C c) -> after.apply(apply(a, b, c));
        }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple4.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple4.java
new file mode 100644
index 0000000..920bf2f
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple4.java
@@ -0,0 +1,111 @@
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.internal.ObjectUtils.*;
+
+import org.apache.juneau.internal.*;
+
+/**
+ * Represents a simple tuple of 4 objects.
+ *
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
+ * @param <C> Object 3 type.
+ * @param <D> Object 4 type.
+ */
+public class Tuple4<A,B,C,D> {
+
+       /**
+        * Creator.
+        *
+        * @param <A> Object 1 type.
+        * @param <B> Object 2 type.
+        * @param <C> Object 3 type.
+        * @param <D> Object 4 type.
+        * @param a Object 1.
+        * @param b Object 2.
+        * @param c Object 3.
+        * @param d Object 4.
+        * @return A new tuple object.
+        */
+       public static <A,B,C,D> Tuple4<A,B,C,D> of(A a, B b, C c, D d) {
+               return new Tuple4<>(a,b,c,d);
+       }
+
+       private final A a;
+       private final B b;
+       private final C c;
+       private final D d;
+
+       /**
+        * Constructor.
+        *
+        * @param a Object 1.
+        * @param b Object 2.
+        * @param c Object 3.
+        * @param d Object 4.
+        */
+       public Tuple4(A a, B b, C c, D d) {
+               this.a = a;
+               this.b = b;
+               this.c = c;
+               this.d = d;
+       }
+
+       /**
+        * Returns the first object in this tuple.
+        *
+        * @return The first object in this tuple.
+        */
+       public A getA() {
+               return a;
+       }
+
+       /**
+        * Returns the second object in this tuple.
+        *
+        * @return The second object in this tuple.
+        */
+       public B getB() {
+               return b;
+       }
+
+       /**
+        * Returns the third object in this tuple.
+        *
+        * @return The third object in this tuple.
+        */
+       public C getC() {
+               return c;
+       }
+
+       /**
+        * Returns the fourth object in this tuple.
+        *
+        * @return The fourth object in this tuple.
+        */
+       public D getD() {
+               return d;
+       }
+
+       @Override /* Object */
+       public int hashCode() {
+               return HashCode.of(a,b,c,d);
+       }
+
+       @Override /* Object */
+       public boolean equals(Object o) {
+               return o instanceof Tuple4 && eq(this, (Tuple4<?,?,?,?>)o, 
(x,y)->eq(x.a,y.a) && eq(x.b,y.b) && eq(x.c,y.c) && eq(x.d,y.d));
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple4Function.java
similarity index 62%
copy from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple4Function.java
index df16803..e641ad1 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple4Function.java
@@ -10,31 +10,36 @@
 // * "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;
+package org.apache.juneau.utils;
+
+import java.util.function.*;
 
 /**
- * Message bundle location.
+ * Allows you to perform a function against 4 objects.
  *
  * <p>
- * Identifies a message bundle by a base class and bundle path.
+ * Similar to {@link BiFunction} except for 4 parameters.
+ *
+ * <p class='bcode w800'>
+ *     Tuple4Function&lt;A,B,C,D,R&gt; <jv>x</jv> = 
(<jv>a</jv>,<jv>b</jv>,<jv>c</jv>,<jv>d</jv>) -> 
<jsm>doSomething</jsm>(<jv>a</jv>,<jv>b</jv>,<jv>c</jv>,<jv>d</jv>);
+ *
+ *     R <jv>result</jv> = 
<jv>x</jv>.apply(<jv>xa</jv>,<jv>xb</jv>,<jv>xc</jv>,<jv>xd</jv>);
+ * </p>
  *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
+ * @param <C> Object 3 type.
+ * @param <D> Object 4 type.
+ * @param <R> Result type.
  */
-public class MessageBundleLocation {
+@FunctionalInterface
+public interface Tuple4Function<A,B,C,D,R> {
 
-       final Class<?> baseClass;
-       final String bundlePath;
+       @SuppressWarnings("javadoc")
+       R apply(A a, B b, C c, D d);
 
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
+       @SuppressWarnings("javadoc")
+       default <V> Tuple4Function<A,B,C,D,V> andThen(Function<? super R, ? 
extends V> after) {
+               return (A a, B b, C c, D d) -> after.apply(apply(a, b, c, d));
        }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple5.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple5.java
new file mode 100644
index 0000000..f5528f0
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple5.java
@@ -0,0 +1,126 @@
+// 
***************************************************************************************************************************
+// * 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.utils;
+
+import static org.apache.juneau.internal.ObjectUtils.*;
+
+import org.apache.juneau.internal.*;
+
+/**
+ * Represents a simple tuple of 5 objects.
+ *
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
+ * @param <C> Object 3 type.
+ * @param <D> Object 4 type.
+ * @param <E> Object 5 type.
+ */
+public class Tuple5<A,B,C,D,E> {
+
+       /**
+        * Creator.
+        *
+        * @param <A> Object 1 type.
+        * @param <B> Object 2 type.
+        * @param <C> Object 3 type.
+        * @param <D> Object 4 type.
+        * @param <E> Object 5 type.
+        * @param a Object 1.
+        * @param b Object 2.
+        * @param c Object 3.
+        * @param d Object 4.
+        * @param e Object 5.
+        * @return A new tuple object.
+        */
+       public static <A,B,C,D,E> Tuple5<A,B,C,D,E> of(A a, B b, C c, D d, E e) 
{
+               return new Tuple5<>(a,b,c,d, e);
+       }
+
+       private final A a;
+       private final B b;
+       private final C c;
+       private final D d;
+       private final E e;
+
+       /**
+        * Constructor.
+        *
+        * @param a Object 1.
+        * @param b Object 2.
+        * @param c Object 3.
+        * @param d Object 4.
+        * @param e Object 5.
+        */
+       public Tuple5(A a, B b, C c, D d, E e) {
+               this.a = a;
+               this.b = b;
+               this.c = c;
+               this.d = d;
+               this.e = e;
+       }
+
+       /**
+        * Returns the first object in this tuple.
+        *
+        * @return The first object in this tuple.
+        */
+       public A getA() {
+               return a;
+       }
+
+       /**
+        * Returns the second object in this tuple.
+        *
+        * @return The second object in this tuple.
+        */
+       public B getB() {
+               return b;
+       }
+
+       /**
+        * Returns the third object in this tuple.
+        *
+        * @return The third object in this tuple.
+        */
+       public C getC() {
+               return c;
+       }
+
+       /**
+        * Returns the fourth object in this tuple.
+        *
+        * @return The fourth object in this tuple.
+        */
+       public D getD() {
+               return d;
+       }
+
+       /**
+        * Returns the fifth object in this tuple.
+        *
+        * @return The fifth object in this tuple.
+        */
+       public E getE() {
+               return e;
+       }
+
+       @Override /* Object */
+       public int hashCode() {
+               return HashCode.of(a,b,c,d,e);
+       }
+
+       @Override /* Object */
+       public boolean equals(Object o) {
+               return o instanceof Tuple5 && eq(this, (Tuple5<?,?,?,?,?>)o, 
(x,y)->eq(x.a,y.a) && eq(x.b,y.b) && eq(x.c,y.c) && eq(x.d,y.d) && eq(x.e,y.e));
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple5Function.java
similarity index 60%
rename from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
rename to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple5Function.java
index df16803..7def989 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/MessageBundleLocation.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/Tuple5Function.java
@@ -10,31 +10,37 @@
 // * "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;
+package org.apache.juneau.utils;
+
+import java.util.function.*;
 
 /**
- * Message bundle location.
+ * Allows you to perform a function against 5 objects.
  *
  * <p>
- * Identifies a message bundle by a base class and bundle path.
+ * Similar to {@link BiFunction} except for 5 parameters.
+ *
+ * <p class='bcode w800'>
+ *     Tuple5Function&lt;A,B,C,D,E,R&gt; <jv>x</jv> = 
(<jv>a</jv>,<jv>b</jv>,<jv>c</jv>,<jv>d</jv>,<jv>e</jv>) -> 
<jsm>doSomething</jsm>(<jv>a</jv>,<jv>b</jv>,<jv>c</jv>,<jv>d</jv>,<jv>e</jv>);
+ *
+ *     R <jv>result</jv> = 
<jv>x</jv>.apply(<jv>xa</jv>,<jv>xb</jv>,<jv>xc</jv>,<jv>xd</jv>,<jv>xe</jv>);
+ * </p>
  *
- * <ul class='seealso'>
- *     <li class='link'>{@doc juneau-rest-server.Messages}
- * </ul>
+ * @param <A> Object 1 type.
+ * @param <B> Object 2 type.
+ * @param <C> Object 3 type.
+ * @param <D> Object 4 type.
+ * @param <E> Object 5 type.
+ * @param <R> Result type.
  */
-public class MessageBundleLocation {
+@FunctionalInterface
+public interface Tuple5Function<A,B,C,D,E,R> {
 
-       final Class<?> baseClass;
-       final String bundlePath;
+       @SuppressWarnings("javadoc")
+       R apply(A a, B b, C c, D d, E e);
 
-       /**
-        * Constructor.
-        *
-        * @param baseClass The base class that the bundle path is relative to.
-        * @param bundlePath The bundle path relative to the base class.
-        */
-       public MessageBundleLocation(Class<?> baseClass, String bundlePath) {
-               this.baseClass = baseClass;
-               this.bundlePath = bundlePath;
+       @SuppressWarnings("javadoc")
+       default <V> Tuple5Function<A,B,C,D,E,V> andThen(Function<? super R, ? 
extends V> after) {
+               return (A a, B b, C c, D d, E e) -> after.apply(apply(a, b, c, 
d, e));
        }
 }
diff --git a/juneau-doc/docs/ReleaseNotes/8.1.4.html 
b/juneau-doc/docs/ReleaseNotes/8.1.4.html
index cc72ad5..d0ac1a9 100644
--- a/juneau-doc/docs/ReleaseNotes/8.1.4.html
+++ b/juneau-doc/docs/ReleaseNotes/8.1.4.html
@@ -446,6 +446,8 @@
                String getFoo();  <jc>// @RestMethod(name=GET,path="/foo") is 
implied.</jc>
        }
                </p>
+       <li>
+               Improved {@link oajr.annotation.RestMethod#REST_messages 
REST_messages} support (mostly bug fixes).
 </ul>
 
 <h5 class='topic w800'>juneau-rest-server-springboot</h5>
diff --git a/juneau-doc/docs/Topics/06.juneau-rest-server/22.Messages.html 
b/juneau-doc/docs/Topics/06.juneau-rest-server/22.Messages.html
index bd2898a..cf3c215 100644
--- a/juneau-doc/docs/Topics/06.juneau-rest-server/22.Messages.html
+++ b/juneau-doc/docs/Topics/06.juneau-rest-server/22.Messages.html
@@ -13,49 +13,97 @@
  
***************************************************************************************************************************/
  -->
 
+{8.1.4-updated} 
 Messages
 
 <p>
-       The {@link oajr.annotation.Rest#messages @Rest(messages)} annotation is 
used to associate a resource bundle with a servlet class.
+       The {@link oajr.annotation.Rest#messages @Rest(messages)} annotation 
identifies the location of the resource bundle 
+       for a <ja>@Rest</ja>-annotated class if it's different from the class 
name.
 </p>
-<p class='bpcode w800'>
-       <jc>// Servlet with associated resource bundle</jc>
-       <ja>@Rest</ja>(messages=<js>"nls/MyMessages"</js>)
-       <jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
-
-               <jc>// Returns the localized greeting from the "greeting" key 
in MyMessages.properties</jc>
-               <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
-               <jk>public</jk> String printLocalizedGreeting(RestRequest req) {
-                       <jk>return</jk> req.getMessage(<js>"greeting"</js>);
-               }
+<p>
+       By default, the resource bundle name is assumed to match the class 
name.  For example, given the class
+       <c>MyClass.java</c>, the resource bundle is assumed to be 
<c>MyClass.properties</c>.  This property
+       allows you to override this setting to specify a different location 
such as <c>MyMessages.properties</c> by
+       specifying a value of <js>"MyMessages"</js>.
 </p>
-<p>    
-       The resource bundle can also be passed into the method by simply 
specifying a parameter
-       of type {@link java.util.ResourceBundle} or {@link 
oaj.utils.MessageBundle}:
+<p>
+Resource bundles are searched using the following base name patterns:
 </p>
-<p class='bpcode w800'>
-       <ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
-       <jk>public</jk> String printLocalizedGreeting(MessageBundle messages) {
-               <jk>return</jk> messages.getString(<js>"greeting"</js>);
-       }
+<ul>
+       <li><js>"{package}.{name}"</js>
+       <li><js>"{package}.i18n.{name}"</js>
+       <li><js>"{package}.nls.{name}"</js>
+       <li><js>"{package}.messages.{name}"</js>
+</ul>
+
+<p>
+       This annotation is used to provide request-localized (based on 
<c>Accept-Language</c>) messages for the following methods:
+</p>
+<ul class='javatree'>
+       <li class='jm'>{@link RestRequest#getMessage(String, Object...)}
+       <li class='jm'>{@link RestContext#getMessages() 
RestContext.getMessages()}
+</ul>
+
+<p>
+       Request-localized messages are also available by passing either of the 
following parameter types into your Java method:
 </p>
+<ul class='javatree'>
+       <li class='jc'>{@link ResourceBundle} - Basic Java resource bundle.
+       <li class='jc'>{@link Messages} - Extended resource bundle with several 
convenience methods.
+</ul>
 <p>
-       If a resource bundle is shared by multiple servlets, the label and 
description can be prefixed by the class 
-       name:
+       The value can be a relative path like <js>"nls/Messages"</js>, 
indicating to look for the resource bundle
+       <js>"com.foo.sample.nls.Messages"</js> if the resource class is in 
<js>"com.foo.sample"</js>, or it can be an
+       absolute path like <js>"com.foo.sample.nls.Messages"</js>
 </p>
+
+<h5 class='figure'>Examples:</h5>
 <p class='bpcode w800'>
        
<cc>#--------------------------------------------------------------------------------
-       # Contents of MyMessages.properties
+       # Contents of org/apache/foo/nls/MyMessages.properties
        
#--------------------------------------------------------------------------------</cc>
-       <ck>greeting</ck> = Hello!
-</p>           
+       <ck>HelloMessage</ck> = <cv>Hello {0}!</cv>
+</p>
+<p class='bpcode w800'>
+       <jc>// Contents of org/apache/foo/MyResource.java</jc>
+
+       <ja>@Rest</ja>(messages=<js>"nls/MyMessages"</js>)
+       <jk>public class</jk> MyResource {...}
+
+               <ja>@RestMethod</ja>(name=<js>"GET"</js>, 
path=<js>"/hello/{you}"</js>)
+               <jk>public</jk> Object helloYou(RestRequest <jv>req</jv>, 
Messages <jv>messages</jv>, <ja>@Path</ja>(<js>"name"</js>) String 
<jv>you</jv>) {
+                       String <jv>s</jv>;
+
+                       <jc>// Get it from the RestRequest object.</jc>
+                       <jv>s</jv> = 
<jv>req</jv>.getMessage(<js>"HelloMessage"</js>, <jv>you</jv>);
+
+                       <jc>// Or get it from the method parameter.</jc>
+                       <jv>s</jv> = 
<jv>messages</jv>.getString(<js>"HelloMessage"</js>, <jv>you</jv>);
+
+                       <jc>// Or get the message in a locale different from 
the request.</jc>
+                       <jv>s</jv> = 
<jv>messages</jv>.forLocale(Locale.<jsf>UK</jsf>).getString(<js>"HelloMessage"</js>,
 <jv>you</jv>);
+
+                       <jk>return</jk> <jv>s</jv>;
+               }
+       }
+</p>
+<p>
+       When using shared resource bundles, keys can be prefixed by class names 
like so and still retrieve by simple
+       key names:
+</p>
 <p class='bpcode w800'>
        
<cc>#--------------------------------------------------------------------------------
-       # Contents of shared MyMessages.properties
+       # Contents of shared org/apache/foo/nls/MyMessages.properties
        
#--------------------------------------------------------------------------------</cc>
-       <ck>MyRestServlet.greeting</ck> = Hello!
+       <ck>MyResource.HelloMessage</ck> = <cv>Hello {0}!</cv>
+</p>
+
+<p>
+       Messages are automatically inherited from super classes.  If a string 
cannot be found in the bundle of the current
+       class, it will be searched for up the class hierarchy.
 </p>
 
 <ul class='seealso'>
+       <li class='jc'>{@link oaj.cp.Messages}
        <li class='jf'>{@link oajr.RestContext#REST_messages}
 </ul>
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
deleted file mode 100644
index 2807fcc..0000000
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestResourceMessagesTest.java
+++ /dev/null
@@ -1,70 +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.rest.annotation;
-
-import static org.junit.runners.MethodSorters.*;
-
-import java.util.*;
-
-import org.apache.juneau.collections.*;
-import org.apache.juneau.rest.mock2.*;
-import org.junit.*;
-
-@FixMethodOrder(NAME_ASCENDING)
-public class RestResourceMessagesTest {
-
-       
//====================================================================================================
-       // Setup
-       
//====================================================================================================
-
-       static OMap convertToMap(ResourceBundle rb) {
-               OMap m = new OMap();
-               for (String k : new TreeSet<>(rb.keySet()))
-                       m.put(k, rb.getString(k));
-               return m;
-       }
-
-       
//====================================================================================================
-       // Basic tests
-       
//====================================================================================================
-
-       @Rest(messages="RestResourceMessagesTest1")
-       public static class A {
-               @RestMethod
-               public OMap a01(ResourceBundle rb) {
-                       return convertToMap(rb);
-               }
-       }
-       static MockRestClient a = MockRestClient.build(A.class);
-
-       @Test
-       public void a01() throws Exception {
-               // Parent resource should just pick up values from its bundle.
-               
a.get("/a01").run().assertBody().is("{key1:'value1a',key2:'value2a'}");
-       }
-
-       
//====================================================================================================
-       // Overridden on subclass.
-       
//====================================================================================================
-
-       @Rest(messages="RestResourceMessagesTest2")
-       public static class B extends A {}
-       static MockRestClient b = MockRestClient.build(B.class);
-
-       @Test
-       public void b01() throws Exception {
-               // Child resource should pick up values from both parent and 
child,
-               // ordered child before parent.
-               
b.get("/a01").run().assertBody().is("{key1:'value1a',key2:'value2b',key3:'value3b'}");
-       }
-}
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Messages_Test.java
 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Messages_Test.java
new file mode 100644
index 0000000..2157af2
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Messages_Test.java
@@ -0,0 +1,126 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest.annotation;
+
+import static org.junit.runners.MethodSorters.*;
+
+import java.util.*;
+
+import org.apache.juneau.collections.*;
+import org.apache.juneau.cp.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.rest.mock2.*;
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class Rest_Messages_Test {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Basic tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Rest
+       public static class A1 {
+               @RestMethod
+               public OMap a(ResourceBundle rb) {
+                       return asMap(rb);
+               }
+               @RestMethod
+               public OMap b(Messages m) {
+                       return asMap(m);
+               }
+               @RestMethod
+               public String c(Messages m, @Query("name") String name) {
+                       return m.getString(name);
+               }
+       }
+       static MockRestClient a1 = MockRestClient.build(A1.class);
+
+       @Test
+       public void a01_default() throws Exception {
+               
a1.get("/a").run().assertBody().is("{'A1.key2':'A1.value2a',key1:'value1a',key2:'A1.value2a'}");
+               
a1.get("/b").run().assertBody().is("{'A1.key2':'A1.value2a',key1:'value1a',key2:'A1.value2a'}");
+               a1.get("/c?name=key1").run().assertBody().is("value1a");
+               a1.get("/c?name=key2").run().assertBody().is("A1.value2a");
+               a1.get("/c?name=key3").run().assertBody().is("{!key3}");
+       }
+
+       @Rest
+       public static class A2 extends A1 {}
+       static MockRestClient a2 = MockRestClient.build(A2.class);
+
+       @Test
+       public void a02_subclassed() throws Exception {
+               
a2.get("/a").run().assertBody().is("{'A1.key2':'A1.value2a','A2.key3':'A2.value3b',key1:'value1a',key2:'value2b',key3:'A2.value3b'}");
+               
a2.get("/b").run().assertBody().is("{'A1.key2':'A1.value2a','A2.key3':'A2.value3b',key1:'value1a',key2:'value2b',key3:'A2.value3b'}");
+               a2.get("/c?name=key1").run().assertBody().is("value1a");
+               a2.get("/c?name=key2").run().assertBody().is("value2b");
+               a2.get("/c?name=key3").run().assertBody().is("A2.value3b");
+               a2.get("/c?name=key4").run().assertBody().is("{!key4}");
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Overridden on subclass.
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Rest(messages="B1x")
+       public static class B1 {
+               @RestMethod
+               public OMap a(ResourceBundle rb) {
+                       return asMap(rb);
+               }
+               @RestMethod
+               public OMap b(Messages m) {
+                       return asMap(m);
+               }
+               @RestMethod
+               public String c(Messages m, @Query("name") String name) {
+                       return m.getString(name);
+               }
+       }
+       static MockRestClient b1 = MockRestClient.build(B1.class);
+
+       @Test
+       public void b01_customName() throws Exception {
+               
b1.get("/a").run().assertBody().is("{'B1.key2':'B1.value2a',key1:'value1a',key2:'B1.value2a'}");
+               
b1.get("/b").run().assertBody().is("{'B1.key2':'B1.value2a',key1:'value1a',key2:'B1.value2a'}");
+               b1.get("/c?name=key1").run().assertBody().is("value1a");
+               b1.get("/c?name=key2").run().assertBody().is("B1.value2a");
+               b1.get("/c?name=key3").run().assertBody().is("{!key3}");
+       }
+
+       @Rest(messages="B2x")
+       public static class B2 extends B1 {}
+       static MockRestClient b2 = MockRestClient.build(B2.class);
+
+       @Test
+       public void b02_subclassed_customName() throws Exception {
+               
b2.get("/a").run().assertBody().stderr().is("{'B1.key2':'B1.value2a','B2.key3':'B2.value3b',key1:'value1a',key2:'value2b',key3:'B2.value3b'}");
+               
b2.get("/b").run().assertBody().is("{'B1.key2':'B1.value2a','B2.key3':'B2.value3b',key1:'value1a',key2:'value2b',key3:'B2.value3b'}");
+               b2.get("/c?name=key1").run().assertBody().is("value1a");
+               b2.get("/c?name=key2").run().assertBody().is("value2b");
+               b2.get("/c?name=key3").run().assertBody().is("B2.value3b");
+               b2.get("/c?name=key4").run().assertBody().is("{!key4}");
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Helper methods.
+       
//------------------------------------------------------------------------------------------------------------------
+
+       private static OMap asMap(ResourceBundle rb) {
+               OMap m = new OMap();
+               for (String k : new TreeSet<>(rb.keySet()))
+                       m.put(k, rb.getString(k));
+               return m;
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/A1.properties
similarity index 97%
copy from 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
copy to 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/A1.properties
index d107ee8..f8077ed 100644
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/A1.properties
@@ -13,4 +13,4 @@
 # 
***************************************************************************************************************************
 
 key1 = value1a
-key2 = value2a
\ No newline at end of file
+A1.key2 = A1.value2a
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/A2.properties
similarity index 97%
copy from 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
copy to 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/A2.properties
index 9a5fe73..505513c 100644
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/A2.properties
@@ -13,4 +13,4 @@
 # 
***************************************************************************************************************************
 
 key2 = value2b
-key3 = value3b
\ No newline at end of file
+A2.key3 = A2.value3b
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/B1x.properties
similarity index 97%
rename from 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
rename to 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/B1x.properties
index d107ee8..a4b7aae 100644
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest1.properties
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/B1x.properties
@@ -13,4 +13,4 @@
 # 
***************************************************************************************************************************
 
 key1 = value1a
-key2 = value2a
\ No newline at end of file
+B1.key2 = B1.value2a
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/B2x.properties
similarity index 97%
rename from 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
rename to 
juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/B2x.properties
index 9a5fe73..12b31a1 100644
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/RestResourceMessagesTest2.properties
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/resources/org/apache/juneau/rest/annotation/B2x.properties
@@ -13,4 +13,4 @@
 # 
***************************************************************************************************************************
 
 key2 = value2b
-key3 = value3b
\ No newline at end of file
+B2.key3 = B2.value3b
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 fefad04..03312dd 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
@@ -14,6 +14,7 @@ package org.apache.juneau.rest;
 
 import static javax.servlet.http.HttpServletResponse.*;
 import static org.apache.juneau.internal.CollectionUtils.*;
+import static org.apache.juneau.internal.ObjectUtils.*;
 import static org.apache.juneau.internal.IOUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.rest.util.RestUtils.*;
@@ -1554,7 +1555,7 @@ public final class RestContext extends BeanContext {
         * <ul class='spaced-list'>
         *      <li><b>ID:</b>  {@link 
org.apache.juneau.rest.RestContext#REST_messages REST_messages}
         *      <li><b>Name:</b>  <js>"RestContext.messages.lo"</js>
-        *      <li><b>Data type:</b>  <c>List&lt;{@link 
org.apache.juneau.rest.MessageBundleLocation}&gt;</c>
+        *      <li><b>Data type:</b>  <c>List&lt;{@link 
org.apache.juneau.utils.Tuple2}&lt;Class,String&gt;&gt;</c>
         *      <li><b>Default:</b>  <jk>null</jk>
         *      <li><b>Session property:</b>  <jk>false</jk>
         *      <li><b>Annotations:</b>
@@ -1564,59 +1565,72 @@ public final class RestContext extends BeanContext {
         *      <li><b>Methods:</b>
         *              <ul>
         *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#messages(String)},
-        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#messages(Class,String)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#messages(MessageBundleLocation...)}
         *              </ul>
         * </ul>
         *
         * <h5 class='section'>Description:</h5>
         * <p>
-        * Identifies the location of the resource bundle for this class.
+        * Identifies the location of the resource bundle for this class if 
it's different from the class name.
         *
         * <p>
-        * This annotation is used to provide localized messages for the 
following methods:
+        * By default, the resource bundle name is assumed to match the class 
name.  For example, given the class
+        * <c>MyClass.java</c>, the resource bundle is assumed to be 
<c>MyClass.properties</c>.  This property
+        * allows you to override this setting to specify a different location 
such as <c>MyMessages.properties</c> by
+        * specifying a value of <js>"MyMessages"</js>.
+        *
+        * <p>
+        *      Resource bundles are searched using the following base name 
patterns:
+        *      <ul>
+        *              <li><js>"{package}.{name}"</js>
+        *              <li><js>"{package}.i18n.{name}"</js>
+        *              <li><js>"{package}.nls.{name}"</js>
+        *              <li><js>"{package}.messages.{name}"</js>
+        *      </ul>
+        *
+        * <p>
+        * This annotation is used to provide request-localized (based on 
<c>Accept-Language</c>) messages for the following methods:
         * <ul class='javatree'>
         *      <li class='jm'>{@link RestRequest#getMessage(String, Object...)}
         *      <li class='jm'>{@link RestContext#getMessages() 
RestContext.getMessages()}
         * </ul>
         *
         * <p>
-        * Messages are also available by passing either of the following 
parameter types into your Java method:
+        * Request-localized messages are also available by passing either of 
the following parameter types into your Java method:
         * <ul class='javatree'>
         *      <li class='jc'>{@link ResourceBundle} - Basic Java resource 
bundle.
         *      <li class='jc'>{@link Messages} - Extended resource bundle with 
several convenience methods.
         * </ul>
         *
-        * <p>
-        * Messages passed into Java methods already have their locale set to 
that of the incoming request.
-        *
-        * <p>
         * The value can be a relative path like <js>"nls/Messages"</js>, 
indicating to look for the resource bundle
         * <js>"com.foo.sample.nls.Messages"</js> if the resource class is in 
<js>"com.foo.sample"</js>, or it can be an
         * absolute path like <js>"com.foo.sample.nls.Messages"</js>
         *
         * <h5 class='section'>Examples:</h5>
         * <p class='bcode w800'>
-        *      <jk>package</jk> org.apache.foo;
+        *      <cc># Contents of org/apache/foo/nls/MyMessages.properties</cc>
+        *
+        *      <ck>HelloMessage</ck> = <cv>Hello {0}!</cv>
+        * </p>
+        * <p class='bcode w800'>
+        *      <jc>// Contents of org/apache/foo/MyResource.java</jc>
         *
-        *      <jc>// Resolve messages to 
org/apache/foo/nls/MyMessages.properties</jc>
         *      <ja>@Rest</ja>(messages=<js>"nls/MyMessages"</js>)
         *      <jk>public class</jk> MyResource {...}
         *
         *              <ja>@RestMethod</ja>(name=<js>"GET"</js>, 
path=<js>"/hello/{you}"</js>)
-        *              <jk>public</jk> Object helloYou(RestRequest req, 
MessageBundle messages, <ja>@Path</ja>(<js>"name"</js>) String you)) {
-        *                      String s;
+        *              <jk>public</jk> Object helloYou(RestRequest 
<jv>req</jv>, Messages <jv>messages</jv>, <ja>@Path</ja>(<js>"name"</js>) 
String <jv>you</jv>) {
+        *                      String <jv>s</jv>;
         *
         *                      <jc>// Get it from the RestRequest object.</jc>
-        *                      s = req.getMessage(<js>"HelloMessage"</js>, 
you);
+        *                      <jv>s</jv> = 
<jv>req</jv>.getMessage(<js>"HelloMessage"</js>, <jv>you</jv>);
         *
         *                      <jc>// Or get it from the method parameter.</jc>
-        *                      s = messages.getString(<js>"HelloMessage"</js>, 
you);
+        *                      <jv>s</jv> = 
<jv>messages</jv>.getString(<js>"HelloMessage"</js>, <jv>you</jv>);
         *
         *                      <jc>// Or get the message in a locale different 
from the request.</jc>
-        *                      s = messages.getString(Locale.<jsf>UK</jsf>, 
<js>"HelloMessage"</js>, you);
+        *                      <jv>s</jv> = 
<jv>messages</jv>.forLocale(Locale.<jsf>UK</jsf>).getString(<js>"HelloMessage"</js>,
 <jv>you</jv>);
         *
-        *                      <jk>return</jk> s;
+        *                      <jk>return</jk> <jv>s</jv>;
         *              }
         *      }
         * </p>
@@ -1627,6 +1641,7 @@ public final class RestContext extends BeanContext {
         * </ul>
         *
         * <ul class='seealso'>
+        *      <li class='jc'>{@link Messages}
         *      <li class='link'>{@doc juneau-rest-server.Messages}
         * </ul>
         */
@@ -3849,16 +3864,11 @@ public final class RestContext extends BeanContext {
                                s.add(sf.getPath());
                        staticFilesPaths = s.toArray(new String[s.size()]);
 
-                       MessageBundleLocation[] mbl = 
getInstanceArrayProperty(REST_messages, MessageBundleLocation.class, new 
MessageBundleLocation[0]);
-                       if (mbl.length == 0)
-                               msgs = Messages.of(rci.inner());
-                       else {
-                               Messages msgs = null;
-                               for (int i = mbl.length-1; i >= 0; i--)
-                                       if (mbl[i] != null)
-                                               msgs = 
Messages.create(mbl[i].baseClass == null ? rci.inner() : 
mbl[i].baseClass).name(mbl[i].bundlePath).parent(msgs).build();
-                               this.msgs = msgs;
-                       }
+                       Tuple2<Class<?>,String>[] mbl = 
getInstanceArrayProperty(REST_messages, Tuple2.class, new Tuple2[0]);
+                       Messages msgs = null;
+                       for (int i = mbl.length-1; i >= 0; i--)
+                               msgs = 
Messages.create(firstNonNull(mbl[i].getA(), 
rci.inner())).name(mbl[i].getB()).parent(msgs).build();
+                       this.msgs = msgs;
 
                        this.fullPath = (builder.parentContext == null ? "" : 
(builder.parentContext.fullPath + '/')) + builder.getPath();
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index 1f443f9..d3ea603 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -46,6 +46,7 @@ import org.apache.juneau.rest.widget.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.svl.*;
 import org.apache.juneau.svl.vars.*;
+import org.apache.juneau.utils.*;
 
 /**
  * Defines the initial configuration of a <c>RestServlet</c> or <c>@Rest</c> 
annotated object.
@@ -1218,28 +1219,6 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
        /**
         * <i><l>RestContext</l> configuration property:&emsp;</i>  Messages.
         *
-        * <p>
-        * Identifies the location of the resource bundle for this class.
-        *
-        * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_messages}
-        * </ul>
-        *
-        * @param values The values to add to this setting.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder messages(MessageBundleLocation...values) {
-               return prependTo(REST_messages, values);
-       }
-
-       /**
-        * <i><l>RestContext</l> configuration property:&emsp;</i>  Messages.
-        *
-        * <p>
-        * Same as {@link #messages(MessageBundleLocation...)} except allows 
you to pass in the base class and bundle
-        * path separately.
-        *
         * <ul class='seealso'>
         *      <li class='jf'>{@link RestContext#REST_messages}
         * </ul>
@@ -1252,7 +1231,7 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
         */
        @FluentSetter
        public RestContextBuilder messages(Class<?> baseClass, String 
bundlePath) {
-               return prependTo(REST_messages, new 
MessageBundleLocation(baseClass, bundlePath));
+               return prependTo(REST_messages, Tuple2.of(baseClass, 
bundlePath));
        }
 
        /**
@@ -1270,7 +1249,7 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
         */
        @FluentSetter
        public RestContextBuilder messages(String bundlePath) {
-               return prependTo(REST_messages, new MessageBundleLocation(null, 
bundlePath));
+               return prependTo(REST_messages, Tuple2.of(null, bundlePath));
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index 8c3990d..79ae60e 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -1226,11 +1226,8 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
         *      <ja>@RestMethod</ja>(...)
         *      <jk>public</jk> String sayHello(RestRequest req, 
<ja>@Query</ja>(<js>"user"</js>) String user) {
         *
-        *              <jc>// Get message bundle.</jc>
-        *              MessageBundle mb = req.getMessageBundle();
-        *
         *              <jc>// Return a localized message.</jc>
-        *              <jk>return</jk> mb.getString(<js>"hello.message"</js>, 
user);
+        *              <jk>return</jk> 
req.getMessages().getString(<js>"hello.message"</js>, user);
         *      }
         * </p>
         *
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
index 9b592a9..74c31a8 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
@@ -32,6 +32,7 @@ import org.apache.juneau.rest.annotation.AnnotationUtils;
 import org.apache.juneau.rest.annotation.Logging;
 import org.apache.juneau.rest.util.*;
 import org.apache.juneau.svl.*;
+import org.apache.juneau.utils.*;
 
 /**
  * Applies {@link Rest} annotations to a {@link PropertyStoreBuilder}.
@@ -181,8 +182,7 @@ public class RestConfigApply extends ConfigApply<Rest> {
                        }
                }
 
-               if (! a.messages().isEmpty())
-                       psb.prependTo(REST_messages, new 
MessageBundleLocation(c.inner(), string(a.messages())));
+               psb.prependTo(REST_messages, Tuple2.of(c.inner(), 
string(a.messages())));
 
                for (String header : strings(a.staticFileResponseHeaders())) {
                        String[] h = RestUtils.parseHeader(header);
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java
index 769603a..e66908f 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java
@@ -173,7 +173,7 @@ public class RestResourceConfigApply extends 
ConfigApply<RestResource> {
                }
 
                if (! a.messages().isEmpty())
-                       psb.prependTo(REST_messages, new 
MessageBundleLocation(c.inner(), string(a.messages())));
+                       psb.prependTo(REST_messages, Tuple2.of(c.inner(), 
string(a.messages())));
 
                for (String header : strings(a.staticFileResponseHeaders())) {
                        String[] h = RestUtils.parseHeader(header);

Reply via email to