Browse Source
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1996 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/head
41 changed files with 0 additions and 2788 deletions
@ -1,42 +0,0 @@
@@ -1,42 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.alert; |
||||
|
||||
/** |
||||
* Communicates an event of interest to the user. |
||||
* For example, an alert may inform a user of a application a business rule was violated. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public interface Alert { |
||||
|
||||
/** |
||||
* The code uniquely identifying this kind of alert; for example, "weakPassword". |
||||
* May be used as a key to lookup additional alert details. |
||||
*/ |
||||
public String getCode(); |
||||
|
||||
/** |
||||
* The level of impact this alert has on the user. |
||||
*/ |
||||
public Severity getSeverity(); |
||||
|
||||
/** |
||||
* The localized message to display to the user; for example, "Please enter a stronger password". |
||||
*/ |
||||
public String getMessage(); |
||||
|
||||
} |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.alert; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* A context for adding and getting alerts for display in a user interface. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public interface AlertContext { |
||||
|
||||
/** |
||||
* Return all alerts in this context indexed by the UI element they are associated with. |
||||
* @return the message map |
||||
*/ |
||||
public Map<String, List<Alert>> getAlerts(); |
||||
|
||||
/** |
||||
* Get all alerts on the UI element provided. |
||||
* Returns an empty list if no alerts have been added for the element. |
||||
* Alerts are returned in the order they were added. |
||||
* @param element the id of the element to lookup alerts against |
||||
*/ |
||||
public List<Alert> getAlerts(String element); |
||||
|
||||
/** |
||||
* Add an alert to this context. |
||||
* @param the element this alert is associated with |
||||
* @param alert the alert to add |
||||
*/ |
||||
public void add(String element, Alert alert); |
||||
|
||||
} |
||||
@ -1,104 +0,0 @@
@@ -1,104 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.alert; |
||||
|
||||
/** |
||||
* A static factory for conveniently constructing Alerts. |
||||
* Usage example: |
||||
* <pre> |
||||
* import static org.springframework.ui.alert.Alerts.*; |
||||
* |
||||
* public void example() { |
||||
* info("An info alert"); |
||||
* warning("A warning alert"); |
||||
* error("An error alert"); |
||||
* fatal("A fatal alert"); |
||||
* } |
||||
* </pre> |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public final class Alerts { |
||||
|
||||
/** |
||||
* Creates a new info alert. |
||||
* @param message the alert message |
||||
* @return the info alert |
||||
* @see Severity#INFO |
||||
*/ |
||||
public static Alert info(String message) { |
||||
return new GenericAlert(Severity.INFO, message); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new warning alert. |
||||
* @param message the alert message |
||||
* @return the info alert |
||||
* @see Severity#WARNING |
||||
*/ |
||||
public static Alert warning(String message) { |
||||
return new GenericAlert(Severity.WARNING, message); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new error alert. |
||||
* @param message the alert message |
||||
* @return the info alert |
||||
* @see Severity#ERROR |
||||
*/ |
||||
public static Alert error(String message) { |
||||
return new GenericAlert(Severity.ERROR, message); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new fatal alert. |
||||
* @param message the alert message |
||||
* @return the info alert |
||||
* @see Severity#FATAL |
||||
*/ |
||||
public static Alert fatal(String message) { |
||||
return new GenericAlert(Severity.FATAL, message); |
||||
} |
||||
|
||||
private static class GenericAlert implements Alert { |
||||
|
||||
private Severity severity; |
||||
|
||||
private String message; |
||||
|
||||
public GenericAlert(Severity severity, String message) { |
||||
this.severity = severity; |
||||
this.message = message; |
||||
} |
||||
|
||||
public String getCode() { |
||||
return null; |
||||
} |
||||
|
||||
public Severity getSeverity() { |
||||
return severity; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
return message; |
||||
} |
||||
|
||||
public String toString() { |
||||
return getSeverity() + ": " + getMessage(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,51 +0,0 @@
@@ -1,51 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.alert; |
||||
|
||||
/** |
||||
* The set of alert severities. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see Alert |
||||
*/ |
||||
public enum Severity { |
||||
|
||||
/** |
||||
* The "Informational" severity. |
||||
* Indicates a successful operation or result. |
||||
*/ |
||||
INFO, |
||||
|
||||
/** |
||||
* The "Warning" severity. |
||||
* Indicates there is a minor problem, or to inform the user of possible misuse, |
||||
* or to indicate a problem may arise in the future. |
||||
*/ |
||||
WARNING, |
||||
|
||||
/** |
||||
* The "Error" severity. |
||||
* Indicates a significant problem like a business rule violation. |
||||
*/ |
||||
ERROR, |
||||
|
||||
/** |
||||
* The "Fatal" severity. |
||||
* Indicates a fatal problem like a system error or runtime exception. |
||||
*/ |
||||
FATAL |
||||
|
||||
} |
||||
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
/** |
||||
* A general-purpose Alerting API to communicate events of interest. |
||||
*/ |
||||
package org.springframework.context.alert; |
||||
|
||||
@ -1,66 +0,0 @@
@@ -1,66 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.alert.support; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.context.alert.Alert; |
||||
import org.springframework.context.alert.AlertContext; |
||||
import org.springframework.core.style.ToStringCreator; |
||||
import org.springframework.util.CachingMapDecorator; |
||||
|
||||
/** |
||||
* The default alert context implementation. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public class DefaultAlertContext implements AlertContext { |
||||
|
||||
@SuppressWarnings("serial") |
||||
private Map<String, List<Alert>> alerts = new CachingMapDecorator<String, List<Alert>>(new LinkedHashMap<String, List<Alert>>()) { |
||||
protected List<Alert> create(String element) { |
||||
return new ArrayList<Alert>(); |
||||
} |
||||
}; |
||||
|
||||
// implementing AlertContext
|
||||
|
||||
public Map<String, List<Alert>> getAlerts() { |
||||
return Collections.unmodifiableMap(alerts); |
||||
} |
||||
|
||||
public List<Alert> getAlerts(String element) { |
||||
List<Alert> messages = alerts.get(element); |
||||
if (messages.isEmpty()) { |
||||
return Collections.emptyList(); |
||||
} |
||||
return Collections.unmodifiableList(messages); |
||||
} |
||||
|
||||
public void add(String element, Alert alert) { |
||||
List<Alert> alerts = this.alerts.get(element); |
||||
alerts.add(alert); |
||||
} |
||||
|
||||
public String toString() { |
||||
return new ToStringCreator(this).append("alerts", alerts).toString(); |
||||
} |
||||
|
||||
} |
||||
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
/** |
||||
* AlertContext implementation suitable for use in most environments. |
||||
*/ |
||||
package org.springframework.context.alert.support; |
||||
|
||||
@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
/** |
||||
* A factory for a default message to return if no message could be resolved. |
||||
* Allows the message String to be created lazily, only when it is needed. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see MessageBuilder |
||||
*/ |
||||
public interface DefaultMessageFactory { |
||||
|
||||
/** |
||||
* Create the default message. |
||||
*/ |
||||
String createDefaultMessage(); |
||||
} |
||||
@ -1,153 +0,0 @@
@@ -1,153 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
import org.springframework.context.MessageSourceResolvable; |
||||
import org.springframework.context.NoSuchMessageException; |
||||
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; |
||||
|
||||
final class DefaultMessageResolver implements MessageResolver, MessageSourceResolvable { |
||||
|
||||
private String[] codes; |
||||
|
||||
private Map<String, Object> args; |
||||
|
||||
private DefaultMessageFactory defaultMessageFactory; |
||||
|
||||
private ExpressionParser expressionParser; |
||||
|
||||
public DefaultMessageResolver(String[] codes, Map<String, Object> args, |
||||
DefaultMessageFactory defaultMessageFactory, ExpressionParser expressionParser) { |
||||
this.codes = codes; |
||||
this.args = args; |
||||
this.defaultMessageFactory = defaultMessageFactory; |
||||
this.expressionParser = expressionParser; |
||||
} |
||||
|
||||
// implementing MessageResolver
|
||||
|
||||
public String resolveMessage(MessageSource messageSource, Locale locale) { |
||||
if (messageSource == null) { |
||||
if (defaultMessageFactory != null) { |
||||
return defaultMessageFactory.createDefaultMessage(); |
||||
} else { |
||||
throw new MessageResolutionException( |
||||
"Unable to resolve message; MessagSource argument is null and no defaultMessage is configured"); |
||||
} |
||||
} |
||||
String messageString; |
||||
try { |
||||
messageString = messageSource.getMessage(this, locale); |
||||
} catch (NoSuchMessageException e) { |
||||
throw new MessageResolutionException("Unable to resolve message in" + messageSource, e); |
||||
} |
||||
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 MessageArgumentAccessor(messageSource, locale)); |
||||
return (String) message.getValue(context); |
||||
} catch (EvaluationException e) { |
||||
throw new MessageResolutionException("Failed to evaluate message expression '" |
||||
+ message.getExpressionString() + "' to generate final message text", e); |
||||
} |
||||
} |
||||
|
||||
// implementing MessageSourceResolver
|
||||
|
||||
public String[] getCodes() { |
||||
return codes; |
||||
} |
||||
|
||||
public Object[] getArguments() { |
||||
return null; |
||||
} |
||||
|
||||
public String getDefaultMessage() { |
||||
return defaultMessageFactory.createDefaultMessage(); |
||||
} |
||||
|
||||
public String toString() { |
||||
return new ToStringCreator(this).append("codes", codes).append("args", args).append("defaultMessageFactory", |
||||
defaultMessageFactory).toString(); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
static class MessageArgumentAccessor implements PropertyAccessor { |
||||
|
||||
private MessageSource messageSource; |
||||
|
||||
private Locale locale; |
||||
|
||||
public MessageArgumentAccessor(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 { |
||||
Map map = (Map) target; |
||||
Object o = map.get(name); |
||||
if (o == null) { |
||||
throw new AccessException("No message argument named '" + name |
||||
+ "' is defined in the argument map; arguments available are " + map.keySet(), null); |
||||
} |
||||
if (o instanceof MessageSourceResolvable) { |
||||
String message = messageSource.getMessage((MessageSourceResolvable) o, locale); |
||||
return new TypedValue(message); |
||||
} else { |
||||
return new TypedValue(o); |
||||
} |
||||
} |
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { |
||||
return false; |
||||
} |
||||
|
||||
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[] { Map.class }; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,148 +0,0 @@
@@ -1,148 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
import org.springframework.context.i18n.LocaleContextHolder; |
||||
|
||||
/** |
||||
* Builds a localized message for display in a user interface. |
||||
* Allows convenient specification of the codes to try to resolve the message. |
||||
* Also supports named arguments that can inserted into a message template using eval #{expressions}. |
||||
* <p> |
||||
* Usage example: |
||||
* <pre> |
||||
* String message = new MessageBuilder(messageSource). |
||||
* code("invalidFormat"). |
||||
* arg("label", new ResolvableArgument("mathForm.decimalField")). |
||||
* arg("format", "#,###.##"). |
||||
* defaultMessage("The decimal field must be in format #,###.##"). |
||||
* build(); |
||||
* </pre> |
||||
* Example messages.properties loaded by the MessageSource: |
||||
* <pre> |
||||
* invalidFormat=The #{label} must be in format #{format}. |
||||
* mathForm.decimalField=Decimal Field |
||||
* </pre> |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see #code(String) |
||||
* @see #arg(String, Object) |
||||
* @see #defaultMessage(String) |
||||
* @see #locale(Locale) |
||||
*/ |
||||
public class MessageBuilder { |
||||
|
||||
private MessageSource messageSource; |
||||
|
||||
private Locale locale; |
||||
|
||||
private MessageResolverBuilder messageResolverBuilder = new MessageResolverBuilder(); |
||||
|
||||
/** |
||||
* Create a new MessageBuilder that builds messages from message templates defined in the MessageSource |
||||
* @param messageSource the message source |
||||
*/ |
||||
public MessageBuilder(MessageSource messageSource) { |
||||
this.messageSource = messageSource; |
||||
} |
||||
|
||||
/** |
||||
* Add a code that will be tried to lookup the message template used to create the localized message. |
||||
* Successive calls to this method add additional codes. |
||||
* Codes are tried in the order they are added. |
||||
* @param code a message code to try |
||||
* @return this, for fluent API usage |
||||
*/ |
||||
public MessageBuilder code(String code) { |
||||
messageResolverBuilder.code(code); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add an argument to insert into the message. |
||||
* Named arguments are inserted by eval #{expressions} denoted within the message template. |
||||
* For example, the value of the 'format' argument would be inserted where a corresponding #{format} expression is defined in the message template. |
||||
* Successive calls to this method add additional arguments. |
||||
* May also add {@link ResolvableArgument resolvable arguments} whose values are resolved against the MessageSource. |
||||
* @param name the argument name |
||||
* @param value the argument value |
||||
* @return this, for fluent API usage |
||||
* @see ResolvableArgument |
||||
*/ |
||||
public MessageBuilder arg(String name, Object value) { |
||||
messageResolverBuilder.arg(name, value); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Set the default message. |
||||
* If there are no codes to try, this will be used as the message. |
||||
* If there are codes to try but none of those resolve to a message, this will be used as the message. |
||||
* @param message the default text |
||||
* @return this, for fluent API usage |
||||
*/ |
||||
public MessageBuilder defaultMessage(String message) { |
||||
messageResolverBuilder.defaultMessage(message); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Set the default message. |
||||
* If there are no codes to try, this will be used as the message. |
||||
* If there are codes to try but none of those resolve to a message, this will be used as the message. |
||||
* @param message the default text |
||||
* @return this, for fluent API usage |
||||
*/ |
||||
public MessageBuilder defaultMessage(DefaultMessageFactory defaultMessageFactory) { |
||||
messageResolverBuilder.defaultMessage(defaultMessageFactory); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Set the message locale. |
||||
* If not set, the default locale the Locale of the current request obtained from {@link LocaleContextHolder#getLocale()}. |
||||
* @param message the locale |
||||
* @return this, for fluent API usage |
||||
*/ |
||||
public MessageBuilder locale(Locale locale) { |
||||
this.locale = locale; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Builds the resolver for the message. |
||||
* Call after recording all builder instructions. |
||||
* @return the built message resolver |
||||
* @throws IllegalStateException if no codes have been added and there is no default message |
||||
*/ |
||||
public String build() { |
||||
return messageResolverBuilder.build().resolveMessage(messageSource, getLocale()); |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private Locale getLocale() { |
||||
if (locale != null) { |
||||
return locale; |
||||
} else { |
||||
return LocaleContextHolder.getLocale(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,43 +0,0 @@
@@ -1,43 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
/** |
||||
* Runtime exception thrown by a {@link MessageResolver} if a message resolution fails. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
@SuppressWarnings("serial") |
||||
public class MessageResolutionException extends RuntimeException { |
||||
|
||||
/** |
||||
* Creates a new message resolution exception. |
||||
* @param message a messaging describing the failure |
||||
*/ |
||||
public MessageResolutionException(String message) { |
||||
super(message); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new message resolution exception. |
||||
* @param message a messaging describing the failure |
||||
* @param cause the cause of the failure |
||||
*/ |
||||
public MessageResolutionException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
|
||||
} |
||||
@ -1,38 +0,0 @@
@@ -1,38 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
|
||||
/** |
||||
* A factory for a localized message resolved from a MessageSource. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see MessageSource |
||||
*/ |
||||
public interface MessageResolver { |
||||
|
||||
/** |
||||
* Resolve the message from the message source for the locale. |
||||
* @param messageSource the message source, an abstraction for a resource bundle |
||||
* @param locale the locale of this request |
||||
* @return the resolved message |
||||
* @throws MessageResolutionException if a resolution failure occurs |
||||
*/ |
||||
public String resolveMessage(MessageSource messageSource, Locale locale); |
||||
} |
||||
@ -1,130 +0,0 @@
@@ -1,130 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
import java.util.LinkedHashMap; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.expression.ExpressionParser; |
||||
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||
|
||||
/** |
||||
* Builds a {@link MessageResolver} that can resolve a localized message for display in a user interface. |
||||
* Allows convenient specification of the codes to try to resolve the message. |
||||
* Also supports named arguments that can inserted into a message template using eval #{expressions}. |
||||
* <p> |
||||
* Usage example: |
||||
* <pre> |
||||
* MessageResolver resolver = new MessageResolverBuilder(). |
||||
* code("invalidFormat"). |
||||
* arg("label", new ResolvableArgument("mathForm.decimalField")). |
||||
* arg("format", "#,###.##"). |
||||
* defaultMessage("The decimal field must be in format #,###.##"). |
||||
* build(); |
||||
* String message = resolver.resolveMessage(messageSource, locale); |
||||
* </pre> |
||||
* Example messages.properties loaded by the MessageSource: |
||||
* <pre> |
||||
* invalidFormat=The #{label} must be in format #{format}. |
||||
* mathForm.decimalField=Decimal Field |
||||
* </pre> |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see #code(String) |
||||
* @see #arg(String, Object) |
||||
* @see #defaultMessage(String) |
||||
*/ |
||||
public class MessageResolverBuilder { |
||||
|
||||
private Set<String> codes = new LinkedHashSet<String>(); |
||||
|
||||
private Map<String, Object> args = new LinkedHashMap<String, Object>(); |
||||
|
||||
private DefaultMessageFactory defaultMessageFactory; |
||||
|
||||
private ExpressionParser expressionParser = new SpelExpressionParser(); |
||||
|
||||
/** |
||||
* Add a code that will be tried to lookup the message template used to create the localized message. |
||||
* Successive calls to this method add additional codes. |
||||
* Codes are tried in the order they are added. |
||||
* @param code a message code to try |
||||
* @return this, for fluent API usage |
||||
*/ |
||||
public MessageResolverBuilder code(String code) { |
||||
codes.add(code); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add an argument to insert into the message. |
||||
* Named arguments are inserted by eval #{expressions} denoted within the message template. |
||||
* For example, the value of the 'format' argument would be inserted where a corresponding #{format} expression is defined in the message template. |
||||
* Successive calls to this method add additional arguments. |
||||
* May also add {@link ResolvableArgument resolvable arguments} whose values are resolved against the MessageSource passed to |
||||
* {@link MessageResolver#resolveMessage(org.springframework.context.MessageSource, java.util.Locale)}. |
||||
* @param name the argument name |
||||
* @param value the argument value |
||||
* @return this, for fluent API usage |
||||
* @see ResolvableArgument |
||||
*/ |
||||
public MessageResolverBuilder arg(String name, Object value) { |
||||
args.put(name, value); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Set the default message. |
||||
* If the MessageResolver has no codes to try, this will be used as the message. |
||||
* If the MessageResolver has codes to try but none of those resolve to a message, this will be used as the message. |
||||
* @param message the default text |
||||
* @return this, for fluent API usage |
||||
*/ |
||||
public MessageResolverBuilder defaultMessage(String message) { |
||||
return defaultMessage(new StaticDefaultMessageFactory(message)); |
||||
} |
||||
|
||||
/** |
||||
* Set the default message. |
||||
* If the MessageResolver has no codes to try, this will be used as the message. |
||||
* If the MessageResolver has codes to try but none of those resolve to a message, this will be used as the message. |
||||
* @param message the default text |
||||
* @return this, for fluent API usage |
||||
*/ |
||||
public MessageResolverBuilder defaultMessage(DefaultMessageFactory defaultMessageFactory) { |
||||
this.defaultMessageFactory = defaultMessageFactory; |
||||
return this; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Builds the resolver for the message. |
||||
* Call after recording all builder instructions. |
||||
* @return the built message resolver |
||||
* @throws IllegalStateException if no codes have been added and there is no default message |
||||
*/ |
||||
public MessageResolver build() { |
||||
if (codes == null && defaultMessageFactory == null) { |
||||
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()]); |
||||
return new DefaultMessageResolver(codesArray, args, defaultMessageFactory, expressionParser); |
||||
} |
||||
|
||||
} |
||||
@ -1,56 +0,0 @@
@@ -1,56 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
import org.springframework.context.MessageSourceResolvable; |
||||
import org.springframework.core.style.ToStringCreator; |
||||
|
||||
/** |
||||
* A message argument value that is resolved from a MessageSource. |
||||
* Allows the value to be localized. |
||||
* @see MessageSource |
||||
* @author Keith Donald |
||||
*/ |
||||
public class ResolvableArgument implements MessageSourceResolvable { |
||||
|
||||
private String code; |
||||
|
||||
/** |
||||
* Creates a resolvable argument. |
||||
* @param code the code that will be used to lookup the argument value from the message source |
||||
*/ |
||||
public ResolvableArgument(String code) { |
||||
this.code = code; |
||||
} |
||||
|
||||
public String[] getCodes() { |
||||
return new String[] { code.toString() }; |
||||
} |
||||
|
||||
public Object[] getArguments() { |
||||
return null; |
||||
} |
||||
|
||||
public String getDefaultMessage() { |
||||
return String.valueOf(code); |
||||
} |
||||
|
||||
public String toString() { |
||||
return new ToStringCreator(this).append("code", code).toString(); |
||||
} |
||||
|
||||
} |
||||
@ -1,30 +0,0 @@
@@ -1,30 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.context.message; |
||||
|
||||
class StaticDefaultMessageFactory implements DefaultMessageFactory { |
||||
|
||||
private String defaultMessage; |
||||
|
||||
public StaticDefaultMessageFactory(String defaultMessage) { |
||||
this.defaultMessage = defaultMessage; |
||||
} |
||||
|
||||
public String createDefaultMessage() { |
||||
return defaultMessage; |
||||
} |
||||
|
||||
} |
||||
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
/** |
||||
* An API for creating localized messages. |
||||
*/ |
||||
package org.springframework.context.message; |
||||
|
||||
@ -1,34 +0,0 @@
@@ -1,34 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.mapping; |
||||
|
||||
/** |
||||
* Maps between a source and target. |
||||
* @author Keith Donald |
||||
* @param <S> the source type mapped from |
||||
* @param <T> the target type mapped to |
||||
*/ |
||||
public interface Mapper<S, T> { |
||||
|
||||
/** |
||||
* Map the source to the target. |
||||
* @param source the source to map from |
||||
* @param target the target to map to |
||||
* @throws MappingException if the mapping process failed |
||||
*/ |
||||
void map(S source, T target); |
||||
|
||||
} |
||||
@ -1,28 +0,0 @@
@@ -1,28 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.mapping; |
||||
|
||||
/** |
||||
* Base runtime exception for the mapping system. |
||||
* @author Keith Donald |
||||
*/ |
||||
public class MappingException extends RuntimeException { |
||||
|
||||
public MappingException(String message, Throwable cause) { |
||||
super(message, cause); |
||||
} |
||||
|
||||
} |
||||
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
package org.springframework.mapping.support; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import org.springframework.expression.EvaluationContext; |
||||
|
||||
interface MappableType { |
||||
|
||||
Set<String> getMappableFields(Object instance); |
||||
|
||||
EvaluationContext getMappingContext(Object instance); |
||||
|
||||
} |
||||
@ -1,7 +0,0 @@
@@ -1,7 +0,0 @@
|
||||
package org.springframework.mapping.support; |
||||
|
||||
import org.springframework.core.convert.converter.Converter; |
||||
|
||||
public interface MappingConfiguration { |
||||
MappingConfiguration setConverter(Converter converter); |
||||
} |
||||
@ -1,222 +0,0 @@
@@ -1,222 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.mapping.support; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.context.expression.MapAccessor; |
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.expression.EvaluationContext; |
||||
import org.springframework.expression.Expression; |
||||
import org.springframework.expression.ExpressionParser; |
||||
import org.springframework.expression.ParseException; |
||||
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||
import org.springframework.expression.spel.support.StandardEvaluationContext; |
||||
import org.springframework.mapping.Mapper; |
||||
import org.springframework.mapping.MappingException; |
||||
|
||||
/** |
||||
* A generic object mapper implementation based on the Spring Expression Language (SpEL). |
||||
* @author Keith Donald |
||||
*/ |
||||
public class SpelMapper implements Mapper<Object, Object> { |
||||
|
||||
private static final MappableType MAP_MAPPABLE_TYPE = new MapMappableType(); |
||||
|
||||
private static final MappableType BEAN_MAPPABLE_TYPE = new BeanMappableType(); |
||||
|
||||
private static final ExpressionParser expressionParser = new SpelExpressionParser(); |
||||
|
||||
private Set<Mapping> mappings = new LinkedHashSet<Mapping>(); |
||||
|
||||
private boolean autoMappingEnabled = true; |
||||
|
||||
public void setAutoMappingEnabled(boolean autoMappingEnabled) { |
||||
this.autoMappingEnabled = autoMappingEnabled; |
||||
} |
||||
|
||||
public MappingConfiguration addMapping(String sourceExpression, String targetExpression) { |
||||
Expression sourceExp; |
||||
try { |
||||
sourceExp = expressionParser.parseExpression(sourceExpression); |
||||
} catch (ParseException e) { |
||||
throw new IllegalArgumentException("The mapping source '" + sourceExpression |
||||
+ "' is not a parseable value expression", e); |
||||
} |
||||
Expression targetExp; |
||||
try { |
||||
targetExp = expressionParser.parseExpression(targetExpression); |
||||
} catch (ParseException e) { |
||||
throw new IllegalArgumentException("The mapping target '" + sourceExpression |
||||
+ "' is not a parseable property expression", e); |
||||
} |
||||
Mapping mapping = new Mapping(sourceExp, targetExp); |
||||
if (mappings == null) { |
||||
mappings = new LinkedHashSet<Mapping>(); |
||||
} |
||||
mappings.add(mapping); |
||||
return mapping; |
||||
} |
||||
|
||||
public void map(Object source, Object target) throws MappingException { |
||||
EvaluationContext sourceContext = getMappingContext(source); |
||||
EvaluationContext targetContext = getMappingContext(target); |
||||
for (Mapping mapping : mappings) { |
||||
mapping.map(sourceContext, targetContext); |
||||
} |
||||
Set<Mapping> autoMappings = getAutoMappings(source); |
||||
for (Mapping mapping : autoMappings) { |
||||
mapping.map(sourceContext, targetContext); |
||||
} |
||||
} |
||||
|
||||
protected EvaluationContext getMappingContext(Object object) { |
||||
if (object instanceof Map) { |
||||
return MAP_MAPPABLE_TYPE.getMappingContext(object); |
||||
} else { |
||||
return BEAN_MAPPABLE_TYPE.getMappingContext(object); |
||||
} |
||||
} |
||||
|
||||
protected Set<String> getMappableFields(Object object) { |
||||
if (object instanceof Map) { |
||||
return MAP_MAPPABLE_TYPE.getMappableFields(object); |
||||
} else { |
||||
return BEAN_MAPPABLE_TYPE.getMappableFields(object); |
||||
} |
||||
} |
||||
|
||||
private Set<Mapping> getAutoMappings(Object source) { |
||||
if (autoMappingEnabled) { |
||||
Set<Mapping> autoMappings = new LinkedHashSet<Mapping>(); |
||||
Set<String> fields = getMappableFields(source); |
||||
for (String field : fields) { |
||||
if (!explicitlyMapped(field)) { |
||||
Expression exp; |
||||
try { |
||||
exp = expressionParser.parseExpression(field); |
||||
} catch (ParseException e) { |
||||
throw new IllegalArgumentException("The mapping source '" + source |
||||
+ "' is not a parseable value expression", e); |
||||
} |
||||
Mapping mapping = new Mapping(exp, exp); |
||||
autoMappings.add(mapping); |
||||
} |
||||
} |
||||
return autoMappings; |
||||
} else { |
||||
return Collections.emptySet(); |
||||
} |
||||
} |
||||
|
||||
private boolean explicitlyMapped(String field) { |
||||
for (Mapping mapping : mappings) { |
||||
if (mapping.source.getExpressionString().equals(field)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private static class Mapping implements MappingConfiguration { |
||||
|
||||
private Expression source; |
||||
|
||||
private Expression target; |
||||
|
||||
private Converter converter; |
||||
|
||||
public Mapping(Expression source, Expression target) { |
||||
this.source = source; |
||||
this.target = target; |
||||
} |
||||
|
||||
public MappingConfiguration setConverter(Converter converter) { |
||||
this.converter = converter; |
||||
return this; |
||||
} |
||||
|
||||
public void map(EvaluationContext sourceContext, EvaluationContext targetContext) throws MappingException { |
||||
try { |
||||
Object value = source.getValue(sourceContext); |
||||
if (converter != null) { |
||||
value = converter.convert(value); |
||||
} |
||||
target.setValue(targetContext, value); |
||||
} catch (Exception e) { |
||||
throw new MappingException("Could not perform mapping", e); |
||||
} |
||||
} |
||||
|
||||
public int hashCode() { |
||||
return source.getExpressionString().hashCode() + target.getExpressionString().hashCode(); |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
if (!(o instanceof Mapping)) { |
||||
return false; |
||||
} |
||||
Mapping m = (Mapping) o; |
||||
return source.getExpressionString().equals(m.source.getExpressionString()) |
||||
&& target.getExpressionString().equals(m.source.getExpressionString()); |
||||
} |
||||
|
||||
public String toString() { |
||||
return source.getExpressionString() + " -> " + target.getExpressionString(); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class MapMappableType implements MappableType { |
||||
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); |
||||
|
||||
public Set<String> getMappableFields(Object instance) { |
||||
Map map = (Map) instance; |
||||
LinkedHashSet<String> fields = new LinkedHashSet<String>(map.size(), 1); |
||||
for (Object key : map.keySet()) { |
||||
fields.add(key.toString()); |
||||
} |
||||
return fields; |
||||
} |
||||
|
||||
public EvaluationContext getMappingContext(Object instance) { |
||||
StandardEvaluationContext context = new StandardEvaluationContext(instance); |
||||
context.addPropertyAccessor(new MapAccessor()); |
||||
return context; |
||||
} |
||||
|
||||
} |
||||
|
||||
static class BeanMappableType implements MappableType { |
||||
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); |
||||
|
||||
public Set<String> getMappableFields(Object instance) { |
||||
// TODO
|
||||
return null; |
||||
} |
||||
|
||||
public EvaluationContext getMappingContext(Object instance) { |
||||
return new StandardEvaluationContext(instance); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -1,37 +0,0 @@
@@ -1,37 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Bind to fields of a model object. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @param <M> The type of model this binder binds to |
||||
*/ |
||||
public interface Binder<M> { |
||||
|
||||
/** |
||||
* Bind submitted field values. |
||||
* @param fieldValues the field values to bind; an entry key is a field name, the associated entry value is the submitted value for that field |
||||
* @param model the model to bind to |
||||
* @return the results of the binding operation |
||||
* @throws MissingFieldException when the fieldValues Map is missing required fields |
||||
*/ |
||||
BindingResults bind(Map<String, ? extends Object> fieldValues, M model); |
||||
|
||||
} |
||||
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder; |
||||
|
||||
import org.springframework.context.alert.Alert; |
||||
|
||||
/** |
||||
* The result of a bind operation. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see Binder#bind(java.util.Map, Object) |
||||
*/ |
||||
public interface BindingResult { |
||||
|
||||
/** |
||||
* The name of the field this binding result is for. |
||||
* @see Binder#getNested(String) |
||||
*/ |
||||
String getFieldName(); |
||||
|
||||
/** |
||||
* The raw submitted value for which binding was attempted. |
||||
* If not a failure, this value was successfully bound to the model. |
||||
* @see #isFailure() |
||||
*/ |
||||
Object getSubmittedValue(); |
||||
|
||||
/** |
||||
* Indicates if the binding failed. |
||||
*/ |
||||
boolean isFailure(); |
||||
|
||||
/** |
||||
* Gets the alert for this binding result, appropriate for rendering the result to the user. |
||||
* An alert describing a successful binding will have info severity. |
||||
* An alert describing a failed binding will have either warning, error, or fatal severity. |
||||
*/ |
||||
Alert getAlert(); |
||||
|
||||
} |
||||
@ -1,68 +0,0 @@
@@ -1,68 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.springframework.context.alert.Severity; |
||||
|
||||
/** |
||||
* The results of a bind operation. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see Binder#bind(java.util.Map, Object) |
||||
*/ |
||||
public interface BindingResults extends Iterable<BindingResult> { |
||||
|
||||
/** |
||||
* The subset of BindingResults that were successful. |
||||
*/ |
||||
List<BindingResult> successes(); |
||||
|
||||
/** |
||||
* The subset of BindingResults that failed. |
||||
*/ |
||||
List<BindingResult> failures(); |
||||
|
||||
/** |
||||
* If there is at least one failure with a Severity equal to or greater than {@link Severity#ERROR}. |
||||
* @see BindingResults#failures() |
||||
*/ |
||||
boolean hasErrors(); |
||||
|
||||
/** |
||||
* The subset of BindingResults that failed with {@link Severity#ERROR} or greater. |
||||
*/ |
||||
List<BindingResult> errors(); |
||||
|
||||
/** |
||||
* The total number of results. |
||||
*/ |
||||
int size(); |
||||
|
||||
/** |
||||
* The BindingResult at the specified index. |
||||
* @throws IndexOutOfBoundsException if the index is out of bounds |
||||
*/ |
||||
BindingResult get(int index); |
||||
|
||||
/** |
||||
* The BindingResult for the specified field. |
||||
* Returns null if no result exists for the fieldName specified. |
||||
*/ |
||||
BindingResult get(String fieldName); |
||||
|
||||
} |
||||
@ -1,58 +0,0 @@
@@ -1,58 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Exception thrown by a Binder when a required source value is missing unexpectedly from the sourceValues map. |
||||
* Indicates a client configuration error. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see Binder#bind(Map, Object) |
||||
*/ |
||||
@SuppressWarnings("serial") |
||||
public class MissingFieldException extends RuntimeException { |
||||
|
||||
private List<String> missing; |
||||
|
||||
/** |
||||
* Creates a new missing field exceptions. |
||||
* @param missing |
||||
* @param fieldValues |
||||
*/ |
||||
public MissingFieldException(List<String> missing, Map<String, ? extends Object> fieldValues) { |
||||
super(getMessage(missing, fieldValues)); |
||||
this.missing = missing; |
||||
} |
||||
|
||||
/** |
||||
* The names of the fields that are missing. |
||||
*/ |
||||
public List<String> getMissing() { |
||||
return missing; |
||||
} |
||||
|
||||
private static String getMessage(List<String> missingRequired, Map<String, ? extends Object> sourceValues) { |
||||
if (missingRequired.size() == 1) { |
||||
return "Missing a field [" + missingRequired.get(0) + "]; fieldValues map contained " + sourceValues.keySet(); |
||||
} else { |
||||
return "Missing fields " + missingRequired + "; fieldValues map contained " + sourceValues.keySet(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
/** |
||||
* API for binding submitted field values in a single batch operation. |
||||
*/ |
||||
package org.springframework.model.binder; |
||||
|
||||
@ -1,127 +0,0 @@
@@ -1,127 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
import org.springframework.model.binder.Binder; |
||||
import org.springframework.model.binder.BindingResult; |
||||
import org.springframework.model.binder.BindingResults; |
||||
import org.springframework.model.binder.MissingFieldException; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Base Binder implementation that defines common structural elements. |
||||
* Subclasses should be parameterized & implement {@link #bind(Map, Object)}. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see #setRequiredFields(String[]) |
||||
* @see #setMessageSource(MessageSource) |
||||
* @see #createFieldBinder() |
||||
* @see #bind(Map, Object) |
||||
*/ |
||||
public abstract class AbstractBinder<M> implements Binder<M> { |
||||
|
||||
private MessageSource messageSource; |
||||
|
||||
private String[] requiredFields; |
||||
|
||||
/** |
||||
* Configure the fields for which values must be present in each bind attempt. |
||||
* @param fieldNames the required field names |
||||
* @see MissingFieldException |
||||
*/ |
||||
public void setRequiredFields(String[] fieldNames) { |
||||
this.requiredFields = fieldNames; |
||||
} |
||||
|
||||
/** |
||||
* Configure the MessageSource that resolves localized {@link BindingResult} alert messages. |
||||
* @param messageSource the message source |
||||
*/ |
||||
public void setMessageSource(MessageSource messageSource) { |
||||
Assert.notNull(messageSource, "The MessageSource is required"); |
||||
this.messageSource = messageSource; |
||||
} |
||||
|
||||
/** |
||||
* The configured MessageSource that resolves binding result alert messages. |
||||
*/ |
||||
protected MessageSource getMessageSource() { |
||||
return messageSource; |
||||
} |
||||
|
||||
// Binder implementation
|
||||
|
||||
public final BindingResults bind(Map<String, ? extends Object> fieldValues, M model) { |
||||
fieldValues = filter(fieldValues, model); |
||||
checkRequired(fieldValues); |
||||
FieldBinder fieldBinder = createFieldBinder(model); |
||||
ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size()); |
||||
for (Map.Entry<String, ? extends Object> fieldValue : fieldValues.entrySet()) { |
||||
results.add(fieldBinder.bind(fieldValue.getKey(), fieldValue.getValue())); |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
// subclass hooks
|
||||
|
||||
/** |
||||
* Subclasses must implement this method to create the {@link FieldBinder} |
||||
* instance for the given model. |
||||
*/ |
||||
protected abstract FieldBinder createFieldBinder(M model); |
||||
|
||||
/** |
||||
* Filter the fields to bind. |
||||
* Allows for pre-processing the fieldValues Map before any binding occurs. |
||||
* For example, you might insert empty or default values for fields that are not present. |
||||
* As another example, you might collapse multiple fields into a single field. |
||||
* Default implementation simply returns the fieldValues Map unchanged. |
||||
* @param fieldValues the original fieldValues Map provided by the caller |
||||
* @return the filtered fieldValues Map that will be used to bind |
||||
*/ |
||||
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> fieldValues, M model) { |
||||
return fieldValues; |
||||
} |
||||
|
||||
// internal helpers
|
||||
|
||||
private void checkRequired(Map<String, ? extends Object> fieldValues) { |
||||
if (requiredFields == null) { |
||||
return; |
||||
} |
||||
List<String> missingRequired = new ArrayList<String>(); |
||||
for (String required : requiredFields) { |
||||
boolean found = false; |
||||
for (String property : fieldValues.keySet()) { |
||||
if (property.equals(required)) { |
||||
found = true; |
||||
} |
||||
} |
||||
if (!found) { |
||||
missingRequired.add(required); |
||||
} |
||||
} |
||||
if (!missingRequired.isEmpty()) { |
||||
throw new MissingFieldException(missingRequired, fieldValues); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,56 +0,0 @@
@@ -1,56 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import org.springframework.context.alert.Alert; |
||||
import org.springframework.context.alert.Severity; |
||||
import org.springframework.model.binder.BindingResult; |
||||
|
||||
public class AlertBindingResult implements BindingResult { |
||||
|
||||
private String fieldName; |
||||
|
||||
private Object submittedValue; |
||||
|
||||
private Alert alert; |
||||
|
||||
public AlertBindingResult(String fieldName, Object sourceValue, Alert alert) { |
||||
this.fieldName = fieldName; |
||||
this.submittedValue = sourceValue; |
||||
this.alert = alert; |
||||
} |
||||
|
||||
public String getFieldName() { |
||||
return fieldName; |
||||
} |
||||
|
||||
public Object getSubmittedValue() { |
||||
return submittedValue; |
||||
} |
||||
|
||||
public boolean isFailure() { |
||||
return alert.getSeverity().compareTo(Severity.INFO) > 1; |
||||
} |
||||
|
||||
public Alert getAlert() { |
||||
return alert; |
||||
} |
||||
|
||||
public String toString() { |
||||
return getAlert().toString(); |
||||
} |
||||
|
||||
} |
||||
@ -1,104 +0,0 @@
@@ -1,104 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.context.alert.Severity; |
||||
import org.springframework.model.binder.BindingResult; |
||||
import org.springframework.model.binder.BindingResults; |
||||
|
||||
class ArrayListBindingResults implements BindingResults { |
||||
|
||||
private List<BindingResult> results; |
||||
|
||||
public ArrayListBindingResults() { |
||||
results = new ArrayList<BindingResult>(); |
||||
} |
||||
|
||||
public ArrayListBindingResults(int size) { |
||||
results = new ArrayList<BindingResult>(size); |
||||
} |
||||
|
||||
public void add(BindingResult result) { |
||||
results.add(result); |
||||
} |
||||
|
||||
// implementing Iterable
|
||||
|
||||
public Iterator<BindingResult> iterator() { |
||||
return results.iterator(); |
||||
} |
||||
|
||||
// implementing BindingResults
|
||||
|
||||
public List<BindingResult> successes() { |
||||
List<BindingResult> results = new ArrayList<BindingResult>(); |
||||
for (BindingResult result : this) { |
||||
if (!result.isFailure()) { |
||||
results.add(result); |
||||
} |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
public List<BindingResult> failures() { |
||||
List<BindingResult> results = new ArrayList<BindingResult>(); |
||||
for (BindingResult result : this) { |
||||
if (result.isFailure()) { |
||||
results.add(result); |
||||
} |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
public boolean hasErrors() { |
||||
return errors().size() > 0; |
||||
} |
||||
|
||||
public List<BindingResult> errors() { |
||||
List<BindingResult> results = new ArrayList<BindingResult>(); |
||||
for (BindingResult result : this) { |
||||
if (result.isFailure() && result.getAlert().getSeverity().compareTo(Severity.ERROR) >= 0) { |
||||
results.add(result); |
||||
} |
||||
} |
||||
return results; |
||||
} |
||||
|
||||
public BindingResult get(int index) { |
||||
return results.get(index); |
||||
} |
||||
|
||||
public BindingResult get(String fieldName) { |
||||
for (BindingResult result : results) { |
||||
if (result.getFieldName().equals(fieldName)) { |
||||
return result; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public int size() { |
||||
return results.size(); |
||||
} |
||||
|
||||
public String toString() { |
||||
return "[BindingResults = " + results.toString() + "]"; |
||||
} |
||||
} |
||||
@ -1,35 +0,0 @@
@@ -1,35 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import org.springframework.model.binder.BindingResult; |
||||
|
||||
/** |
||||
* Binder callback interface for binding a single field value. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
* @see AbstractBinder#createFieldBinder(Object) |
||||
*/ |
||||
public interface FieldBinder { |
||||
|
||||
/** |
||||
* Bind a single field. |
||||
* @param fieldName the field name |
||||
* @param value the field value |
||||
* @return the binding result |
||||
*/ |
||||
BindingResult bind(String fieldName, Object value); |
||||
} |
||||
@ -1,86 +0,0 @@
@@ -1,86 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
import org.springframework.context.alert.Alert; |
||||
import org.springframework.context.alert.Severity; |
||||
import org.springframework.context.message.DefaultMessageFactory; |
||||
import org.springframework.context.message.MessageBuilder; |
||||
import org.springframework.context.message.ResolvableArgument; |
||||
import org.springframework.model.binder.BindingResult; |
||||
|
||||
/** |
||||
* Indicates a field failed to bind because it was not editable/writeable. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public class FieldNotEditableResult implements BindingResult { |
||||
|
||||
private String fieldName; |
||||
|
||||
private Object submittedValue; |
||||
|
||||
private MessageSource messageSource; |
||||
|
||||
public FieldNotEditableResult(String fieldName, Object submittedValue, MessageSource messageSource) { |
||||
this.fieldName = fieldName; |
||||
this.submittedValue = submittedValue; |
||||
this.messageSource = messageSource; |
||||
} |
||||
|
||||
public String getFieldName() { |
||||
return fieldName; |
||||
} |
||||
|
||||
public Object getSubmittedValue() { |
||||
return submittedValue; |
||||
} |
||||
|
||||
public boolean isFailure() { |
||||
return true; |
||||
} |
||||
|
||||
public Alert getAlert() { |
||||
return new Alert() { |
||||
public String getCode() { |
||||
return "fieldNotEditable"; |
||||
} |
||||
|
||||
public Severity getSeverity() { |
||||
return Severity.WARNING; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
MessageBuilder builder = new MessageBuilder(messageSource); |
||||
builder.code(getCode()); |
||||
builder.arg("label", new ResolvableArgument(fieldName)); |
||||
builder.arg("value", submittedValue); |
||||
builder.defaultMessage(new DefaultMessageFactory() { |
||||
public String createDefaultMessage() { |
||||
return "Failed to bind submitted value " + submittedValue + "; field '" + fieldName + "' is not editable"; |
||||
} |
||||
}); |
||||
return builder.build(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public String toString() { |
||||
return getAlert().toString(); |
||||
} |
||||
|
||||
} |
||||
@ -1,86 +0,0 @@
@@ -1,86 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
import org.springframework.context.alert.Alert; |
||||
import org.springframework.context.alert.Severity; |
||||
import org.springframework.context.message.DefaultMessageFactory; |
||||
import org.springframework.context.message.MessageBuilder; |
||||
import org.springframework.context.message.ResolvableArgument; |
||||
import org.springframework.model.binder.BindingResult; |
||||
|
||||
/** |
||||
* Indicates field failed to bind because it was not found. |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public class FieldNotFoundResult implements BindingResult { |
||||
|
||||
private String fieldName; |
||||
|
||||
private Object submittedValue; |
||||
|
||||
private MessageSource messageSource; |
||||
|
||||
public FieldNotFoundResult(String fieldName, Object submittedValue, MessageSource messageSource) { |
||||
this.fieldName = fieldName; |
||||
this.submittedValue = submittedValue; |
||||
this.messageSource = messageSource; |
||||
} |
||||
|
||||
public String getFieldName() { |
||||
return fieldName; |
||||
} |
||||
|
||||
public Object getSubmittedValue() { |
||||
return submittedValue; |
||||
} |
||||
|
||||
public boolean isFailure() { |
||||
return true; |
||||
} |
||||
|
||||
public Alert getAlert() { |
||||
return new Alert() { |
||||
public String getCode() { |
||||
return "fieldNotFound"; |
||||
} |
||||
|
||||
public Severity getSeverity() { |
||||
return Severity.WARNING; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
MessageBuilder builder = new MessageBuilder(messageSource); |
||||
builder.code(getCode()); |
||||
builder.arg("label", new ResolvableArgument(fieldName)); |
||||
builder.arg("value", submittedValue); |
||||
builder.defaultMessage(new DefaultMessageFactory() { |
||||
public String createDefaultMessage() { |
||||
return "Failed to bind submitted value " + submittedValue + "; no field '" + fieldName + "' found"; |
||||
} |
||||
}); |
||||
return builder.build(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public String toString() { |
||||
return getAlert().toString(); |
||||
} |
||||
|
||||
} |
||||
@ -1,212 +0,0 @@
@@ -1,212 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import org.springframework.context.MessageSource; |
||||
import org.springframework.context.alert.Alert; |
||||
import org.springframework.context.alert.Severity; |
||||
import org.springframework.context.expression.MapAccessor; |
||||
import org.springframework.context.message.DefaultMessageFactory; |
||||
import org.springframework.context.message.MessageBuilder; |
||||
import org.springframework.context.message.ResolvableArgument; |
||||
import org.springframework.core.convert.ConversionFailedException; |
||||
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.spel.SpelEvaluationException; |
||||
import org.springframework.expression.spel.SpelMessage; |
||||
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||
import org.springframework.expression.spel.standard.SpelExpressionParserConfiguration; |
||||
import org.springframework.expression.spel.support.StandardEvaluationContext; |
||||
import org.springframework.model.binder.Binder; |
||||
import org.springframework.model.binder.BindingResult; |
||||
|
||||
/** |
||||
* A {@link Binder} implementation that accepts any target object and uses |
||||
* Spring's Expression Language (SpEL) to evaluate the keys in the field value Map. |
||||
* @author Mark Fisher |
||||
* @author Keith Donald |
||||
* @since 3.0 |
||||
*/ |
||||
public class GenericBinder extends AbstractBinder<Object> { |
||||
|
||||
private final ExpressionParser expressionParser = new SpelExpressionParser( |
||||
SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull |
||||
| SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize); |
||||
|
||||
@Override |
||||
protected FieldBinder createFieldBinder(Object model) { |
||||
StandardEvaluationContext context = new StandardEvaluationContext(); |
||||
context.addPropertyAccessor(new MapAccessor()); |
||||
context.setRootObject(model); |
||||
return new ExpressionFieldBinder(getMessageSource(), expressionParser, context); |
||||
} |
||||
|
||||
private static class ExpressionFieldBinder implements FieldBinder { |
||||
|
||||
private final MessageSource messageSource; |
||||
|
||||
private final ExpressionParser expressionParser; |
||||
|
||||
private final EvaluationContext evaluationContext; |
||||
|
||||
private ExpressionFieldBinder(MessageSource messageSource, ExpressionParser expressionParser, |
||||
EvaluationContext evaluationContext) { |
||||
this.messageSource = messageSource; |
||||
this.expressionParser = expressionParser; |
||||
this.evaluationContext = evaluationContext; |
||||
} |
||||
|
||||
public BindingResult bind(String fieldName, Object value) { |
||||
Alert alert = null; |
||||
try { |
||||
Expression exp = expressionParser.parseExpression(fieldName); |
||||
if (!exp.isWritable(evaluationContext)) { |
||||
return new FieldNotEditableResult(fieldName, value, messageSource); |
||||
} |
||||
exp.setValue(evaluationContext, value); |
||||
alert = new BindSuccessAlert(fieldName, value, messageSource); |
||||
} catch (ParseException e) { |
||||
alert = new InternalErrorAlert(e); |
||||
} catch (EvaluationException e) { |
||||
SpelEvaluationException spelException = (SpelEvaluationException) e; |
||||
if (spelException.getMessageCode() == SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE) { |
||||
ConversionFailedException conversionFailure = findConversionFailureCause(spelException); |
||||
if (conversionFailure != null) { |
||||
alert = new TypeMismatchAlert(fieldName, value, conversionFailure, messageSource); |
||||
} |
||||
} |
||||
if (alert == null) { |
||||
alert = new InternalErrorAlert(e); |
||||
} |
||||
} |
||||
return new AlertBindingResult(fieldName, value, alert); |
||||
} |
||||
|
||||
private ConversionFailedException findConversionFailureCause(Exception e) { |
||||
Throwable cause = e.getCause(); |
||||
while (cause != null) { |
||||
if (cause instanceof ConversionFailedException) { |
||||
return (ConversionFailedException) cause; |
||||
} |
||||
cause = cause.getCause(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
|
||||
private static class BindSuccessAlert implements Alert { |
||||
|
||||
private final String fieldName; |
||||
|
||||
private final Object value; |
||||
|
||||
private MessageSource messageSource; |
||||
|
||||
public BindSuccessAlert(String fieldName, Object value, MessageSource messageSource) { |
||||
this.fieldName = fieldName; |
||||
this.value = value; |
||||
this.messageSource = messageSource; |
||||
} |
||||
|
||||
public String getCode() { |
||||
return "bindSuccess"; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
MessageBuilder builder = new MessageBuilder(messageSource); |
||||
builder.code(getCode()); |
||||
builder.arg("label", new ResolvableArgument(fieldName)); |
||||
builder.arg("value", value); |
||||
builder.defaultMessage(new DefaultMessageFactory() { |
||||
public String createDefaultMessage() { |
||||
return "Successfully bound submitted value " + value + " to field '" + fieldName + "'"; |
||||
} |
||||
}); |
||||
return builder.build(); |
||||
} |
||||
|
||||
public Severity getSeverity() { |
||||
return Severity.INFO; |
||||
} |
||||
} |
||||
|
||||
private static class TypeMismatchAlert implements Alert { |
||||
|
||||
private final String fieldName; |
||||
|
||||
private final Object value; |
||||
|
||||
private final ConversionFailedException cause; |
||||
|
||||
private MessageSource messageSource; |
||||
|
||||
public TypeMismatchAlert(String fieldName, Object value, ConversionFailedException cause, |
||||
MessageSource messageSource) { |
||||
this.fieldName = fieldName; |
||||
this.value = value; |
||||
this.cause = cause; |
||||
this.messageSource = messageSource; |
||||
} |
||||
|
||||
public String getCode() { |
||||
return "typeMismatch"; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
MessageBuilder builder = new MessageBuilder(messageSource); |
||||
builder.code(getCode()); |
||||
builder.arg("label", new ResolvableArgument(fieldName)); |
||||
builder.arg("value", value); |
||||
builder.defaultMessage(new DefaultMessageFactory() { |
||||
public String createDefaultMessage() { |
||||
return "Failed to bind submitted value " + value + " to field '" + fieldName |
||||
+ "'; value could not be converted to type [" + cause.getTargetType().getName() + "]"; |
||||
} |
||||
}); |
||||
return builder.build(); |
||||
} |
||||
|
||||
public Severity getSeverity() { |
||||
return Severity.ERROR; |
||||
} |
||||
} |
||||
|
||||
private static class InternalErrorAlert implements Alert { |
||||
|
||||
private final Exception cause; |
||||
|
||||
public InternalErrorAlert(Exception cause) { |
||||
this.cause = cause; |
||||
} |
||||
|
||||
public String getCode() { |
||||
return "internalError"; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
return "An internal error occurred; message = [" + cause.getMessage() + "]"; |
||||
} |
||||
|
||||
public Severity getSeverity() { |
||||
return Severity.FATAL; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
/** |
||||
* Binder API implementation support. |
||||
*/ |
||||
package org.springframework.model.binder.support; |
||||
|
||||
@ -1,34 +0,0 @@
@@ -1,34 +0,0 @@
|
||||
package org.springframework.context.alert; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.springframework.context.alert.Alerts.error; |
||||
import static org.springframework.context.alert.Alerts.fatal; |
||||
import static org.springframework.context.alert.Alerts.info; |
||||
import static org.springframework.context.alert.Alerts.warning; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.context.alert.Alert; |
||||
import org.springframework.context.alert.Severity; |
||||
|
||||
public class AlertsTests { |
||||
|
||||
@Test |
||||
public void testFactoryMethods() { |
||||
Alert a1 = info("alert 1"); |
||||
assertEquals(Severity.INFO, a1.getSeverity()); |
||||
assertEquals("alert 1", a1.getMessage()); |
||||
|
||||
Alert a2 = warning("alert 2"); |
||||
assertEquals(Severity.WARNING, a2.getSeverity()); |
||||
assertEquals("alert 2", a2.getMessage()); |
||||
|
||||
Alert a3 = error("alert 3"); |
||||
assertEquals(Severity.ERROR, a3.getSeverity()); |
||||
assertEquals("alert 3", a3.getMessage()); |
||||
|
||||
Alert a4 = fatal("alert 4"); |
||||
assertEquals(Severity.FATAL, a4.getSeverity()); |
||||
assertEquals("alert 4", a4.getMessage()); |
||||
|
||||
} |
||||
} |
||||
@ -1,39 +0,0 @@
@@ -1,39 +0,0 @@
|
||||
package org.springframework.context.alert.support; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.context.alert.Alert; |
||||
import org.springframework.context.alert.Severity; |
||||
import org.springframework.context.alert.support.DefaultAlertContext; |
||||
|
||||
public class DefaultAlertContextTests { |
||||
|
||||
private DefaultAlertContext context; |
||||
|
||||
@Before |
||||
public void setUp() { |
||||
context = new DefaultAlertContext(); |
||||
} |
||||
|
||||
@Test |
||||
public void addAlert() { |
||||
Alert alert = new Alert() { |
||||
public String getCode() { |
||||
return "invalidFormat"; |
||||
} |
||||
|
||||
public String getMessage() { |
||||
return "Please enter a value in format yyyy-dd-mm"; |
||||
} |
||||
|
||||
public Severity getSeverity() { |
||||
return Severity.ERROR; |
||||
} |
||||
}; |
||||
context.add("form.property", alert); |
||||
assertEquals(1, context.getAlerts().size()); |
||||
assertEquals("invalidFormat", context.getAlerts("form.property").get(0).getCode()); |
||||
} |
||||
} |
||||
@ -1,23 +0,0 @@
@@ -1,23 +0,0 @@
|
||||
package org.springframework.context.message; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.context.message.MessageBuilder; |
||||
import org.springframework.context.message.ResolvableArgument; |
||||
|
||||
public class MessageBuilderTests { |
||||
|
||||
@Test |
||||
public void buildMessage() { |
||||
MockMessageSource messageSource = new MockMessageSource(); |
||||
messageSource.addMessage("invalidFormat", Locale.US, "#{label} must be in format #{format}"); |
||||
messageSource.addMessage("mathForm.decimalField", Locale.US, "Decimal Field"); |
||||
MessageBuilder builder = new MessageBuilder(messageSource); |
||||
String message = builder.code("invalidFormat").arg("label", new ResolvableArgument("mathForm.decimalField")) |
||||
.arg("format", "#,###.##").locale(Locale.US).defaultMessage("Field must be in format #,###.##").build(); |
||||
assertEquals("Decimal Field must be in format #,###.##", message); |
||||
} |
||||
} |
||||
@ -1,26 +0,0 @@
@@ -1,26 +0,0 @@
|
||||
package org.springframework.context.message; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.context.message.MessageResolver; |
||||
import org.springframework.context.message.MessageResolverBuilder; |
||||
import org.springframework.context.message.ResolvableArgument; |
||||
|
||||
public class MessageResolverBuilderTests { |
||||
|
||||
private MessageResolverBuilder builder = new MessageResolverBuilder(); |
||||
|
||||
@Test |
||||
public void buildMessage() { |
||||
MessageResolver resolver = builder.code("invalidFormat").arg("label", new ResolvableArgument("mathForm.decimalField")) |
||||
.arg("format", "#,###.##").defaultMessage("Field must be in format #,###.##").build(); |
||||
MockMessageSource messageSource = new MockMessageSource(); |
||||
messageSource.addMessage("invalidFormat", Locale.US, "#{label} must be in format #{format}"); |
||||
messageSource.addMessage("mathForm.decimalField", Locale.US, "Decimal Field"); |
||||
String message = resolver.resolveMessage(messageSource, Locale.US); |
||||
assertEquals("Decimal Field must be in format #,###.##", message); |
||||
} |
||||
} |
||||
@ -1,47 +0,0 @@
@@ -1,47 +0,0 @@
|
||||
package org.springframework.context.message; |
||||
|
||||
import java.text.MessageFormat; |
||||
import java.util.HashMap; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.context.support.AbstractMessageSource; |
||||
import org.springframework.util.Assert; |
||||
|
||||
public class MockMessageSource extends AbstractMessageSource { |
||||
|
||||
/** Map from 'code + locale' keys to message Strings */ |
||||
private final Map<String, String> messages = new HashMap<String, String>(); |
||||
|
||||
@Override |
||||
protected MessageFormat resolveCode(String code, Locale locale) { |
||||
throw new IllegalStateException("Should not be called"); |
||||
} |
||||
|
||||
@Override |
||||
protected String resolveCodeWithoutArguments(String code, Locale locale) { |
||||
return this.messages.get(code + "_" + locale.toString()); |
||||
} |
||||
|
||||
/** |
||||
* Associate the given message with the given code. |
||||
* @param code the lookup code |
||||
* * @param locale the locale that the message should be found within |
||||
* @param msg the message associated with this lookup code |
||||
*/ |
||||
public void addMessage(String code, Locale locale, String msg) { |
||||
Assert.notNull(code, "Code must not be null"); |
||||
Assert.notNull(locale, "Locale must not be null"); |
||||
Assert.notNull(msg, "Message must not be null"); |
||||
this.messages.put(code + "_" + locale.toString(), msg); |
||||
if (logger.isDebugEnabled()) { |
||||
logger.debug("Added message [" + msg + "] for code [" + code + "] and Locale [" + locale + "]"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return getClass().getName() + ": " + this.messages; |
||||
} |
||||
|
||||
} |
||||
@ -1,149 +0,0 @@
@@ -1,149 +0,0 @@
|
||||
package org.springframework.mapping.support; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.mapping.MappingException; |
||||
import org.springframework.mapping.support.SpelMapper; |
||||
|
||||
public class SpelMapperTests { |
||||
|
||||
private SpelMapper mapper = new SpelMapper(); |
||||
|
||||
@Test |
||||
public void mapAutomatic() { |
||||
Map<String, Object> source = new HashMap<String, Object>(); |
||||
source.put("name", "Keith"); |
||||
source.put("age", 31); |
||||
|
||||
Person target = new Person(); |
||||
|
||||
mapper.map(source, target); |
||||
|
||||
assertEquals("Keith", target.name); |
||||
assertEquals(31, target.age); |
||||
} |
||||
|
||||
@Test |
||||
public void mapExplicit() throws MappingException { |
||||
mapper.setAutoMappingEnabled(false); |
||||
mapper.addMapping("name", "name"); |
||||
|
||||
Map<String, Object> source = new HashMap<String, Object>(); |
||||
source.put("name", "Keith"); |
||||
source.put("age", 31); |
||||
|
||||
Person target = new Person(); |
||||
|
||||
mapper.map(source, target); |
||||
|
||||
assertEquals("Keith", target.name); |
||||
assertEquals(0, target.age); |
||||
} |
||||
|
||||
@Test |
||||
public void mapAutomaticWithExplictOverrides() { |
||||
mapper.addMapping("test", "age"); |
||||
|
||||
Map<String, Object> source = new HashMap<String, Object>(); |
||||
source.put("name", "Keith"); |
||||
source.put("test", "3"); |
||||
source.put("favoriteSport", "FOOTBALL"); |
||||
|
||||
Person target = new Person(); |
||||
|
||||
mapper.map(source, target); |
||||
|
||||
assertEquals("Keith", target.name); |
||||
assertEquals(3, target.age); |
||||
assertEquals(Sport.FOOTBALL, target.favoriteSport); |
||||
} |
||||
|
||||
@Test |
||||
public void mapSameSourceFieldToMultipleTargets() { |
||||
mapper.addMapping("test", "name"); |
||||
mapper.addMapping("test", "favoriteSport"); |
||||
|
||||
Map<String, Object> source = new HashMap<String, Object>(); |
||||
source.put("test", "FOOTBALL"); |
||||
|
||||
Person target = new Person(); |
||||
|
||||
mapper.map(source, target); |
||||
|
||||
assertEquals("FOOTBALL", target.name); |
||||
assertEquals(0, target.age); |
||||
assertEquals(Sport.FOOTBALL, target.favoriteSport); |
||||
} |
||||
|
||||
@Test |
||||
public void bean() { |
||||
|
||||
} |
||||
|
||||
|
||||
public static class Employee { |
||||
|
||||
private String name; |
||||
|
||||
private int age; |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public int getAge() { |
||||
return age; |
||||
} |
||||
|
||||
public void setAge(int age) { |
||||
this.age = age; |
||||
} |
||||
|
||||
} |
||||
|
||||
public static class Person { |
||||
|
||||
private String name; |
||||
|
||||
private int age; |
||||
|
||||
private Sport favoriteSport; |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public int getAge() { |
||||
return age; |
||||
} |
||||
|
||||
public void setAge(int age) { |
||||
this.age = age; |
||||
} |
||||
|
||||
public Sport getFavoriteSport() { |
||||
return favoriteSport; |
||||
} |
||||
|
||||
public void setFavoriteSport(Sport favoriteSport) { |
||||
this.favoriteSport = favoriteSport; |
||||
} |
||||
|
||||
} |
||||
|
||||
public enum Sport { |
||||
FOOTBALL, BASKETBALL |
||||
} |
||||
} |
||||
@ -1,278 +0,0 @@
@@ -1,278 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2009 the original author or authors. |
||||
* |
||||
* Licensed 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.springframework.model.binder.support; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertNotNull; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.context.alert.Severity; |
||||
import org.springframework.context.i18n.LocaleContextHolder; |
||||
import org.springframework.context.message.MockMessageSource; |
||||
import org.springframework.core.style.ToStringCreator; |
||||
import org.springframework.model.binder.Binder; |
||||
import org.springframework.model.binder.BindingResults; |
||||
import org.springframework.model.binder.MissingFieldException; |
||||
|
||||
/** |
||||
* @author Mark Fisher |
||||
* @since 3.0 |
||||
*/ |
||||
public class GenericBinderTests { |
||||
|
||||
@Test |
||||
public void simpleValues() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new LinkedHashMap<String, Object>(); |
||||
map.put("name", "John Doe"); |
||||
map.put("age", 42); |
||||
map.put("male", true); |
||||
Binder<Object> binder = new GenericBinder(); |
||||
|
||||
BindingResults results = binder.bind(map, person); |
||||
assertEquals(3, results.size()); |
||||
assertEquals(3, results.successes().size()); |
||||
assertEquals(0, results.failures().size()); |
||||
assertEquals(0, results.errors().size()); |
||||
assertEquals("name", results.get(0).getFieldName()); |
||||
assertEquals("John Doe", results.get(0).getSubmittedValue()); |
||||
assertEquals(false, results.get(0).isFailure()); |
||||
assertEquals(Severity.INFO, results.get(0).getAlert().getSeverity()); |
||||
assertEquals("bindSuccess", results.get(0).getAlert().getCode()); |
||||
assertEquals("Successfully bound submitted value John Doe to field 'name'", results.get(0).getAlert().getMessage()); |
||||
assertEquals("name", results.get("name").getFieldName()); |
||||
assertEquals("John Doe", results.get("name").getSubmittedValue()); |
||||
|
||||
assertEquals("John Doe", person.name); |
||||
assertEquals(42, person.age); |
||||
assertTrue(person.male); |
||||
} |
||||
|
||||
@Test |
||||
public void nestedValues() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
map.put("pob.city", "Rome"); |
||||
map.put("pob.country", "Italy"); |
||||
Binder<Object> binder = new GenericBinder(); |
||||
binder.bind(map, person); |
||||
assertNotNull(person.pob); |
||||
assertEquals("Rome", person.pob.city); |
||||
assertEquals("Italy", person.pob.country); |
||||
} |
||||
|
||||
@Test |
||||
public void mapValues() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
map.put("jobHistory['0']", "Clerk"); |
||||
map.put("jobHistory['1']", "Plumber"); |
||||
Binder<Object> binder = new GenericBinder(); |
||||
binder.bind(map, person); |
||||
assertEquals("Clerk", person.jobHistory.get(0)); |
||||
assertEquals("Plumber", person.jobHistory.get(1)); |
||||
} |
||||
|
||||
@Test |
||||
public void typeMismatch() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
map.put("male", "bogus"); |
||||
Binder<Object> binder = new GenericBinder(); |
||||
BindingResults results = binder.bind(map, person); |
||||
assertEquals(1, results.size()); |
||||
assertEquals(0, results.successes().size()); |
||||
assertEquals(1, results.failures().size()); |
||||
assertEquals(1, results.errors().size()); |
||||
assertEquals("bogus", results.get(0).getSubmittedValue()); |
||||
assertEquals("typeMismatch", results.get(0).getAlert().getCode()); |
||||
assertEquals(Severity.ERROR, results.get(0).getAlert().getSeverity()); |
||||
assertEquals("Failed to bind submitted value bogus to field 'male'; value could not be converted to type [boolean]", results.get(0).getAlert().getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void internalError() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
map.put("bogus", "bogus"); |
||||
Binder<Object> binder = new GenericBinder(); |
||||
BindingResults results = binder.bind(map, person); |
||||
assertEquals(1, results.size()); |
||||
assertEquals(0, results.successes().size()); |
||||
assertEquals(1, results.failures().size()); |
||||
assertEquals(1, results.errors().size()); |
||||
assertEquals("bogus", results.get(0).getSubmittedValue()); |
||||
assertEquals("internalError", results.get(0).getAlert().getCode()); |
||||
assertEquals(Severity.FATAL, results.get(0).getAlert().getSeverity()); |
||||
assertEquals("An internal error occurred; message = [EL1034E:(pos 0): A problem occurred whilst attempting to set the property 'bogus': Unable to access property 'bogus' through setter]", results.get(0).getAlert().getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void fieldNotEditable() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
map.put("readOnly", "whatever"); |
||||
Binder<Object> binder = new GenericBinder(); |
||||
BindingResults results = binder.bind(map, person); |
||||
assertEquals(1, results.size()); |
||||
assertEquals(0, results.successes().size()); |
||||
assertEquals(1, results.failures().size()); |
||||
assertEquals(0, results.errors().size()); |
||||
assertEquals("whatever", results.get(0).getSubmittedValue()); |
||||
assertEquals("fieldNotEditable", results.get(0).getAlert().getCode()); |
||||
assertEquals(Severity.WARNING, results.get(0).getAlert().getSeverity()); |
||||
assertEquals("Failed to bind submitted value whatever; field 'readOnly' is not editable", results.get(0).getAlert().getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void messageSource() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
map.put("male", "bogus"); |
||||
GenericBinder binder = new GenericBinder(); |
||||
MockMessageSource messageSource = new MockMessageSource(); |
||||
messageSource.addMessage("typeMismatch", Locale.US, "Please enter true or false for the value of the #{label} field; you entered #{value}"); |
||||
binder.setMessageSource(messageSource); |
||||
LocaleContextHolder.setLocale(Locale.US); |
||||
BindingResults results = binder.bind(map, person); |
||||
assertEquals("Please enter true or false for the value of the male field; you entered bogus", results.get(0).getAlert().getMessage()); |
||||
LocaleContextHolder.setLocale(null); |
||||
} |
||||
|
||||
@Test |
||||
public void missingFields() { |
||||
Person person = new Person(); |
||||
Map<String, Object> map = new HashMap<String, Object>(); |
||||
GenericBinder binder = new GenericBinder(); |
||||
binder.setRequiredFields(new String[] { "name", "age", "male" }); |
||||
try { |
||||
binder.bind(map, person); |
||||
} catch (MissingFieldException e) { |
||||
assertEquals(3, e.getMissing().size()); |
||||
assertEquals("name", e.getMissing().get(0)); |
||||
assertEquals("age", e.getMissing().get(1)); |
||||
assertEquals("male", e.getMissing().get(2)); |
||||
} |
||||
} |
||||
|
||||
public static class Person { |
||||
|
||||
private String name; |
||||
|
||||
private int age; |
||||
|
||||
private boolean male; |
||||
|
||||
private PlaceOfBirth pob; |
||||
|
||||
private Map<Integer, String> jobHistory; |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public int getAge() { |
||||
return age; |
||||
} |
||||
|
||||
public void setAge(int age) { |
||||
this.age = age; |
||||
} |
||||
|
||||
public boolean isMale() { |
||||
return male; |
||||
} |
||||
|
||||
public void setMale(boolean male) { |
||||
this.male = male; |
||||
} |
||||
|
||||
public PlaceOfBirth getPob() { |
||||
return pob; |
||||
} |
||||
|
||||
public void setPob(PlaceOfBirth pob) { |
||||
this.pob = pob; |
||||
} |
||||
|
||||
public Map<Integer, String> getJobHistory() { |
||||
return jobHistory; |
||||
} |
||||
|
||||
public void setJobHistory(Map<Integer, String> jobHistory) { |
||||
this.jobHistory = jobHistory; |
||||
} |
||||
|
||||
public void setBogus(String bogus) { |
||||
throw new RuntimeException("internal error"); |
||||
} |
||||
|
||||
public boolean isReadOnly() { |
||||
return true; |
||||
} |
||||
|
||||
public String toString() { |
||||
return new ToStringCreator(this) |
||||
.append("name", name) |
||||
.append("age", age) |
||||
.append("male", male) |
||||
.append("pob", pob) |
||||
.toString(); |
||||
} |
||||
} |
||||
|
||||
|
||||
public static class PlaceOfBirth { |
||||
|
||||
private String city; |
||||
|
||||
private String country; |
||||
|
||||
public String getCity() { |
||||
return city; |
||||
} |
||||
|
||||
public void setCity(String city) { |
||||
this.city = city; |
||||
} |
||||
|
||||
public String getCountry() { |
||||
return country; |
||||
} |
||||
|
||||
public void setCountry(String country) { |
||||
this.country = country; |
||||
} |
||||
|
||||
public String toString() { |
||||
return new ToStringCreator(this) |
||||
.append("city", city) |
||||
.append("country", country) |
||||
.toString(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue