Reputation: 65
I have an application using JSF 2.2 (with primefaces) in the front layer and Spring 4 on the business layer.
I am using Tomcat 7.
I am not using Spring MVC. Presentation Layer is pure JSF and I access Spring beans using @ManagedProperty(#{someSpringBean})
I am using JSR-349 for client and server side validation. I have my ValidationMessages.properties on the classpath.
On client side validation there is no problem because Primefaces manages everything.
On Facade layer (server side method validation) I need Spring to interpolate validation messages using JSF current locale (FacesContext.getCurrentInstance().getViewRoot().getLocale()).
It's worth saying that the users of my application are allowed to change locale through menu option.
So, how can I make Spring use JSF locale when interpolating messages in server side validation?
I'll give you some code so you can understand better my needs:
JSF Bean
@ManagedBean
@ViewScoped
public class RegisterBean {
@ManagedProperty(value = "#{partnerServiceFacade}")
private PartnerServiceFacade partnerServiceFacade;
// properties...
public String registerPartner() {
...
partner = partnerServiceFacade.registerPartner(partner);
}
}
Facade interface:
@Validated
public interface PartnerServiceFacade {
@PreAuthorize("hasRole('ROLE_USER')")
public Partner registerPartner(@Valid Partner toRegister);
//Other methods
}
JPA Entity:
@Entity
@Table(name = DBConstants.TABLE_PARTNER)
@Inheritance(strategy = InheritanceType.JOINED)
public class Partner extends XWeedDBEntity {
private static final long serialVersionUID = 5692151244956513381L;
@Id
@Column(name = DBConstants.PARTNER_COL_PARTNER_NUMBER)
private Integer partnerNumber;
@NotEmpty
@Column(name = DBConstants.PARTNER_COL_NAME, nullable = false)
private String name;
@NotEmpty
@Column(name = DBConstants.PARTNER_COL_SURNAME, nullable = false)
private String surname;
@NotEmpty
@Column(name = DBConstants.PARTNER_COL_LASTNAME)
private String lastname;
}
Spring configuration:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="defaultEncoding" value="UTF-8"/>
<property name="basename" value="ValidationMessages" />
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource" ref="messageSource" />
</bean>
Thanks in advance!
I found the solution. Here it is:
Spring validation configuration:
<!-- SPRING MESSAGE LOCATOR -->
<bean id="messageLocator" class="org.springframework.validation.beanvalidation.MessageSourceResourceBundleLocator">
<constructor-arg index="0" ref="messageSource" />
</bean>
<!-- SPRING LOCALE MESSAGE INTERPOLATOR -->
<bean id="messageInterpolator" class="org.springframework.validation.beanvalidation.LocaleContextMessageInterpolator">
<constructor-arg index="0">
<bean id="hibernateMessageInterpolator" class="org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator">
<constructor-arg name="userResourceBundleLocator" ref="messageLocator" />
<constructor-arg name="cacheMessages" value="true"/>
</bean>
</constructor-arg>
</bean>
<!-- SPRING VALIDATOR -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator" ref="messageInterpolator" />
</bean>
<!-- SPRING ANNOTATION VALIDATION CONFIGURATION -->
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
<property name="validator" ref="validator"/>
</bean>
Phase Listener to manage Locale:
public class LocalePhaseListener implements PhaseListener {
// Constants --------------------------------------------------------------------------------------------------------------
private static final long serialVersionUID = 3678092859009088388L;
// Overridden methods -----------------------------------------------------------------------------------------------------
@Override
public void afterPhase(PhaseEvent event) {
}
@Override
public void beforePhase(PhaseEvent event) {
HttpSession session = (HttpSession) event.getFacesContext().getExternalContext().getSession(false);
Locale locale = ((UserBean) session.getAttribute("userBean")).getLocale();
LocaleContextHolder.resetLocaleContext();
LocaleContextHolder.setLocale(locale);
}
@Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
}
Using LocaleContextMessageInterpolator you enforce Spring to use the locale in LocaleContextHolder, and in the PhaseListener you fill LocaleContextHolder locale with JSF locale.
Upvotes: 2
Views: 1339
Reputation: 19119
Provided that you have access to the Locale
via some sort of ThreadLocal
(not sure whether LocalContextHolder
will work, since I am not so familiar with the Spring API), you can jsut provide a custom MessageInterpolator
and configure it via validation.xml
. See also http://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html_single/#section-validator-factory-message-interpolator.
In the implementation you need to retrieve the current user's Locale
and then call the appropriate interpolation method.
Upvotes: 1