Using a class to read a properties file, in Java, spring - java

I'm trying to use a PropertyReader class to get my information (portNumber, hostName, etc) from a test.properties file in java spring, but I am pretty confused on how to go about this because there seems to be a million different ways (resource bundle etc)... I would greatly appreciate any input! Here's what my code looks like. Oh and the names are the same as in the properties file.
#Configuration
#PropertySource("classpath:test.properties")
public class PropertyReader {
private Environment environment;
String portNumber;
String hostName;
String subjectName;
String myUrl;
String portProtocol;
String hostProtocol;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
public PropertyReader(String propertyFile) throws IOException {...}
I've already added
<context:property-placeholder location="classpath:test.properties" />
to my context. but not sure how to go about getting the info as environment.getProperty doesn't seem to be recognized as a function...

For what it's worth, this is how I do it: https://github.com/KevinWorkman/StaticVoidGames/blob/master/StaticVoidGames/src/main/java/com/StaticVoidGames/spring/config/PropertiesConfig.java
An example PropertiesConfig file:
#Configuration
#PropertySource("classpath:/live.properties")
public class PropertiesConfig {
#Value( "${property.name}" )
private String property;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
And here's how I use those properties from a Controller class: https://github.com/KevinWorkman/StaticVoidGames/blob/master/StaticVoidGames/src/main/java/com/StaticVoidGames/spring/controller/StaticVoidGamesController.java
#Component
public class ExampleController implements ExampleControllerInterface{
#Autowired
private Environment env;
public String viewHomePage(HttpServletRequest request, ModelMap model, HttpSession session){
String property = env.getProperty("property.name");
model.addAttribute("propertyValue", property);
return "index";
}
}
But you're right about there being a million different ways to do things. That's what makes programming so fun- and so frustrating!

I would recomend using Typesafe Configuration Properties, it keeps it litle bit cleaner and you do not need to use to many annotations.
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties

Related

Spring boot #Value NullPointerException

I'm writing a Spring Boot application and am trying to load some values from a properties file using the #Value annotation. However, the variables with this annotation remain null even though I believe they should get a value.
The files are located in src/main/resources/custom.propertes and src/main/java/MyClass.java.
(I have removed parts of the code that I believe are irrelevant from the snippets below)
MyClass.java
#Component
#PropertySource("classpath:custom.properties")
public class MyClass {
#Value("${my.property:default}")
private String myProperty;
public MyClass() {
System.out.println(myProperty); // throws NullPointerException
}
}
custom.properties
my.property=hello, world!
What should I do to ensure I can read the values from my property file?
Thanks!
#value will be invoked after the object is created. Since you are using the property inside the constructor hence it is not available.
You should be using constructor injection anyway. It makes testing your class easier.
public MyClass(#Value("${my.property:default}") String myProperty) {
System.out.println(myProperty); // doesn't throw NullPointerException
}
You are getting this error because you are initializing the class with new keyword. To solve this,
first you need to create the configuration class and under this class you need to create the bean of this class.
When you will call it by using bean then it will work..
My code:
#Component
#PropertySource("db.properties")
public class ConnectionFactory {
#Value("${jdbc.user}")
private String user;
#Value("${jdbc.password}")
private String password;
#Value("${jdbc.url}")
private String url;
Connection connection;
#Bean
public String init(){
return ("the value is: "+user);
}
My Config.class:
#Configuration
#ComponentScan
public class Config {
#Bean
public Testing testing() {
return new Testing();
}
#Bean
public ConnectionFactory connectionFactory() {
return new ConnectionFactory();
}
}
Calling it:
public static void main(String[] args) {
AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext(Config.class);
ConnectionFactory connectionFactory= context.getBean(ConnectionFactory.class);
System.out.println(connectionFactory.init());
}




A way to configure the Adapter to autowire via yml

I have a (spring) service sending emails via different client adapters, depending on the environment they run on. So when i am on dev i want to use ClientAdapterA and on live ClientAdapterB. The usage looks like the following:
#Service
public class EmailService {
#Autowired
private ClientAdapter clientAdapter;
public EmailResponse send(EmailRequest emailRequest) {
return clientAdapter.sendMail(emailRequest);
}
}
The configuration i want to happen via my application.yml:
mail:
adapter: ClientAdapterA
I tried to use #Qualifier but that only allows use of one hard-coded adapter:
#Qualifier("ClientAdapterB")
#AutoWired
private ClientAdapter clientAdapter;
I also tried creating a Config class which should provide the respective bean, but that didn't work either:
#Configuration
public class JavaBeansAdapterConfig {
#Value("${mail.adapter}")
private String adapterName;
#Bean
public ClientAdapter clientAdapterImplementation() throws ClassNotFoundException {
ApplicationContext ctx = new AnnotationConfigApplicationContext();
return (ClientAdapter)ctx.getAutowireCapableBeanFactory().createBean(Class.forName(adapterName));
}
}
What am i doing wrong, or is there even a way do do it like i want to? Any help is appreciated, thank you.
Define your Bean by using Class.forName(). But you need to set packageName as well. See below:
#Configuration
public class JavaBeansAdapterConfig {
#Value("${mail.adapter}")
private String adapterName;
private final String packageName = "com.foo.bar";
#Bean
public ClientAdapter clientAdapterImplementation() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
return (ClientAdapter) Class.forName(packageName + "." + adapterName).newInstance();
}
}
I tried with the package name, but this only fixed half the problems. I still could not seem to autowire the sub-dependencies, so I did some more digging and stumbled upon this solution.
My adapter configuration now looks like this:
#Component
#Setter
#Getter
#ConfigurationProperties(prefix = "mail.adapter")
public class ClientAdapterConfig {
#Qualifier("mailClientA")
#Autowired
private ClientAdapter mailClientA;
#Qualifier("mailClientB")
#Autowired
private ClientAdapter mailClientB;
private String name;
#Bean
#Primary
public ClientAdapter getAdapter()
{
ClientAdapter adapter = null;
switch (name) {
case "mailClientA":
adapter = mailClientA;
break;
case "mailClientB":
adapter = mailClientB;
break;
default:
break;
}
return adapter;
}
}
With the #Qualifier annotation I make sure that it puts in the Adapter I want.
Making the Bean #Primary then ensures it is correctly autowired into the EmailService (which remains unchanged compared to the block in the question)
I am aware that this is not actually a Configuration in the Spring sense, but at this point this is good-enough of a replacement for me.

How to read data from java properties file using Spring Boot

I have a spring boot application and I want to read some variable from my application.properties file. In fact below codes do that. But I think there is a good method for this alternative.
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("config.properties");
prop.load(input);
gMapReportUrl = prop.getProperty("gMapReportUrl");
} catch (IOException ex) {
ex.printStackTrace();
} finally {
...
}
You can use #PropertySource to externalize your configuration to a properties file. There is number of way to do get properties:
1.
Assign the property values to fields by using #Value with PropertySourcesPlaceholderConfigurer to resolve ${} in #Value:
#Configuration
#PropertySource("file:config.properties")
public class ApplicationConfiguration {
#Value("${gMapReportUrl}")
private String gMapReportUrl;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
2.
Get the property values by using Environment:
#Configuration
#PropertySource("file:config.properties")
public class ApplicationConfiguration {
#Autowired
private Environment env;
public void foo() {
env.getProperty("gMapReportUrl");
}
}
Hope this can help
I have created following class
ConfigUtility.java
#Configuration
public class ConfigUtility {
#Autowired
private Environment env;
public String getProperty(String pPropertyKey) {
return env.getProperty(pPropertyKey);
}
}
and called as follow to get application.properties value
myclass.java
#Autowired
private ConfigUtility configUtil;
public AppResponse getDetails() {
AppResponse response = new AppResponse();
String email = configUtil.getProperty("emailid");
return response;
}
application.properties
emailid=sunny#domain.com
unit tested, working as expected...
i would suggest the following way:
#PropertySource(ignoreResourceNotFound = true, value = "classpath:otherprops.properties")
#Controller
public class ClassA {
#Value("${myName}")
private String name;
#RequestMapping(value = "/xyz")
#ResponseBody
public void getName(){
System.out.println(name);
}
}
Here your new properties file name is "otherprops.properties" and the property name is "myName". This is the simplest implementation to access properties file in spring boot version 1.5.8.

Spring Boot - Environment #Autowired throws NullPointerException

I have a project setup using Spring Boot 0.5.0.M5.
In one of the configuration files I am trying to #Autowire Environment but that fails with a NullPointerException.
Here's what I have so far:
Application.java
#EnableAutoConfiguration
#Configuration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
JpaConfig.java where I am trying to #Autowire Environment
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.ui.persistence.repository")
public class JpaConfig {
private static final String DATABASE_DRIVER = "db.driver";
private static final String DATABASE_PASSWORD = "db.password";
private static final String DATABASE_URL = "db.url";
private static final String DATABASE_USERNAME = "db.username";
private static final String HIBERNATE_DIALECT = "hibernate.dialect";
private static final String HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String ENTITYMANAGER_PACKAGES_TO_SCAN
= "entitymanager.packages.to.scan";
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty(DATABASE_DRIVER));
dataSource.setUrl(env.getProperty(DATABASE_URL));
dataSource.setUsername(env.getProperty(DATABASE_USERNAME));
dataSource.setPassword(env.getProperty(DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean
= new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(
HibernatePersistence.class);
entityManagerFactoryBean.setPackagesToScan(
env.getProperty(ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(hibernateProperties());
return entityManagerFactoryBean;
}
}
I am trying to load the database properties configured in a properties file. However, the Environment is not injected and the code fails with NullPointerException. I do not have any configuration in XML files.
For the properties file I have configured PropertySourcesPlaceholderConfigurer this way:
#Configuration
#PropertySource("classpath:database.properties")
public class PropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
I have tried swapping #Autowired, #Resource and #Inject but nothing has worked so far. Would appreciate any help. Thanks.
Though your specific problem is solved, here's how to get Environment in case Spring's autowiring happens too late.
The trick is to implement org.springframework.context.EnvironmentAware; Spring then passes environment to setEnvironment() method.
This works since Spring 3.1.
An example:
#Configuration
#PropertySource("classpath:myProperties.properties")
public class MyConfiguration implements EnvironmentAware {
private Environment environment;
#Override
public void setEnvironment(final Environment environment) {
this.environment = environment;
}
public void myMethod() {
final String myPropertyValue = environment.getProperty("myProperty");
// ...
}
}
This is not as elegant as #Autowired or #Value, but it works as workaround in some situations.
I believe there were some lifecycle issues with Spring and the EntityManagerFactory, and you might have fallen foul of those (fixed in 4.0.0.RC1) - if your #Configuration class gets instantiated super early, it might not be eligible for autowiring. You can probably tell from the log output if that is the case.
Just out of interest, did you know that the functionality provided by your JpaConfig and PropertyConfig is already presetn out of the box if you use #EnableAutoConfiguration (as long as you #ComponentScan that package where your repositories are defined)? See the JPA sample in Spring Boot for an example.
I had the same problem on Spring Batch. Writers cannot autowire Environment class because Configuration class was instantiated earlier.
So I created a sort of Singleton (old manner) to instantiate Environment and I could access to it every time.
I did this implementation :
#Configuration
#PropertySource(value = { "classpath:kid-batch.properties" }, ignoreResourceNotFound = false)
public class BatchConfiguration implements EnvironmentAware {
private static Environment env;
public static String getProperty(String key) {
return env.getProperty(key);
}
#Override
public void setEnvironment(Environment env) {
BatchConfiguration.env = env;
}
}
And it works
I was having the similar issue to read properties from my application.properties file in spring boot application. I have struggled a lot to figure out the problem and make it work. Finally I have done. Here is my Constants class which will read properties values from properties file. I hope it will help to someone.
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
#Configuration
#PropertySource("classpath:application.properties")
public class Constants implements EnvironmentAware {
static Environment environment;
#Override
public void setEnvironment(Environment environment) {
Constants.environment = environment;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
public static String getActiveMQHost() {
System.out.println(environment.getProperty("spring.activemq.broker-host"));
return environment.getProperty("spring.activemq.broker-host");
}
public static String getActiveMQPort() {
System.out.println(environment.getProperty("spring.activemq.broker-port"));
return environment.getProperty("spring.activemq.broker-port");
}
public static String getActiveMQUser() {
System.out.println(environment.getProperty("spring.activemq.user"));
return environment.getProperty("spring.activemq.user");
}
public static String getActiveMQPassword() {
System.out.println(environment.getProperty("spring.activemq.password"));
return environment.getProperty("spring.activemq.password");
}
}
These are the property key's declared in my application.properties,
spring.activemq.broker-host
spring.activemq.broker-port
spring.activemq.user
spring.activemq.password

Cannot access properties

I got a Spring MVC application. It runs over the Tomcat 7 server.
I want to make a props.properties file, so my app could access properties during Beans initialization process.
So i did the following:
1.Create a context-parameter to my web.xml
<context-param>
<param-name>mainProps</param-name>
<param-value>${catalina.home}/conf/props.properties</param-value>
</context-param>
2. I created a MainCobfig class
#Configuration
#PropertySource("classpath:/racoonsoft/wish/properties/props.properties")
#Import({WebConfig.class })
public class MainConfig {
#Autowired
Environment env;
#Value("${db.host}")
static String dbHost;
#Value("${db.name}")
static String dbName;
#Value("${db.login}")
static String dbLogin;
#Value("${db.password}")
static String dbPassword;
#Value("${ozon.login}")
static String ozonLogin;
#Value("${ozon.password}")
static String ozonPassword;
#Value("${ozon.apiurl}")
static String ozonApiUrl;
#Value("${payture.apihost}")
static String paytureApiHost;
#Value("${payture.merchant}")
static String paytureMerchant;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationBeanPostProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
#Bean
public OzonProcessor apiProcessor() {
return new OzonProcessor(ozonLogin, ozonPassword, ozonApiUrl);
}
#Bean
public PGSQLDataSource pgsqlDataSource() throws Exception{
PGSQLDataSource result = new PGSQLDataSource(dbHost,dbName,5432,dbLogin,dbPassword,"org.postgresql.Driver","jdbc:postgresql:");
result.loadSettings();
if(FacebookController.dbProc==null)
{
FacebookController.dbProc = result;
}
//FacebookController.dbProc = result;
return result;
}
#Bean
public PaytureProcessor paytureProcessor()
{
PaytureProcessor proc = new PaytureProcessor(paytureApiHost,paytureMerchant);
return proc;
}
}
3 - I created props.properties file and put it into /conf directory
When i start my application it didnt throw the exception (file not found) - so i beleave it sees the properties file. But during bean initialization my fields (dbHost,dbLogin etc.) are still null`s.
How can i put values from properties file to my fields?
Help me please.
The annotated factory method of PropertySourcesPlaceholderConfigurer MUST be a static method:
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Spring API Reference manual of #Bean remarks this.
A little bit more detailed explanation:
This is because PropertySourcesPlaceholderConfigurer is a BeanFactoryPostProcessor (BFPP).
BFPP does a post-processing on the bean factory just before other (normal) beans are being instantiated and intialized. So, BFPP's are needed to be created in order to work, before the MainConfig bean is instantiated. Marking this factory method as a static method, we can invoke this method without instantiating MainConfig.
# form user login properties
userName.required = User Name is required
In controller side you declare only userName.required. That's how you declare it.

Categories

Resources