REST refactoring.
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/Messages_Test.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/Messages_Test.java
index 4e4d49e..df86893 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/Messages_Test.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/Messages_Test.java
@@ -75,7 +75,7 @@
assertString(x1.forLocale(CHINA).getString("file")).is("MessageBundleTest1.properties");
assertString(x1.forLocale((Locale)null).getString("file")).is("MessageBundleTest1.properties");
- Messages x2 = Messages.create(MessageBundleTest1.class).locale(null).build();
+ Messages x2 = Messages.create(MessageBundleTest1.class).locale((Locale)null).build();
assertString(x2.getString("file")).is("MessageBundleTest1.properties");
assertString(x2.forLocale(JAPANESE).getString("file")).is("MessageBundleTest1_ja.properties");
assertString(x2.forLocale(JAPAN).getString("file")).is("MessageBundleTest1_ja_JP.properties");
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/MessagesBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/MessagesBuilder.java
index 9f698a2..67db127 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/MessagesBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/MessagesBuilder.java
@@ -94,6 +94,18 @@
}
/**
+ * Specifies the locale.
+ *
+ * @param locale
+ * The locale.
+ * If <jk>null</jk>, the default locale is used.
+ * @return This object (for method chaining).
+ */
+ public MessagesBuilder locale(String locale) {
+ return locale(locale == null ? null : Locale.forLanguageTag(locale));
+ }
+
+ /**
* Creates a new {@link Messages} based on the setting of this builder.
*
* @return A new {@link Messages} object.
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 7579c7f..5f0cef5 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
@@ -52,6 +52,7 @@
import org.apache.juneau.httppart.bean.*;
import org.apache.juneau.json.*;
import org.apache.juneau.jsonschema.*;
+import org.apache.juneau.marshall.*;
import org.apache.juneau.msgpack.*;
import org.apache.juneau.mstat.*;
import org.apache.juneau.oapi.*;
@@ -3345,29 +3346,25 @@
consumes = getListProperty(REST_consumes, MediaType.class, parsers.getSupportedMediaTypes());
produces = getListProperty(REST_produces, MediaType.class, serializers.getSupportedMediaTypes());
- Tuple2<Class<?>,String>[] mbl = getInstanceArrayProperty(REST_messages, Tuple2.class);
- 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;
+ msgs = createMessages(r);
- this.fullPath = (builder.parentContext == null ? "" : (builder.parentContext.fullPath + '/')) + builder.getPath();
+ fullPath = (builder.parentContext == null ? "" : (builder.parentContext.fullPath + '/')) + builder.getPath();
String p = builder.getPath();
if (! p.endsWith("/*"))
p += "/*";
- this.pathMatcher = UrlPathMatcher.of(p);
+ pathMatcher = UrlPathMatcher.of(p);
- this.childResources = Collections.synchronizedMap(new LinkedHashMap<String,RestContext>()); // Not unmodifiable on purpose so that children can be replaced.
+ childResources = Collections.synchronizedMap(new LinkedHashMap<String,RestContext>()); // Not unmodifiable on purpose so that children can be replaced.
- this.startCallMethods = createStartCallMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
- this.endCallMethods = createEndCallMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
- this.postInitMethods = createPostInitMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
- this.postInitChildFirstMethods = createPostInitChildFirstMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
- this.destroyMethods = createDestroyMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
+ startCallMethods = createStartCallMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
+ endCallMethods = createEndCallMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
+ postInitMethods = createPostInitMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
+ postInitChildFirstMethods = createPostInitChildFirstMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
+ destroyMethods = createDestroyMethods(r).stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
- this.preCallMethods = createPreCallMethods(r).stream().map(this::toRestMethodInvoker).toArray(RestMethodInvoker[]:: new);
- this.postCallMethods = createPostCallMethods(r).stream().map(this::toRestMethodInvoker).toArray(RestMethodInvoker[]:: new);
+ preCallMethods = createPreCallMethods(r).stream().map(this::toRestMethodInvoker).toArray(RestMethodInvoker[]:: new);
+ postCallMethods = createPostCallMethods(r).stream().map(this::toRestMethodInvoker).toArray(RestMethodInvoker[]:: new);
//----------------------------------------------------------------------------------------------------
// Initialize the child resources.
@@ -4620,6 +4617,37 @@
}
/**
+ * Instantiates the messages for this REST object.
+ *
+ * @param resource The REST resource object.
+ * @return The messages for this REST object.
+ * @throws Exception An error occurred.
+ */
+ protected Messages createMessages(Object resource) throws Exception {
+ Tuple2<Class<?>,String>[] mbl = getInstanceArrayProperty(REST_messages, Tuple2.class);
+ Messages msgs = null;
+ for (int i = mbl.length-1; i >= 0; i--) {
+ Class<?> c = firstNonNull(mbl[i].getA(), resource.getClass());
+ String value = mbl[i].getB();
+ if (isJsonObject(value,true)) {
+ MessagesString x = SimpleJson.DEFAULT.read(value, MessagesString.class);
+ msgs = Messages.create(c).name(x.name).baseNames(split(x.baseNames, ',')).locale(x.locale).parent(msgs).build();
+ } else {
+ msgs = Messages.create(c).name(value).parent(msgs).build();
+ }
+ }
+ if (msgs == null)
+ msgs = Messages.create(resource.getClass()).build();
+ return msgs;
+ }
+
+ private static class MessagesString {
+ public String name;
+ public String[] baseNames;
+ public String locale;
+ }
+
+ /**
* Instantiates the list of {@link HookEvent#START_CALL} methods.
*
* @param resource The REST resource object.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
index 283006b..b1eedd1 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
@@ -697,6 +697,26 @@
*
* Identifies the location of the resource bundle for this class.
*
+ * <p>
+ * There are two possible formats:
+ * <ul>
+ * <li>A simple string - Represents the {@link MessagesBuilder#name(String) name} of the resource bundle.
+ * <br><br><i>Example:</i>
+ * <p class='bcode w800'>
+ * <jc>// Bundle name is Messages.properties.</jc>
+ * <ja>@Rest</ja>(messages=<js>"Messages"</js>)
+ * </p>
+ * <li>Simplified JSON - Represents parameters for the {@link MessagesBuilder} class.
+ * <br><br><i>Example:</i>
+ * <p class='bcode w800'>
+ * <jc>// Bundles can be found in two packages.</jc>
+ * <ja>@Rest</ja>(messages=<js>"{name:'Messages',baseNames:['{package}.{name}','{package}.i18n.{name}']"</js>)
+ * </p>
+ * </ul>
+ *
+ * <p>
+ * If the bundle name is not specified, the class name of the resource object is used.
+ *
* <ul class='notes'>
* <li>
* Supports {@doc RestSvlVariables}