el-based message resolution; expected failure right now
This commit is contained in:
@@ -16,10 +16,22 @@
|
||||
package org.springframework.ui.message;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.ParseException;
|
||||
import org.springframework.expression.ParserContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
class DefaultMessageResolver implements MessageResolver, MessageSourceResolvable {
|
||||
|
||||
@@ -27,22 +39,41 @@ class DefaultMessageResolver implements MessageResolver, MessageSourceResolvable
|
||||
|
||||
private String[] codes;
|
||||
|
||||
private Object[] args;
|
||||
|
||||
private Map<String, Object> args;
|
||||
|
||||
private String defaultText;
|
||||
|
||||
public DefaultMessageResolver(Severity severity, String[] codes, Object[] args, String defaultText) {
|
||||
private ExpressionParser expressionParser;
|
||||
|
||||
public DefaultMessageResolver(Severity severity, String[] codes, Map<String, Object> args,
|
||||
String defaultText, ExpressionParser expressionParser) {
|
||||
this.severity = severity;
|
||||
this.codes = codes;
|
||||
this.args = args;
|
||||
this.defaultText = defaultText;
|
||||
this.expressionParser = expressionParser;
|
||||
}
|
||||
|
||||
|
||||
// implementing MessageResolver
|
||||
|
||||
public Message resolveMessage(MessageSource messageSource, Locale locale) {
|
||||
String text = messageSource.getMessage(this, locale);
|
||||
return new TextMessage(severity, text);
|
||||
String messageString = messageSource.getMessage(this, locale);
|
||||
Expression message;
|
||||
try {
|
||||
message = expressionParser.parseExpression(messageString, ParserContext.TEMPLATE_EXPRESSION);
|
||||
} catch (ParseException e) {
|
||||
throw new MessageResolutionException("Failed to parse message expression", e);
|
||||
}
|
||||
try {
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.setRootObject(args);
|
||||
context.addPropertyAccessor(new MapAccessor());
|
||||
context.addPropertyAccessor(new MessageSourceResolvableAccessor(messageSource, locale));
|
||||
String text = (String) message.getValue(context);
|
||||
return new TextMessage(severity, text);
|
||||
} catch (EvaluationException e) {
|
||||
throw new MessageResolutionException("Failed to evaluate expression to generate message text", e);
|
||||
}
|
||||
}
|
||||
|
||||
// implementing MessageSourceResolver
|
||||
@@ -52,7 +83,7 @@ class DefaultMessageResolver implements MessageResolver, MessageSourceResolvable
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
return args;
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getDefaultMessage() {
|
||||
@@ -60,20 +91,21 @@ class DefaultMessageResolver implements MessageResolver, MessageSourceResolvable
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("severity", severity).append("codes", codes).append("args", args).append("defaultText", defaultText).toString();
|
||||
return new ToStringCreator(this).append("severity", severity).append("codes", codes).append("defaultText",
|
||||
defaultText).toString();
|
||||
}
|
||||
|
||||
|
||||
static class TextMessage implements Message {
|
||||
|
||||
private Severity severity;
|
||||
|
||||
|
||||
private String text;
|
||||
|
||||
|
||||
public TextMessage(Severity severity, String text) {
|
||||
this.severity = severity;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
||||
public Severity getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
@@ -81,7 +113,41 @@ class DefaultMessageResolver implements MessageResolver, MessageSourceResolvable
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MessageSourceResolvableAccessor implements PropertyAccessor {
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
private Locale locale;
|
||||
|
||||
public MessageSourceResolvableAccessor(MessageSource messageSource, Locale locale) {
|
||||
this.messageSource = messageSource;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return true;
|
||||
}
|
||||
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
// TODO this does not get called when resolving MessageSourceResolvable variables; only when accessing properties on MessageSourceResolvable targets.
|
||||
return new TypedValue(messageSource.getMessage((MessageSourceResolvable)target, locale));
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
|
||||
throw new UnsupportedOperationException("Should not be called");
|
||||
}
|
||||
|
||||
public Class[] getSpecificTargetClasses() {
|
||||
return new Class[] { MessageSourceResolvable.class };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,14 +15,18 @@
|
||||
*/
|
||||
package org.springframework.ui.message;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* A convenient builder for building {@link MessageResolver} objects programmatically.
|
||||
@@ -46,16 +50,18 @@ import org.springframework.core.style.ToStringCreator;
|
||||
*/
|
||||
public class MessageBuilder {
|
||||
|
||||
private Severity severity;
|
||||
|
||||
private Set<String> codes = new LinkedHashSet<String>();
|
||||
|
||||
private Severity severity;
|
||||
|
||||
private List<Object> args = new ArrayList<Object>();
|
||||
private Map<String, Object> args = new LinkedHashMap<String, Object>();
|
||||
|
||||
private String defaultText;
|
||||
|
||||
private ExpressionParser expressionParser = new SpelExpressionParser();
|
||||
|
||||
/**
|
||||
* Records the severity of the message.
|
||||
* Set the severity of the message.
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder severity(Severity severity) {
|
||||
@@ -64,8 +70,8 @@ public class MessageBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the message being built should try and resolve its text using the code provided.
|
||||
* Adds the code to the codes list. Successive calls to this method add additional codes.
|
||||
* Add a message code to use to resolve the message text.
|
||||
* Successive calls to this method add additional codes.
|
||||
* Codes are applied in the order they are added.
|
||||
* @param code the message code
|
||||
* @return this, for fluent API usage
|
||||
@@ -76,31 +82,31 @@ public class MessageBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the message being built has a variable argument.
|
||||
* Adds the arg to the args list. Successive calls to this method add additional args.
|
||||
* Args are applied in the order they are added.
|
||||
* @param arg the message argument value
|
||||
* Add a message argument.
|
||||
* Successive calls to this method add additional args.
|
||||
* @param name the argument name
|
||||
* @param value the argument value
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder arg(Object arg) {
|
||||
args.add(arg);
|
||||
public MessageBuilder arg(String name, Object value) {
|
||||
args.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the message being built has a variable argument, whose display value is also {@link MessageSourceResolvable}.
|
||||
* Adds the arg to the args list. Successive calls to this method add additional resolvable args.
|
||||
* Args are applied in the order they are added.
|
||||
* @param arg the resolvable message argument
|
||||
* Add a message argument whose value is a resolvable message code.
|
||||
* Successive calls to this method add additional resolvable arguements.
|
||||
* @param name the argument name
|
||||
* @param value the argument value
|
||||
* @return this, for fluent API usage
|
||||
*/
|
||||
public MessageBuilder resolvableArg(Object arg) {
|
||||
args.add(new ResolvableArgument(arg));
|
||||
public MessageBuilder resolvableArg(String name, Object value) {
|
||||
args.put(name, new ResolvableArgumentValue(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the fallback text of the message being built.
|
||||
* Set the fallback text for the message.
|
||||
* If the message has no codes, this will always be used as the text.
|
||||
* If the message has codes but none can be resolved, this will always be used as the text.
|
||||
* @param text the default text
|
||||
@@ -113,28 +119,28 @@ public class MessageBuilder {
|
||||
|
||||
/**
|
||||
* Builds the message that will be resolved.
|
||||
* Call after recording builder instructions.
|
||||
* Call after recording all builder instructions.
|
||||
* @return the built message resolver
|
||||
* @throws Illegal
|
||||
*/
|
||||
public MessageResolver build() {
|
||||
if (severity == null) {
|
||||
severity = Severity.INFO;
|
||||
}
|
||||
if (codes == null && defaultText == null) {
|
||||
throw new IllegalArgumentException(
|
||||
throw new IllegalStateException(
|
||||
"A message code or the message text is required to build this message resolver");
|
||||
}
|
||||
String[] codesArray = (String[]) codes.toArray(new String[codes.size()]);
|
||||
Object[] argsArray = args.toArray(new Object[args.size()]);
|
||||
return new DefaultMessageResolver(severity, codesArray, argsArray, defaultText);
|
||||
return new DefaultMessageResolver(severity, codesArray, args, defaultText, expressionParser);
|
||||
}
|
||||
|
||||
private static class ResolvableArgument implements MessageSourceResolvable {
|
||||
static class ResolvableArgumentValue implements MessageSourceResolvable {
|
||||
|
||||
private Object arg;
|
||||
private Object value;
|
||||
|
||||
public ResolvableArgument(Object arg) {
|
||||
this.arg = arg;
|
||||
public ResolvableArgumentValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object[] getArguments() {
|
||||
@@ -142,15 +148,15 @@ public class MessageBuilder {
|
||||
}
|
||||
|
||||
public String[] getCodes() {
|
||||
return new String[] { arg.toString() };
|
||||
return new String[] { value.toString() };
|
||||
}
|
||||
|
||||
public String getDefaultMessage() {
|
||||
return arg.toString();
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("arg", arg).toString();
|
||||
return new ToStringCreator(this).append("value", value).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.springframework.ui.message;
|
||||
|
||||
public class MessageResolutionException extends RuntimeException {
|
||||
|
||||
public MessageResolutionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user