I am looking at using Spring JavaConfig with some property files but properties in bean is not getting set?in bean is not getting set?
Here is my WebConfig:
#Configuration
#EnableWebMvc
#PropertySource(value = "classpath:application.properties")
#Import(DatabaseConfig.class)
#ImportResource("/WEB-INF/applicationContext.xml")
public class WebMVCConfig extends WebMvcConfigurerAdapter {
private static final String MESSAGE_SOURCE = "/WEB-INF/classes/messages";
private static final Logger logger = LoggerFactory.getLogger(WebMVCConfig.class);
#Value("${rt.setPassword}")
private String RTPassword;
#Value("${rt.setUrl}")
private String RTURL;
#Value("${rt.setUser}")
private String RTUser;
#Bean
public ViewResolver resolver() {
UrlBasedViewResolver url = new UrlBasedViewResolver();
url.setPrefix("/WEB-INF/view/");
url.setViewClass(JstlView.class);
url.setSuffix(".jsp");
return url;
}
#Bean(name = "messageSource")
public MessageSource configureMessageSource() {
logger.debug("setting up message source");
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename(MESSAGE_SOURCE);
messageSource.setCacheSeconds(5);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver lr = new SessionLocaleResolver();
lr.setDefaultLocale(Locale.ENGLISH);
return lr;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
logger.debug("setting up resource handlers");
registry.addResourceHandler("/resources/").addResourceLocations("/resources/**");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
logger.debug("configureDefaultServletHandling");
configurer.enable();
}
#Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
}
#Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver b = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.put("org.springframework.web.servlet.PageNotFound", "p404");
mappings.put("org.springframework.dao.DataAccessException", "dataAccessFailure");
mappings.put("org.springframework.transaction.TransactionException", "dataAccessFailure");
b.setExceptionMappings(mappings);
return b;
}
#Bean
public RequestTrackerConfig requestTrackerConfig()
{
RequestTrackerConfig tr = new RequestTrackerConfig();
tr.setPassword(RTPassword);
tr.setUrl(RTURL);
tr.setUser(RTUser);
return tr;
}
}
The value in tr.url is "rt.setUrl" not the value in application.properties?
I'm not 100%, but I think your #PropertySource isn't quite right. Instead of
#PropertySource(value = "classpath:application.properties")
It should just be:
#PropertySource("classpath:application.properties")
based on this:
Spring PropertySource Documentation
Also, based on the link above and since you have mentioned you were converting to a java config approach instead of xml, I think the below might be the solution to your issue:
Resolving ${...} placeholders in and #Value annotations In
order to resolve ${...} placeholders in definitions or #Value
annotations using properties from a PropertySource, one must register
a PropertySourcesPlaceholderConfigurer. This happens automatically
when using in XML, but must be
explicitly registered using a static #Bean method when using
#Configuration classes. See the "Working with externalized values"
section of #Configuration Javadoc and "a note on
BeanFactoryPostProcessor-returning #Bean methods" of #Bean Javadoc for
details and examples.
The example from the link above is how I normally do it:
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
So add at the top:
#Autowired
Environment env;
Then in your method use:
tr.setPassword(env.getProperty("rt.setPassword"));
and so on for the remaining property values. I am just not as familiar with the way you are doing it. I know the above approach will work though.
Aside from #ssn771 answer that involves injecting the Environment and retrieving the properties through it which is indeed the suggested way of doing it, this is what I've done as a workaround without having to change the way #Value is being used in the #Configuration POJO.
Out of the many suggested things the most important one is that you need to configure PropertySourcesPlaceholderConfigurer in Spring 3.1+ (or PropertyPlaceholderConfigurer in Spring 3.0). It must be static if you want it to be applied to the configuration class (to use #Value annotations).
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
From javadoc for PropertySourcesPlaceholderConfigurer :
This class is designed as a general replacement for PropertyPlaceholderConfigurer in Spring 3.1 applications. It is used by default to support the property-placeholder element in working against the spring-context-3.1 XSD, whereas spring-context versions <= 3.0 default to PropertyPlaceholderConfigurer to ensure backward compatibility. See the spring-context XSD documentation for complete details.
Related
Below is my class in which i had to use both #Configuration and #Controller as there should be only one instance of Thymeleaf in the entire application else i get exceptions for that. My other classes are annotated with #RequestScope so i cannot use a singleton scoped bean. So i had a mixup of Configuration and Controller to get the result, but i feel it is a bad practice. I would appreciate any help to refactor the code and remove the bad practice.
UPDATE
I am using spring-boot 1.5.14. I am using the following approach to process a template and keep the processed template as string.
#Controller
#Configuration
#EnableWebMvc
#ApplicationScope
public class MyThymeleafConfig {
#GetMapping("/view-template")
#ResponseBody
public void viewTemplates() {
Context context = new Context();
context.setVariable("mydata", "this is it");
String html = templateEngine().process("templates/view-to-process.html", context);
System.out.println(html);
}
/*
configuration for thymeleaf and template processing
*/
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(thymeleafTemplateResolver());
return templateEngine;
}
#Bean
public SpringResourceTemplateResolver thymeleafTemplateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:");
templateResolver.setSuffix(".html");
templateResolver.setCacheable(false);
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
}
To serve static resources the following config:
#Configuration
#EnableWebMvc
public class StaticResourceConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("/static/", "classpath:static/");
}
}
UPDATE
I have also mentioned the reasons why i couldn't accept the below mentioned answers as my other classes have request scopes.
UPDATE
I have other classes with #RequestScopelike below:
#RequestScope
#Controller
public class SecondController {
#GetMapping("/viewPage")
public String viewPage(Model model) {
model.addAttribute("mydata", "sjfbsdf");
model.addAttribute("somedata", "sjdfksfjhshgdfbskdfj");
return "templates/view-to-process.html";
}
}
Assuming you're using Spring Boot, since you have it in tags, you do not need any configuration to use Thymeleaf.
By just having this dependency, you can:
#GetMapping("/view-template")
public String viewTemplates(Model model) {
model.addAttribute("mydata", "this is it")
return "view-to-process";
}
And it should work.
By the way, yes, having #Configuration and #Controller in the same class is something you should never need.
If you see the source codes of the annotations (Spring 5) you have:
Controller
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* #return the suggested component name, if any (or empty String otherwise)
*/
#AliasFor(annotation = Component.class)
String value() default "";
}
Configuration
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Configuration {
/**
* Explicitly specify the name of the Spring bean definition associated
* with this Configuration class. If left unspecified (the common case),
* a bean name will be automatically generated.
* <p>The custom name applies only if the Configuration class is picked up via
* component scanning or supplied directly to a {#link AnnotationConfigApplicationContext}.
* If the Configuration class is registered as a traditional XML bean definition,
* the name/id of the bean element will take precedence.
* #return the suggested component name, if any (or empty String otherwise)
* #see org.springframework.beans.factory.support.DefaultBeanNameGenerator
*/
#AliasFor(annotation = Component.class)
String value() default "";
}
you notice that they are the same (they both include the more generic #Component annotation). So it doesn't make sense to use them both by seeing this fact. Another thing, more important, is that spring is trying to give a sort of tags meaning of these annotations that should describe the use.
The Configuration is used to wire in necessary parts to the application to function properly, at startup phase.
The Controller is used to define a class which is serving as an interface to the outside world, i.e: how can other actors use your application.
As you can see, it makes very little sense to use those 2 together.
Take look at Spring Boot documentation typical layout
Also this article SOLID Programming Principles
And look at Spring Boot guide Spring Boot Thymeleaf (you don't need your #Bean configurations)
In two words you should separate
1. MyThymeleafConfig configuration
2. TemplateController with viewTemplates() and another endpoints
To refactor them, it's easy and straight forward to separate #Bean methods to a separate #Configuration class:
#Configuration
// #Controller is redundant as we have #Configuration
// #EnableWebMvc is also redundant since you already annotate it in other class
// #ApplicationScope is also redundant since you do not need to create bean of MyThymeleafConfig anymore
public class MyThymeleafConfig {
/*
configuration for thymeleaf and template processing
*/
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(thymeleafTemplateResolver());
return templateEngine;
}
#Bean
public SpringResourceTemplateResolver thymeleafTemplateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:");
templateResolver.setSuffix(".html");
templateResolver.setCacheable(false);
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
}
#Configuration class return the same bean instance, regardless how many times you call the bean methods.
Now in your controller:
#Controller
public class MyThymeleafConfig {
#Autowired
private SpringTemplateEngine templateEngine;
#GetMapping("/view-template")
#ResponseBody
public void viewTemplates() {
Context context = new Context();
context.setVariable("mydata", "this is it");
String html = templateEngine.process("templates/view-to-process.html", context);
System.out.println(html);
}
}
But honestly, I don't know why you have to manually interact with TemplateEngine / SpringTemplateEngine, since Spring-thymeleaf will automatically process the template with given variable for you. (Like #sedooe example)
Don't put request mappings inside configuration classes, it violates the principal of separation of concerns. You can go for a approach like below.
All the application wide beans are setup in Application class which is present in the root of the classpath. Application class in the best place to have your thymeleaf and static resource configurations too, since the Application class have application-scope.
#SpringBootApplication
#EnableWebMvc
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
resolver.setCache(false);
return resolver;
}
#Bean
public TemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setEnableSpringELCompiler(true);
templateEngine.addDialect(new LayoutDialect());
templateEngine.addDialect(new Java8TimeDialect());
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new
SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/templates/");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
}
If you put the static resources inside a folder named static or public in the classpath, springboot identify that as the location for static resources. Then you don't need to override addResourceHandlers method. If you really want to do it, you can do it inside the Application class extending WebMvcConfigurerAdapter. You don't need separate class to configure just static resource paths.
Don't put request mappings inside configuration classes, put them in separate controller classes like:
#Controller
public class MyController {
#GetMapping("/view-template")
#ResponseBody
public void viewTemplates() {
Context context = new Context();
context.setVariable("mydata", "this is it");
String html = templateEngine().process("templates/view-to-process.html", context);
System.out.println(html);
}
}
Of cause, springboot allows you to do it the way you like, but you'd better stick to a general approach.
These two annotations are for different things, thus it's better to not use them on the same class. Cause it's against Separation of Concerns principal.
How to read properties file in Controller using annotations only?
Properties file contains (env.properties):
document.portal.path=http://flana.gost.com/service
Spring Controller:
#Controller
#RequestMapping("/kap/*")
#SessionAttributes({"user", "KapForm", "activity"})
public class KapController {
#Value("${document.portal.path}")
private String URL;
}
Nothing else is done. In XML, we use to use placeholder, which i am not getting how to introduce in it. So I am getting exception.
Injection of autowired dependencies failed;
You can achieve it in two ways
Option 1
In config class put #PropertySource and define a bean for PropertySourcesPlaceholderConfigurer as below -
#Configuration
#PropertySource("classpath:someFile.properties")
public class SampleConfig {
// other configs...
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Option 2
In config class directly specify the bean for PropertyPlaceholderConfigurer and supply the name of property file as ClassPathResource
#Configuration
public class SampleConfig {
// other configs...
#Bean
public static PropertyPlaceholderConfigurer placeHolderConfigurer(){
PropertyPlaceholderConfigurer placeHolderConfigurer = new PropertyPlaceholderConfigurer();
ClassPathResource[] cpResources = new ClassPathResource[]
{ new ClassPathResource( "someFile.properties" ) };
placeHolderConfigurer.setLocations(cpResources);
placeHolderConfigurer.setIgnoreUnresolvablePlaceholders(true);
return placeHolderConfigurer;
}
}
Do note that the bean definition for place holder need to be static as per java docs (excerpts below)
Special consideration must be taken for #Bean methods that return Spring BeanFactoryPostProcessor (BFPP) types. Because BFPP objects must be instantiated very early in the container lifecycle, they can interfere with processing of annotations such as #Autowired, #Value, and #PostConstruct within #Configuration classes. To avoid these lifecycle issues, mark BFPP-returning #Bean methods as static.
Another way out found is
import org.springframework.context.MessageSource;
#Autowired
private MessageSource messageSource;
cutiePie = messageSource.getMessage("cutie.pie.property", new Object[] {},"cutie.pie.property", LocaleContextHolder.getLocale());
We can externalize properties using <context:property-placeholder> and we can override the Spring bean properties by configuring <context:property-override> as follows:
<context:property-placeholder location="classpath:application.properties"/>
<context:property-override location="classpath:override.properties"/>
I want to move my XML config to JavaConfig.
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
But how to configure my override properties using Annotation?
PS:
I have a bean say MyBean as follows:
#Component
public class MyBean {
#Value("${someProp}")
private String someProp;
}
In my application.properties I have
someProp=TestValue
and in my override.properties i am overriding someProp value as
myBean.someProp=RealValue
No, It isn't.
But you could create a bean of type PropertyOverrideConfigurer in the configuration class whit the same result.
Update
For example:
#Bean public static PropertyOverrideConfigurer propertyOverrideConfigurer() {
PropertyOverrideConfigurer overrideConfigurer = new PropertyOverrideConfigurer();
overrideConfigurer.setLocation(new ClassPathResource("override.properties"));
return overrideConfigurer;
}
Note the static modifier, this is because BFPP should be instantiated early in the container lifecycle.
see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html for more info.
Here's my app:
public static void main( String[] args ) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
//run the importer
final ImportNewOrders importer = (ImportNewOrders) ApplicationContextProvider.getApplicationContext().getBean("importNewOrders");
importer.run();
//importer.runInBackground();
}
Here's my config:
#Configuration
#ComponentScan(basePackages = {
"com.production"
})
#PropertySource(value = {
"classpath:/application.properties",
"classpath:/environment-${MY_ENVIRONMENT}.properties"
})
#EnableJpaRepositories("com.fettergroup.production.repositories")
#EnableTransactionManagement
public class Config {
.... skipping things that aren't relevant
#Bean
public ImportNewOrders importNewOrders() {
return new ImportNewOrders();
}
Here's my class...
#Component
public class ImportNewOrders implements Task {
private final static Logger logger = Logger.getLogger(ImportNewOrders.class.getName());
#Autowired
private OrderService orderService;
#Autowired
private ImportOrderRequest importOrderRequest;
#Value("${api.user}")
private String apiUser;
#Value("${api.password}")
private String apiPassword;
#Value("${api.orders.pingFrequency}")
private String pingFrequency;
And finally the application.properties:
# ------------------- Application settings -------------------
#Base URL to the API application
api.baseUrl=http://localhost:9998
#Unique token used to authenticate this vendor
api.vendor.token=asdf
#API credentials
api.user=myuser
api.password=mypassword
#How often to check for new orders; frequency is in seconds
api.orders.pingFrequency=60
This worked an hour or two ago, now it's decided it doesn't like these values. I'm at a loss as to why. Everything looks correct to me.
Update
#Configuration
#ComponentScan(basePackages = {
"com.production"
})
#PropertySource(value = {
"classpath:/application.properties",
"classpath:/environment-${MY_ENVIRONMENT}.properties"
})
#EnableJpaRepositories("com.production.repositories")
#EnableTransactionManagement
public class Config {
#Value("${db.url}")
private static String PROPERTY_DATABASE_URL;
#Bean
public DataSource dataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUrl(PROPERTY_DATABASE_URL); //is null
/*dataSource.setUser(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USER));
dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));*/
return dataSource;
}
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer () {
return new PropertySourcesPlaceholderConfigurer();
}
}
Your properties file is found by your #Configuration and is using it for your database properties within that class because of #PropertySource. But #Value fields and ${} evaluation need more than that.
From Javadoc for #PropertySource
In order to resolve ${...} placeholders in definitions or
#Value annotations using properties from a PropertySource, one must
register a PropertySourcesPlaceholderConfigurer. This happens
automatically when using in XML, but
must be explicitly registered using a static #Bean method when using
#Configuration classes. See the "Working with externalized values"
section of #Configuration Javadoc and "a note on
BeanFactoryPostProcessor-returning #Bean methods" of #Bean Javadoc for
details and examples.
So declare a
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer p = new PropertySourcesPlaceholderConfigurer();
p.setLocation(new ClassPathResource("your properties path"));
// other properties
return p;
}
in your config class, or as ach has aptly mentioned in the comments if you use #PropertySource your can omit setLocation altogether:
#Configuration
#PropertySource(value="classpath:your_file.properties")
public class MyConfiguration{
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer p = new PropertySourcesPlaceholderConfigurer();
return p;
}
}
You shouldn't need the environment when you have the PropertySourcesPlaceholderConfigurer
In most cases, however, application-level beans should not need to>
interact with the Environment directly but instead may have to have
${...} property values replaced by a property placeholder configurer
such as PropertySourcesPlaceholderConfigurer, which itself is
EnvironmentAware and as of Spring 3.1 is registered by default when
using < context:property-placeholder/>.
I am using the following for the spring 3.1 configuration:
#Configuration
#EnableTransactionManagement
public class DataConfig {
#Inject
private Environment env;
#Inject
private DataSource dataSource;
// #Bean
public SpringLiquibase liquibase() {
SpringLiquibase b = new SpringLiquibase();
b.setDataSource(dataSource);
b.setChangeLog("classpath:META-INF/db-changelog-master.xml");
b.setContexts("test, production");
return b;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean b = new LocalContainerEntityManagerFactoryBean();
b.setDataSource(dataSource);
HibernateJpaVendorAdapter h = new HibernateJpaVendorAdapter();
h.setShowSql(env.getProperty("jpa.showSql", Boolean.class));
h.setDatabasePlatform(env.getProperty("jpa.database"));
b.setJpaVendorAdapter(h);
return (EntityManagerFactory) b;
}
#Bean
public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
PersistenceExceptionTranslationPostProcessor b = new PersistenceExceptionTranslationPostProcessor();
// b.setRepositoryAnnotationType(Service.class);
// do this to make the persistence bean post processor pick up our #Service class. Normally
// it only picks up #Repository
return b;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager b = new JpaTransactionManager();
b.setEntityManagerFactory(entityManagerFactory());
return b;
}
/**
* Allows repositories to access RDBMS data using the JDBC API.
*/
#Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
#Bean(destroyMethod = "close")
public DataSource dataSource() {
BasicDataSource db = new BasicDataSource();
if (env != null) {
db.setDriverClassName(env.getProperty("jdbc.driverClassName"));
db.setUsername(env.getProperty("jdbc.username"));
db.setPassword(env.getProperty("jdbc.password"));
} else {
throw new RuntimeException("environment not injected");
}
return db;
}
}
the issue is that the variable env is not injected and is always null.
I have not done anything about the Environment setup since I do not know if it's needed or how to. I looked at the greenhouse example and i did not find anything specifically for Environment. What should I do to make sure the env is injected?
The related files:
// CoreConfig.java
#Configuration
public class CoreConfig {
#Bean
LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
/**
* Properties to support the 'standard' mode of operation.
*/
#Configuration
#Profile("standard")
#PropertySource("classpath:META-INF/runtime.properties")
static class Standard {
}
}
// the Webconfig.java
#Configuration
#EnableWebMvc
#EnableAsync
// #EnableScheduling
#EnableLoadTimeWeaving
#ComponentScan(basePackages = "com.jfd", excludeFilters = { #Filter(Configuration.class) })
#Import({ CoreConfig.class, DataConfig.class, SecurityConfig.class })
#ImportResource({ "/WEB-INF/spring/applicationContext.xml" })
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/images/**").addResourceLocations(
"/images/");
}
#Bean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver b = new BeanNameViewResolver();
b.setOrder(1);
return b;
}
#Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver b = new InternalResourceViewResolver();
b.setSuffix(".jsp");
b.setPrefix("/WEB-INF/jsp/");
b.setOrder(2);
return b;
}
#Bean
public CookieLocaleResolver localeResolver() {
CookieLocaleResolver b = new CookieLocaleResolver();
b.setCookieMaxAge(100000);
b.setCookieName("cl");
return b;
}
// for messages
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource b = new ResourceBundleMessageSource();
b.setBasenames(new String[] { "com/jfd/core/CoreMessageResources",
"com/jfd/common/CommonMessageResources",
"com/jfd/app/AppMessageResources",
"com/jfd/app/HelpMessageResources" });
b.setUseCodeAsDefaultMessage(false);
return b;
}
#Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver b = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.put("org.springframework.web.servlet.PageNotFound", "p404");
mappings.put("org.springframework.dao.DataAccessException",
"dataAccessFailure");
mappings.put("org.springframework.transaction.TransactionException",
"dataAccessFailure");
b.setExceptionMappings(mappings);
return b;
}
/**
* ViewResolver configuration required to work with Tiles2-based views.
*/
#Bean
public ViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(TilesView.class);
return viewResolver;
}
/**
* Supports FileUploads.
*/
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(500000);
return multipartResolver;
}
// for configuration
#Bean
public CompositeConfigurationFactoryBean myconfigurations()
throws ConfigurationException {
CompositeConfigurationFactoryBean b = new CompositeConfigurationFactoryBean();
PropertiesConfiguration p = new PropertiesConfiguration(
"classpath:META-INF/app-config.properties");
p.setReloadingStrategy(new FileChangedReloadingStrategy());
b.setConfigurations(new org.apache.commons.configuration.Configuration[] { p });
b.setLocations(new ClassPathResource[] { new ClassPathResource(
"META-INF/default-config.properties") });
return b;
}
#Bean
org.apache.commons.configuration.Configuration configuration()
throws ConfigurationException {
return myconfigurations().getConfiguration();
}
// and the SecurityConfig.java
#Configuration
#ImportResource({ "/WEB-INF/spring/applicationContext-security.xml" })
public class SecurityConfig {
#Bean
public BouncyCastleProvider bcProvider() {
return new BouncyCastleProvider();
}
#Bean
public PasswordEncryptor jasyptPasswordEncryptor() {
ConfigurablePasswordEncryptor b = new ConfigurablePasswordEncryptor();
b.setAlgorithm("xxxxxx");
return b;
}
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder b = new org.jasypt.spring.security3.PasswordEncoder();
b.setPasswordEncryptor(jasyptPasswordEncryptor());
return b;
}
}
in the applicationcontext.xml, it only imported two xmls to config cache and cassandra, so it may not be important.
Not sure why, but using the #Resource annotation worked for me. #Autowired always returned null.
The problem is with the spring security for the remember me feature. if I take this line <code> <remember-me data-source-ref="dataSource" /> </code> out. everything works fine. if this line presents, it will try to load the db before anything else and env was never injected.
If you don't use full Java EE compatible server you have to include javax.inject.jar to your project classpath to add the support of #Inject. You can also try to use spring's native #Autowired annotation.
#jfd,
I don't immediately see anything wrong with your configuration that would cause a failure to inject the Environment.
If you start from scratch with an empty #Configuration class, and then #Inject the Environment, does it work for you?
If yes, then at what point does it begin to fail?
Would you be willing to reduce the example down to the smallest possible configuration that fails and submit it as a reproduction project? The instructions here make this as simple as possible: https://github.com/SpringSource/spring-framework-issues#readme
Thanks!
I've detect a similar error for my project as mentioned here.
I've also figure out, that a call of afterproperties is necessary to get the sessionFactory.
... and yes, I'm using Spring Security too (which may be the source of the problem).
My #Configuration annotated class uses #ComponentScan for packages containing Hibernate based DAOs and a #Bean annotated method for creating the SessionFactory used by the DAOs. At runtime, a exception is thrown, mentioned that 'sessionFactory' or 'hibernateTemplate' was not found. It seems that the DAOs are constructed before the SessionFactory was created. One workaround for me was to put the component scan directive back in a XML file () and replace #ComponentScan with #ImportResource of that file.
#Configuration
//#ComponentScan(basePackages = "de.webapp.daocustomer", excludeFilters = {#ComponentScan.Filter(Configuration.class), #ComponentScan.Filter(Controller.class)})
#ImportResource({"classpath*:componentScan.xml","classpath*:properties-config.xml","classpath*:security-context.xml"})
public class AppConfig
{
...
#Bean
public SessionFactory sessionFactory() throws Exception
{
AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();
bean.setDataSource(dataSource());
bean.setPackagesToScan(new String[] {"de.webapp"});
bean.setHibernateProperties(hibernateProps());
bean.afterPropertiesSet();
return bean.getObject();
}
Also interesting fact: if #ComponentScan is included, a breakpoint set in method sessionFactory() was never reached !
I also had the similar issue with spring-social-sample app.
After I converted field level #Inject to constructor level inject it worked.