From 3f31a1cf756207947eb56ad211c2c1345aef727e Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 28 Jun 2010 22:08:31 +0000 Subject: [PATCH] added "validationMessageSource" property to LocalValidatorFactoryBean, for Spring-based messages (SPR-7307) --- org.springframework.context/context.iml | 16 +++--- org.springframework.context/ivy.xml | 2 +- .../beanvalidation/CustomValidatorBean.java | 9 ++- .../LocalValidatorFactoryBean.java | 42 +++++++++++++- .../LocaleContextMessageInterpolator.java | 6 +- .../MessageSourceResourceBundleLocator.java | 55 +++++++++++++++++++ org.springframework.context/template.mf | 1 + 7 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java diff --git a/org.springframework.context/context.iml b/org.springframework.context/context.iml index 4d96df6091..2ab9dfca2e 100644 --- a/org.springframework.context/context.iml +++ b/org.springframework.context/context.iml @@ -113,44 +113,44 @@ - + - + - + - + - + - + - + - + diff --git a/org.springframework.context/ivy.xml b/org.springframework.context/ivy.xml index 9519b0587e..ebbdf33465 100644 --- a/org.springframework.context/ivy.xml +++ b/org.springframework.context/ivy.xml @@ -46,6 +46,7 @@ + @@ -62,7 +63,6 @@ - diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java index 63961d3d4e..bde13ced82 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -71,8 +71,11 @@ public class CustomValidatorBean extends SpringValidatorAdapter implements Valid } ValidatorContext validatorContext = this.validatorFactory.usingContext(); - validatorContext.messageInterpolator(new LocaleContextMessageInterpolator( - this.messageInterpolator, this.validatorFactory.getMessageInterpolator())); + MessageInterpolator targetInterpolator = this.messageInterpolator; + if (targetInterpolator == null) { + targetInterpolator = this.validatorFactory.getMessageInterpolator(); + } + validatorContext.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator)); if (this.traversableResolver != null) { validatorContext.traversableResolver(this.traversableResolver); } diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java index da59c63f8d..de7a73bc69 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -30,9 +30,12 @@ import javax.validation.ValidatorContext; import javax.validation.ValidatorFactory; import javax.validation.spi.ValidationProvider; +import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; + import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.MessageSource; import org.springframework.core.io.Resource; import org.springframework.util.CollectionUtils; @@ -94,6 +97,25 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter this.messageInterpolator = messageInterpolator; } + /** + * Specify a custom Spring MessageSource for resolving validation messages, + * instead of relying on JSR-303's default "ValidationMessages.properties" bundle + * in the classpath. This may refer to a Spring context's shared "messageSource" bean, + * or to some special MessageSource setup for validation purposes only. + *

NOTE: This feature requires Hibernate Validator 4.1 or higher on the classpath. + * You may nevertheless use a different validation provider but Hibernate Validator's + * {@link ResourceBundleMessageInterpolator} class must be accessible during configuration. + *

Specify either this property or {@link #setMessageInterpolator "messageInterpolator"}, + * not both. If you would like to build a custom MessageInterpolator, consider deriving from + * Hibernate Validator's {@link ResourceBundleMessageInterpolator} and passing in a + * Spring {@link MessageSourceResourceBundleLocator} when constructing your interpolator. + * @see ResourceBundleMessageInterpolator + * @see MessageSourceResourceBundleLocator + */ + public void setValidationMessageSource(MessageSource messageSource) { + this.messageInterpolator = HibernateValidatorDelegate.buildMessageInterpolator(messageSource); + } + /** * Specify a custom TraversableResolver to use for this ValidatorFactory * and its exposed default Validator. @@ -160,8 +182,11 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter Validation.byProvider(this.providerClass).configure() : Validation.byDefaultProvider().configure()); - configuration.messageInterpolator(new LocaleContextMessageInterpolator( - this.messageInterpolator, configuration.getDefaultMessageInterpolator())); + MessageInterpolator targetInterpolator = this.messageInterpolator; + if (targetInterpolator == null) { + targetInterpolator = configuration.getDefaultMessageInterpolator(); + } + configuration.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator)); if (this.traversableResolver != null) { configuration.traversableResolver(this.traversableResolver); @@ -216,4 +241,15 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter return this.validatorFactory.getConstraintValidatorFactory(); } + + /** + * Inner class to avoid a hard-coded Hibernate Validator 4.1 dependency. + */ + private static class HibernateValidatorDelegate { + + public static MessageInterpolator buildMessageInterpolator(MessageSource messageSource) { + return new ResourceBundleMessageInterpolator(new MessageSourceResourceBundleLocator(messageSource)); + } + } + } diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java index 657bd2cf50..1bab6a4aa7 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -44,10 +44,6 @@ public class LocaleContextMessageInterpolator implements MessageInterpolator { this.targetInterpolator = targetInterpolator; } - LocaleContextMessageInterpolator(MessageInterpolator customInterpolator, MessageInterpolator defaultInterpolator) { - this.targetInterpolator = (customInterpolator != null ? customInterpolator : defaultInterpolator); - } - public String interpolate(String message, Context context) { return this.targetInterpolator.interpolate(message, context, LocaleContextHolder.getLocale()); diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java new file mode 100644 index 0000000000..cf9177c9ed --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2010 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.validation.beanvalidation; + +import java.util.Locale; +import java.util.ResourceBundle; + +import org.hibernate.validator.resourceloading.ResourceBundleLocator; + +import org.springframework.context.MessageSource; +import org.springframework.context.support.MessageSourceResourceBundle; +import org.springframework.util.Assert; + +/** + * Implementation of Hibernate Validator 4.1's {@link ResourceBundleLocator} interface, + * exposing a Spring {@link MessageSource} as localized {@link MessageSourceResourceBundle}. + * + * @author Juergen Hoeller + * @since 3.0.4 + * @see ResourceBundleLocator + * @see MessageSource + * @see MessageSourceResourceBundle + */ +public class MessageSourceResourceBundleLocator implements ResourceBundleLocator { + + private final MessageSource messageSource; + + /** + * Build a MessageSourceResourceBundleLocator for the given MessageSource. + * @param messageSource the Spring MessageSource to wrap + */ + public MessageSourceResourceBundleLocator(MessageSource messageSource) { + Assert.notNull(messageSource, "MessageSource must not be null"); + this.messageSource = messageSource; + } + + public ResourceBundle getResourceBundle(Locale locale) { + return new MessageSourceResourceBundle(this.messageSource, locale); + } + +} diff --git a/org.springframework.context/template.mf b/org.springframework.context/template.mf index cc90f89c69..0520294124 100644 --- a/org.springframework.context/template.mf +++ b/org.springframework.context/template.mf @@ -27,6 +27,7 @@ Import-Template: org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", org.aspectj.weaver.*;version=${aj.osgi.range};resolution:=optional, org.codehaus.groovy.*;version="[1.5.0, 2.0.0)";resolution:=optional, + org.hibernate.validator.*;version="[4.1.0, 5.0.0)";resolution:=optional, org.joda.*;version="[1.6.0, 2.0.0)";resolution:=optional, org.jruby.*;version="[1.1.0, 2.0.0)";resolution:=optional, org.omg.CORBA.*;version="0";resolution:=optional,