How to read properties file with IntelliJ - java

I have a Spring Boot service, and I'm using IntelliJ to run it. I have a file call "application.properties" in my resources folder. I want intelliJ to read that .properties file, how do I do that? the only way I get it to use the properties in .properties file is to add them directly to Environment VM Option.
I tried doing things like
-Dspring.config.location:/src/main/resources/application.properties but that doesnt work.
Folder Structure:
Services
-src
-main
-resources
-application.properties
-target
-pom.xml
#Component
#Configuration
#EnableAutoConfiguration
#PropertySource({ "classpath:application.properties"})
#EntityScan(basePackages = "com.org")
public class AppConfig {
}

In case of Spring Boot, you don't have to pass any option when starting boot application.
When Spring boot application loads, it automatically checks if properties file exists in certain locations including src/main/resources, src/main/resources/config.
If you keep your properties file in these folders, the app automatically picks up the files and register properties. So in your AppConfig you don't need #Component, #EnableAutoConfiguration, #PropertySource, and #EntityScan because #Configuration already includes #Component which enables #Value to work.
I think the problem may arise when you call the property in the constructor of AppConfig because when the class is being constructed the #Value is not injected yet.
If you want to check if the property value is injected by Spring you can make a small test in the application class such as following
#SpringBootApplication
public class ApppropApplication {
#Autowired
private AppConfig appConfig;
public static void main(String[] args) {
SpringApplication.run(ApppropApplication.class, args);
}
#PostConstruct
public void init(){
System.out.println(appConfig.getTestProperty());
}
}
If your problem still exists, it would be great to provide more info (error logs and entire class structure)
Hope this helps! Happy Coding :)

The ideal way for your springboot project to include the properties file would be to import using the annotation "#PropertySource" in your starter class. Please re check your starter class. It should include something like this below
#PropertySource({ "classpath:application-example.properties"})
#EntityScan(basePackages = "com.org")
public class YourProjectLauncher extends SpringBootServletInitializer {
#Value("${your.db.url}")
private transient String dataSourceUrl;
#Value("${your.db.username}")
private transient String userName;
#Value("${your.db.password}")
private transient String password;
#Value("${your.db.driver-class-name}")
private transient String driverClass;
public static void main(String... args) {
SpringApplication.run(YourProjectLauncher.class, args);
}
Let me know if you have already done this and still facing the issue.
Also it would be best if you add the starter class in your question, that way it is easier to analyse the problem you are facing.
Note - If you have already done this, please add more information to the question, will be happy to help.

Related

How do I resolve spring configuration property without #ConfigurationProperties?

I'm using Java 8 and Spring Boot. And I'm trying to solve the warning "Cannot resolve configuration property" from IDEA:
(application.properties)
But for this param I don't have any #ConfigurationProperties class to be handled by the "spring-boot-configuration-processor"
I'm only using this param like this:
import org.springframework.beans.factory.annotation.Value;
#Value("${some.param}")
private String param;
I tried to create de metadata file manually but that didn't solve the problem either.
Does anyone have a tip for this?
This is my Application Class:
#SpringBootApplication
#EnableConfigurationProperties
#ComponentScan(basePackages = {"com.sample"})
#ConfigurationPropertiesScan
#EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Looks like you can use additional metadata for this. Although it would be nice to automatically generate this from the #Value (or similar) annotation automatically...
https://docs.spring.io/spring-boot/docs/current/reference/html/configuration-metadata.html#appendix.configuration-metadata.annotation-processor.adding-additional-metadata

#ComponentScan doesn't work in my Minecraft plugin

I am creating a plugin for Minecraft server in which I use this SpringFramework. And I use JavaConfig + Annotations, but my project couldn't normally in runtime due to #ComponentScan.I discovered the fact that this is only in the Minecraft server plugin, but I could be wrong. Although in a normal Spring project everything is scanned normally
I have a directory like this: me.stordshally.testplugin
Main class (me.stordshally.testplugin.Main)
public class Main extends JavaPlugin {
private User user;
#Override
public void onEnable() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
user = context.getBean(FacebookUser.class);
}
}
JavaConfig (me.stordshally.testplugin.SpringConfig)
#Configuration
#ComponentScan
public class SpringConfig {
}
Component (me.stordshally.testplugin.FacebookUser) (exists also User interafce in that directory)
#Component
public class FacebookUser implements User {
#Override
public String getNet() {
return "Facebook";
}
}
And at the moment context.getBean I get this exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'me.stordshally.testplugin.FacebookUser' available
onEnable - starts when the server starts, consider it as an analog of psvm.
Why is this happening? How can I fix my ComponentScan?
Github for test: https://github.com/Prot-CN/SpringBug
Ideally, some more information would have helped, however, I do not know what the src package structure looks like but try explicitly providing base package like
#ComponentScan(basePackages = "me.stordshally.testplugin")
This tells spring explicitly where to look for potentials beans to create. Please make sure you provide the path under which all your beans are located.
If this doesn't work, it means for some reason your application is failing, try running your app in debug mode by setting log-level to debug. It will tell where the issue is. it's the best I can tell from the info provided, Hope this helps.

Spring boot how to pick externalized spring properties file

I have this configurations which needs to be used for a spring boot application.
server.port=8085
server.servlet.context-path=/authserver
#data source
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=<url>
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
By default spring-boot picks up up the application.properties file located in src/main/resources/
I want to alter this path and direct spring boot to different application.properties file
I can achieve this using
java -jar app.jar --spring.config.location=classpath:/another-location.properties
Is there any any alternative solution I can achieve this without passing args through command line?
I was using this
#PropertySource("file:C:\Users\test\.test\test.properties")
#ConfigurationProperties(prefix = "spring")
public class Configuration {
private String ddlAuto;
private String url;
private String username;
private String password;
private String driverClassName;
}
in my Main class
#SpringBootApplication
#EnableConfigurationProperties(Configuration.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
There after I tried executing the app commenting out all datasource properties in application.properties under src/main/resources/
But it keeps giving me the error mentioned bellow and application fails to start
I was referring this tutorial : https://www.mkyong.com/spring-boot/spring-boot-configurationproperties-example/
but as it's mentioned I get this error when i start the spring boot application
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException:
Any help on this would be appreciated
The recommended way to have externalized properties is to use the spring.config.location system property, by starting your application like so:
java -jar -Dspring.config.location=/path/to/my/file.properties app.jar
The reason for this is that you don't add coupling between your code and your filesystem hierarchy.
Before Spring Boot 2.0 this property is additive, meaning that it will complement the default locations. After Spring Boot 2.0, spring.config.location replaces the default locations (e.g. classpath src/main/resources/application.properties). To keep the additive behaviour after 2.0, use spring.config.additional-location instead.
Please see here for official documentation on this matter.
I am able to make it work properly on Spring Boot 2.1.2.RELEASE. This is what I have done:
I have a test.properties in my /tmp folder with the following content:
test.myprop=hello
I also have the usual property file in the resources folder:
myprop=world
I have created a class for the custom property file:
#Configuration
#PropertySource("file:/tmp/test.properties")
#ConfigurationProperties(prefix = "test")
public class TestConfig {
private String myprop;
public String getMyprop() {
return myprop;
}
public void setMyprop(String myprop) {
this.myprop = myprop;
}
}
And then in my main class I have enabled to configuration properties:
#EnableConfigurationProperties(TestConfig.class)
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Now I have this test controller:
#RestController
public class TestController {
#Value("${test.myprop}")
private String externalisedProp;
#Value("${myprop}")
private String prop;
#GetMapping("test")
public void test() {
System.out.println("externalised: " + externalisedProp);
System.out.println("not externalised" + prop);
}
}
Which, once called, is properly printing:
externalised: hello
not externalised: world
My TestConfig class is in the same package as the MyApp main class.
What I have done is very similar, almost identical, to your solution, are you sure your path is correct? Also, I can see that the content of your property file is not matching what you have in your config class, the prefix is different. Maybe that is the problem?
Edit:
I have tried to remove the #Configuration annotation from my property class (which you do not have as well) and it is not able to pick up the externalised properties anymore. The error is different though but you should try to add it.

How to load a properties file based on the server environment with spring so that the values can be injected?

To my surprise I have had a difficult time finding an answer to this question. I have Seen many examples where you can use #PropertySource to load a specific properties file for a class. I have also seen examples where you can easily add different property files in spring boot projects. But what I want to do is to do this for a spring project that is NOT spring boot and load a properties file so that the values of this file can be injected in classes annotated with #Component which is dependent on the server environment. So for example if I am on development server I want a particular properties file loaded and on production a different properties file. The reason that I am doing it like this is because my data and service layers are their own modules. These modules contain their own unit tests and can be imported as their own modules in other spring boot projects. I need properties files to be loaded to serve these modules which use spring but not spring boot. I have tried the following, but this does not work.
#Configuration
#Profile("test")
#EnableJpaRepositories("com.hi.repository")
#EnableTransactionManagement
#EnableScheduling
public class InfrastructureConfig {
...
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
Map<String, String> env = System.getenv();
String propertiesFile=null;
String e = env.get("SERVER_ENV");
if (e.equals("dev")) {
propertiesFile = "environment/development.properties";
} else if (e.equals("prod")) {
propertiesFile = "environment/production.properties";
}
configurer.setLocation(new ClassPathResource(propertiesFile));
return configurer;
}
Then I have a test which looks like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/spring/DealServiceTest-context.xml"})
#ActiveProfiles("test")
public class LogTest {
private static final Logger log = LogManager.getLogger(LogTest.class);
#Autowired
PathsService pathsService;
#Autowired
Environment environment;
#Test
public void testBeans(){
System.out.println("********** WASSUP from LogTest");
System.out.println(environment.getProperty("imageBucket"));
}
Although the test prints out null which indicates to me the properties file has not been loaded and prepared for its values to be injected. How can I achieve this?
You don't really need to set properties yourself, but you can do this using spring configuration. Check the documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties
If you're using spring boot - all you need to do is create multiple properties file for your environments. And only for properties you need to override.
So your main properties file would be at
src/main/resources/application.properties
Production
src/main/resources/application-prod.properties
Development
src/main/resources/application-dev.properties
Testing
src/main/resources/application-test.properties
And then just use the profile name as your environment variable
java -jar -Dspring.profiles.active=prod demo-0.0.1-SNAPSHOT.jar
Actually, you can just use a placeholder in #PropertySource annotation.
See documentation:
Any ${...} placeholders present in a #PropertySource resource location will be resolved against the set of property sources already registered against the environment.
Assuming that placeholder is present in one of the property sources already registered, e.g. system properties or environment variables, the placeholder will be resolved to the corresponding value.
I've made a simple example, it receives a 'property.environment' value to choose, which .properties file should be used as property source. I have two resource files in my classpath - application-test.properties and application-dev.properties, each one contains a 'test.property' value ('test-env' and 'dev-env' respectively).
Property configuration:
#Configuration
#PropertySource("classpath:/config/application-${property.environment}.properties")
public class PropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
return propertySourcesPlaceholderConfigurer;
}
}
Component with #Value
#Component
public class TestService {
#Value("${test.property}")
String testProperty;
#PostConstruct
void init() {
System.out.println("---------------------------------------------------------");
System.out.println("Running in " + testProperty + " environment");
System.out.println("---------------------------------------------------------");
}
}
Build command line example (it runs tests with test environment properties)
mvn clean install -DargLine="-Dproperty.environment=test"
Output
---------------------------------------------------------
Running in test-env environment
---------------------------------------------------------
Run command line example
java -jar -Dproperty.environment=dev PATH_TO_YOUR_JAR.jar
Output
---------------------------------------------------------
Running in dev-env environment
---------------------------------------------------------
Don't hard code based on different environment, in spring boot you can able to maintain properties specific environment easily. Refer https://spapas.github.io/2016/03/31/spring-boot-settings/
I would try to take advantage of the profile mechanism already in place in Spring. You basically have done the job yourself already, the only thing you need to change is to have different configurations for "test" and "production" profiles. I prefer to keep everything related to test away from production code (allowing me to place the TestConfig class below in the test source path), so I would probably do something like this:
#Configuration
#Profile("!test")
#PropertySource(value = "classpath:/environment/production.properties")
#Import(AppConfig.class)
public class ProductionConfig
{
// Your production-specific config goes here
}
#Configuration
#Profile("test")
#PropertySource(value = "classpath:/environment/development.properties")
#Import(AppConfig.class)
public class TestConfig
{
// Your test-specific config goes here
}
#Configuration
public class AppConfig
{
// Needed for spring to handle ${property:default} syntax
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
}
If you prefer to have one config for both cases, you can let the AppConfig import the TestConfig and the ProductionConfig instead, but that will put test code in to production...
Good luck with your project!

Spring Boot auto configuration order from external dependency

I have a problem trying to get my autoconfiguration working. I have two jars as follows, each have a spring.factories file where these two are enabled for EnableAutoConfigurationProperties.
This configuration is in my-package-mock.jar, it depends on my-package-real.jar below:
package org.packages.package.packageA;
#Configuration
#AutoConfigureBefore(AutoConfigurationB.class)
public class AutoConfigurationA {
#Bean
public MyService mockService() {
return new MyMockService();
}
}
This configuration is in my-package-real.jar:
package org.packages.package.packageB;
#Configuration
#ConditionalOnMissingBean(MyService.class)
public class AutoConfigurationB {
#Bean
public MyService realService() {
return new MyRealService();
}
}
Now the idea is that if my-package-mock.jar is included then AutoConfigurationB will not be processed as A is ordered to be before and by the time it gets to B MyService is already defined.
However, it does not work when used in a third project that includes these jars. It looks like the AutoConfigureOrder annotation is skipped when loading these jars from the classpath and these configurations are processed in the order the jvm loads these classes. In my particular case it does B first and at that point MyService is not yet defined and thus will instantiate the RealService bean. How can I get this to work?
Obviously this is a small example where a #Primary annotation on the mock will do the job, but that is not what I'm looking for.
Edit: it seems if the #SpringBootApplication annotated main is not a part of the package where these configurations are then things do work. E.g. the annotation is not in "org.packages.package" but "org.somewhereelse" then things work.
package org.packages.package;
#SpringBootApplication
public class TestApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(Collections.singletonList(TestApplication.class).toArray(), args);
}
}
#AutoConfigureBefore and #AutoConfigureAfter only apply when a configuration class is loaded as a result of auto-configuration being enabled and it being listed in spring.factories. When your auto-configuration classes are in org.packages.package (or a sub-package) and your main application class is in the same package, they're being found by Spring Framework's standard component scanning. This happens because #SpringBootApplication enables component scanning for the package of the class that it's annotating. As a result of this the auto-configuration-specific ordering doesn't apply.
To avoid the problem, you should places your auto-configuration classes in a package that isn't used by any application code.

Categories

Resources