ReloadableResourceBundleMessageSource not working - spring

Currently im working on a new Spring 4 + Thymeleaf + Security project without XML bean files. Somehow the localization property files are not loading and i cant find anything about them in the log files.
/**
* Generates the i18n language loader.
*
* #return
*/
#Bean(name="messageSource")
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
resource.setBasename("classpath:messages");
resource.setDefaultEncoding("UTF-8");
resource.setUseCodeAsDefaultMessage(true);
resource.setFallbackToSystemLocale(false);
return resource;
}
/**
* Generates the i18n language changer parameter.
*
* #return
*/
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("language");
return localeChangeInterceptor;
}
/**
* Genereates the default i18n language.
*
* #return
*/
#Bean(name = "localeResolver")
public SessionLocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(new Locale("en"));
return localeResolver;
}
/**
* Generates the template resolver for thymeleaf.
*
* #return
*/
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
return resolver;
}
/**
* Generates the template engine for thymeleaf.
*
* #return
*/
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
engine.addDialect(new SpringSecurityDialect());
return engine;
}
/**
* Generates the view resolver from Spring MVC with thymeleaf intergrated.
*
* #return
*/
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[]{"*"});
viewResolver.setCache(false);
return viewResolver;
}
/**
* Add resources.
*
* #param registry
*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("/WEB-INF/assets/");
}
/**
* Add interceptors.
*
* #param registry
*/
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
File names in the src/main/resources/ folder:
messages.properties
messages_en.properties
messages_nl.properties
Is there anyone who can help me out?

Slash character "/" denoting the classpath root is missing in the basename pattern of your ReloadableResourceBundleMessageSource.
resource.setBasename("classpath:/messages");

Javabase Config:
#Configuration
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new
ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setCacheSeconds(10);
return messageSource;
}
#Bean
public LocalValidatorFactoryBean localValidatorFactoryBean() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setValidationMessageSource(messageSource());
return factoryBean;
}
#Override
public Validator getValidator() {
return localValidatorFactoryBean();
}
}
XmLbase Config:
Note: You should add mvc namespaces already.
<mvc:annotation-driven validator="validatorFactoryBean"/>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages"/>
</bean>
<bean id="validatorFactoryBean"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource" ref="messageSource"/>
</bean>
Note: If you're trying to load from "webapp" folder so there is no need to use "classpath:" prefix.

I neded up with the following configuration for my dev env:
application.properties:
spring.messages.basename=file:src/main/resources/messages
spring.messages.cache-duration=0
Java configuration:
#Bean
#ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
#Bean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME)
public ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource( MessageSourceProperties properties ) {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
if (StringUtils.hasText( properties.getBasename() )) {
messageSource.setBasenames( StringUtils.commaDelimitedListToStringArray( StringUtils.trimAllWhitespace( properties.getBasename() ) ) );
}
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding( properties.getEncoding().name() );
}
messageSource.setFallbackToSystemLocale( properties.isFallbackToSystemLocale() );
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis( cacheDuration.toMillis() );
}
messageSource.setAlwaysUseMessageFormat( properties.isAlwaysUseMessageFormat() );
messageSource.setUseCodeAsDefaultMessage( properties.isUseCodeAsDefaultMessage() );
return messageSource;
}
Exaplanation:
spring.messages.basename=file:src/main/resources/messages => read files directly from source
spring.messages.cache-duration=0 => disable caching for files to be reloaded. Default is -1 which means cache forever.
The ReloadableResourceBundleMessageSource bean is a direct copy from spring's MessageSourceAutoConfiguration.java impl, but using ReloadableResourceBundleMessageSource instead as message source.
Bean needs to have name AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME to disable default auto-configuration.

Related

JpaRepositoryFactoryBean has wrong entitymanager

the given entitymanager has no managedtype for my class, it is the wrong entitymanager.
i thought that by simply defining the model and repository scan to the specific namespace does handle this automatically, but as it seems i am wrong (?!). Does anybody know how to handle this problem?
He has the class something.application.model.User but uses the entitymanager with the managedtypes of the namespace something.manager.model.
public class JpaConfiguration {
#Configuration
#EntityScan(basePackages = { "something.application.model" })
#EnableJpaAuditing
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = { "something.application.model" }, repositoryFactoryBeanClass = RepositoryFactoryBean.class, entityManagerFactoryRef = "applicationEntityManagerFactory", transactionManagerRef = "applicationTransactionManager")
public static class ApplicationJpaConfiguration {
#Autowired
private ApplicationContext applicationContext;
/**
* The datasource used by the system. Configuration see
* /src/main/resources/application.properties.
*/
#Primary
#Bean(name="applicationDataSource")
#ConfigurationProperties(prefix = "spring.application.datasource")
public DataSource applicationDataSource() {
return new TenantAwareDataSource();
}
/**
* The transaction manager used by the application system.
*
* #param javax.sql.DataSource applicationDataSource
* #param javax.sql.DataSource loadTimeWeaver
* #return org.springframework.orm.jpa.JpaTransactionManager
*/
#Primary
#Bean(name="applicationTransactionManager")
public JpaTransactionManager applicationTransactionManager(LoadTimeWeaver loadTimeWeaver) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(applicationEntityManagerFactory(loadTimeWeaver).getObject());
return transactionManager;
}
/**
* The entity manager factory used by application system. Specific properties of the
* persistence provider eclipselink are configured here.
*/
#Primary
#Bean(name="applicationEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean applicationEntityManagerFactory(LoadTimeWeaver loadTimeWeaver) {
Map<String, String> jpaProperties = new HashMap<String, String>();
jpaProperties.put("eclipselink.ddl-generation", "create-or-extend-tables");
jpaProperties.put("eclipselink.session.customizer", HistoryBuildingSessionCustomizer.class.getName());
jpaProperties.put("eclipselink.logging.level.sql", "fine");
jpaProperties.put("eclipselink.logging.parameters", "true");
jpaProperties.put("eclipselink.temporal.mutable", "true");
jpaProperties.put("eclipselink.persistence-context.flush-mode", "commit");
jpaProperties.put("eclipselink.cache.shared.default", "false");
jpaProperties.put("eclipselink.query-results-cache", "false");
jpaProperties.put("eclipselink.target-database", "MySQL");
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(applicationDataSource());
entityManagerFactoryBean.setJpaVendorAdapter(new EclipseLinkJpaVendorAdapter());
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
entityManagerFactoryBean.setLoadTimeWeaver(loadTimeWeaver);
entityManagerFactoryBean.setPersistenceUnitName("applicationPersistenceUnit");
return entityManagerFactoryBean;
}
/**
* A support object that wraps all available repositories and has some
* convenience functions.
*/
#Bean
public Repositories repositories() {
return new Repositories(applicationContext);
}
}
#Configuration
#EntityScan(basePackages = { "something.manager.model" })
#EnableJpaAuditing
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = { "something.manager.model" }, repositoryFactoryBeanClass = RepositoryFactoryBean.class, entityManagerFactoryRef = "managerEntityManagerFactory", transactionManagerRef = "managerTransactionManager")
public static class ManagerJpaConfiguration {
#Autowired
private ApplicationContext applicationContext;
/**
* The datasource used by the system. Configuration see
* /src/main/resources/application.properties.
*/
#Bean(name="managerDataSource")
#ConfigurationProperties(prefix = "spring.manager.datasource")
public DataSource managerDataSource() {
return new BasicDataSource();
}
/**
* The transaction manager used by the manager system.
*
* #param javax.sql.DataSource managerDataSource
* #param javax.sql.DataSource loadTimeWeaver
* #return org.springframework.orm.jpa.JpaTransactionManager
*/
#Bean(name="managerTransactionManager")
public JpaTransactionManager managerTransactionManager(DataSource managerDataSource, LoadTimeWeaver loadTimeWeaver) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(managerEntityManagerFactory(managerDataSource, loadTimeWeaver).getObject());
return transactionManager;
}
/**
* The entity manager factory used by manager system. Specific properties of the
* persistence provider eclipselink are configured here.
*/
#Bean(name="managerEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean managerEntityManagerFactory(DataSource managerDataSource, LoadTimeWeaver loadTimeWeaver) {
Map<String, String> jpaProperties = new HashMap<String, String>();
jpaProperties.put("eclipselink.ddl-generation", "create-or-extend-tables");
jpaProperties.put("eclipselink.session.customizer", HistoryBuildingSessionCustomizer.class.getName());
jpaProperties.put("eclipselink.logging.level.sql", "fine");
jpaProperties.put("eclipselink.logging.parameters", "true");
jpaProperties.put("eclipselink.temporal.mutable", "true");
jpaProperties.put("eclipselink.persistence-context.flush-mode", "commit");
jpaProperties.put("eclipselink.cache.shared.default", "false");
jpaProperties.put("eclipselink.query-results-cache", "false");
jpaProperties.put("eclipselink.target-database", "MySQL");
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(managerDataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new EclipseLinkJpaVendorAdapter());
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
entityManagerFactoryBean.setLoadTimeWeaver(loadTimeWeaver);
return entityManagerFactoryBean;
}
/**
* A support object that wraps all available repositories and has some
* convenience functions.
*/
#Bean
public Repositories repositories() {
return new Repositories(applicationContext);
}
}
}

Spring MVC + Webflow 2 + Thymeleaf fragments: can't configure .HTML extension

I have a Spring MVC application with Thymeleaf configured to use fragments (NO tiles!) and all files have .html extension. Everything is working fine.
Now i'm trying to setup Webflow but, when i call my webflow url, i get 404 error as he tries to load a JSP view instead of html (outside flow, everything is fine):
HTTP Status 404 - /app/WEB-INF/views/contest/contest-step1.jsp
I know that put kilometers of line of code isn't good, but honestly i don't know which pieces are interesting and which no.
ThymeleafConfig:
#Configuration
public class ThymeleafConfig {
#Bean
public TemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
/**
* only on development machine
*/
templateResolver.setCacheable(false);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
Set<IDialect> dialects = new HashSet<IDialect>();
dialects.add(springSecurityDialect());
templateEngine.setAdditionalDialects(dialects);
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
return resolver;
}
#Bean
public SpringSecurityDialect springSecurityDialect(){
SpringSecurityDialect dialect = new SpringSecurityDialect();
return dialect;
}
}
WebAppConfig:
#Configuration
#EnableWebMvc
#ComponentScan("com.myapp")
public class WebAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
// Maps resources path to webapp/resources
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
/**************************************************
*
* Web Flow: wizard contest
*
*/
#Autowired
private WebFlowConfig webFlowConfig;
/**
* Maps request paths to flows in the flowRegistry;
* e.g. a path of /hotels/booking looks for a flow with id "hotels/booking"
*
* Configuring this mapping allows the Dispatcher to map application resource paths
* to flows in a flow registry.
* For example, accessing the resource path /hotels/booking would result in a
* registry query for the flow with id hotels/booking.
* If a flow is found with that id,
* that flow will handle the request. If no flow is found, the next handler mapping in the
* Dispatcher's ordered chain will be queried or a "noHandlerFound" response will be returned.
*/
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1); //0 ?
handlerMapping.setFlowRegistry(this.webFlowConfig.flowRegistry());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
handlerAdapter.setFlowExecutor(this.webFlowConfig.flowExecutor());
handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
return handlerAdapter;
}
#Bean(name="contest/add") //defined in in WebFlowConfig
public ContestFlowHandler ContestFlowHandler() {
return new ContestFlowHandler();
}
/* TODO
#Bean
public AjaxThymeleafViewResolver tilesViewResolver() {
AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
viewResolver.setViewClass(FlowAjaxThymeleafTilesView.class);
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
} */
}
WebFlowConfig:
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
private ThymeleafConfig thymeleafConfig;
//private WebFlowConfig WebAppConfig;
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/views/gare/gare-add-flow.xml", "gare/add")
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.setMaxFlowExecutions(5)
.setMaxFlowExecutionSnapshots(30)
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.build();
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Arrays.<ViewResolver>asList(this.thymeleafConfig.thymeleafViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
}
I found a trick that gives me a quick solution, but honestly i would like don't do this, but correctly configure the resolver. The trick is to set the view file in flow xml file:
<view-state id="contest-step1" model="contest" view="/WEB-INF/views/contest/contest-step1.html"></view-state>
thanks
Try the following in flowRegistry method.
return getFlowDefinitionRegistryBuilder(flowBuilderServices())
instead of
return getFlowDefinitionRegistryBuilder()
Hope this helps.
I am not sure but kindly look into the following part of your code
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
it is pointing to .jsp whatever you call in controller it will append .jsp
Also your controller code is not here url mapping should be like /login.html
I am not much familier with thymeleaf and spring-webflow-2

Configuring a Conversion Service with a custom DateFormatter

I'm trying to add a custom DateFormatter to my spring/thymeleaf application, with the help of the following documentation :
http://www.thymeleaf.org/doc/html/Thymeleaf-Spring3.html#conversions-utility-object
The problem is that I don't use xml configuration for my beans definitions, but a WebConfig.java class with the following implementation :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.myapp.web.controller","net.atos.wfs.wts.adminportal.web.domain"})
public class WebConfig extends WebMvcConfigurerAdapter {
private static final Logger LOG = LoggerFactory.getLogger(WebConfig.class);
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
#Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(StringUtils.parseLocaleString("en"));
return cookieLocaleResolver;
}
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html");
//NB, selecting HTML5 as the template mode.
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
return resolver;
}
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
engine.setMessageResolver(messageResolver());
engine.addDialect(new LayoutDialect());
return engine;
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[]{"*"});
viewResolver.setCache(false);
return viewResolver;
}
#Bean
public IMessageResolver messageResolver() {
SpringMessageResolver messageResolver = new SpringMessageResolver();
messageResolver.setMessageSource(messageSource());
return messageResolver;
}
#Override
public void addFormatters(FormatterRegistry registry) {
super.addFormatters(registry);
registry.addFormatter(new DateFormatter());
}
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("/WEB-INF/messages/messages");
// if true, the key of the message will be displayed if the key is not
// found, instead of throwing a NoSuchMessageException
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
// # -1 : never reload, 0 always reload
messageSource.setCacheSeconds(0);
return messageSource;
}
}
And here is the code of my Custom DateFormatter :
public class DateFormatter implements Formatter<Date> {
#Autowired
private MessageSource messageSource;
public DateFormatter() {
super();
}
public Date parse(final String text, final Locale locale) throws ParseException {
final SimpleDateFormat dateFormat = createDateFormat(locale);
return dateFormat.parse(text);
}
public String print(final Date object, final Locale locale) {
final SimpleDateFormat dateFormat = createDateFormat(locale);
return dateFormat.format(object);
}
private SimpleDateFormat createDateFormat(final Locale locale) {
//The following line is not working (nullPointerException on messageSource)
//final String format = this.messageSource.getMessage("date.format", null, locale);
//The following line is working :
final String format = "dd/MM/yyyy";
final SimpleDateFormat dateFormat = new SimpleDateFormat(format);
dateFormat.setLenient(false);
return dateFormat;
}
}
My question is : how can I add a custom formatter that will be able to use #Autowired elements ?
The xml configuration is this one :
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
...
<mvc:annotation-driven conversion-service="conversionService" />
...
<!-- **************************************************************** -->
<!-- CONVERSION SERVICE -->
<!-- Standard Spring formatting-enabled implementation -->
<!-- **************************************************************** -->
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="thymeleafexamples.stsm.web.conversion.VarietyFormatter" />
<bean class="thymeleafexamples.stsm.web.conversion.DateFormatter" />
</set>
</property>
</bean>
...
</beans>
I tried to uset the following configuration in WebConfig class :
#Bean
public FormattingConversionServiceFactoryBean conversionService() {
FormattingConversionServiceFactoryBean conversionService = new FormattingConversionServiceFactoryBean();
Set<Formatter<?>> formatters = new TreeSet<Formatter<?>>();
formatters.add(new DateFormatter());
conversionService.setFormatters(formatters);
return conversionService;
}
But in this case, the formatter is not taken into account in my application.
Thanks in advance,
Antoine.
Add this to your WebMvcConfigurerAdapter
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(dateFormatter);
}
#Autowired
private DateFormatter dateFormatter;
#Bean
public DateFormatter dateFormatter() {
return new DateFormatter("dd/MM/yyyy");
}
I used the following configuration class and was able to get the custom formatter to be called. I have not been able to get the messageSource to be passed in, it is always null as the auto-configure bean is created later in the application startup.
#Configuration
public class ThymeleafConfig {
#Autowired
private MessageSource messageSource;
#Bean
public SpringSecurityDialect securityDialect() {
return new SpringSecurityDialect();
}
#Bean
public ConversionService conversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService( false );
conversionService.addFormatter( dateFormatter() );
return conversionService;
}
#Bean
public DateFormatter dateFormatter() {
return new DateFormatter( messageSource );
}
}
You also need to make sure in your template that you use the double brackets around the field. i.e.
<td th:text="${{user.createDate}}">12-MAR-2015</td>

Overriding default ValidationMessages.properties from hibernate-validation

I'm trying to override the ValidationMessages.properties from default hibernate-validation (5.0.2 version) in a Spring MVC application.
But it keeps using the internal ValidationMessages.properties from jar.
UPDATE: it works (but it should be another way) when I copy the *.properties files to org\hibernate\validator ...
This is my configuration:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.blueliv.search.*"} )
public class WebConfig extends WebMvcConfigurerAdapter {
static Logger log =LoggerFactory.getLogger(WebMvcConfigurerAdapter.class);
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new GsonHttpMessageConverter());
//converters.add(new MappingJackson2HttpMessageConverter());
}
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
#Bean
public ExceptionHandlerExceptionResolver exceptionResolver() {
return new ExceptionHandlerExceptionResolver();
}
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean();
validatorFactoryBean.setValidationMessageSource(getBundle());
return validatorFactoryBean;
}
public ReloadableResourceBundleMessageSource getBundle(){
log.debug("get bundle!");
ReloadableResourceBundleMessageSource bundle = new ReloadableResourceBundleMessageSource();
bundle.setBasenames("classpath:/i18n/validation/ValidatonMessages");
return bundle;
}
#Override
public Validator getValidator() {
return validator();
}

ContextLoaderListener Configuration with AbstractAnnotationConfigDispatcherServletInitialier not loaded

I use Spring version 3.2.2.RELEASE.
I want to create a webapp with hibernate and have the folllowing configuration:
public class LifepulseServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { PersistenceConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { LifepulseWebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected WebApplicationContext createRootApplicationContext() {
return super.createRootApplicationContext();
}
}
My two with #Configuration annotated files look like this:
My PersistenceConfig should be used for the ContextLoaderListener:
#Configuration
#EnableTransactionManagement(proxyTargetClass=true, mode=AdviceMode.PROXY)
public class PersistenceConfig{
Logger logger = LoggerFactory.getLogger(PersistenceConfig.class);
/** The Application Context. */
#Autowired
ApplicationContext context;
/**
* Gets the database url.
*
* #return the database url
*/
#Bean(name="databaseUrl")
public String getDatabaseUrl(){
return "jdbc:mysql://localhost/lifepulse";
}
/**
* Gets the session factory properties.
*
* #return the session factory properties
*/
#Bean(name="sessionFactoryProperties")
public Properties getSessionFactoryProperties(){
Properties props = new Properties();
props.put("hibernate.dialect", MySQL5InnoDBDialect.class.getName());
props.put("hibernate.hbm2ddl.auto", "create-drop");
props.put("hibernate.show_sql", "true");
props.put("hibernate.format_sql", "true");
return props;
}
/** The Constant ANNOTATED_CLASSES. */
#SuppressWarnings("unchecked")
private static final Class<? extends Serializable>[] ANNOTATED_CLASSES=new Class[]{
Melder.class,
LogEntry.class
};
/**
* Gets the annotated classes.
*
* #return the annotated classes
*/
private static Class<? extends Serializable>[] getAnnotatedClasses(){
return ANNOTATED_CLASSES;
}
/**
* Gets the data source.
* This bean represents the application's MYSQL datasource, without using xml.
*
* #return the data source
*/
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(getDatabaseUrl());
dataSource.setUsername("lifepulse");
dataSource.setPassword("lifepulse");
return dataSource;
}
/**
* Session factory.
* This bean represents the Hibernate Session Factory. By declaring this bean
* it can easily be injected into Spring DAOs later on.
*
* #return the local session factory bean
*/
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setAnnotatedClasses(getAnnotatedClasses());
factory.setHibernateProperties(getSessionFactoryProperties());
factory.setDataSource(dataSource());
return factory;
}
#Bean()
public GenericDao genericDao() {
return new HibernateDaoImpl();
}
#Bean
PlatformTransactionManager txManager(){
HibernateTransactionManager htm = new HibernateTransactionManager(sessionFactory().getObject());
return htm;
}
}
My LifepulseWebConfig should be used for the DispatcherSerlvet:
#Configuration
#EnableWebMvc
#ComponentScan(value= {"com.ansiworks.lifepulse.controllers"})
#EnableTransactionManagement(proxyTargetClass=true, mode=AdviceMode.PROXY)
public class LifepulseWebConfig extends WebMvcConfigurerAdapter{
#Autowired
ApplicationContext context;
#Bean
ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
//resolver.setPrefix("");
resolver.setSuffix(".jsp");
return resolver;
}
#Bean
MainService mainService(){
return new MainServiceImpl();
}
}
This configuration doesn't work. The dispathcer servlet doesn't load my PersistenceConfig, and so the beans are not herited to the LifepulseWebConfig.
But: When I add the PersistenceConfig to the class-array of the Method LifepulseServletInitializer#getServletConfigClasses() everything works fine.
However... I can't use sprin-security in this way....
What am I doing wrong!? Why are the config-classes returned by LifepulseServletInitializer#getRootConfigClasses() not read by the ContextLoaderListener?
I also tried it this way (without the LifepulseServletInitializer ) with the same effect. The beans of my PersistenceConfig are simply not loaded...
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(PersistenceConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(LifepulseWebConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}

Resources