Override Spring properties without using profiles - spring-boot

I have few property files(application.properties) which contains both custom and spring configuration under classpath, i want load these properties based on system variables.
I used PropertySourcesPlaceholderConfigurer to load properties as below.
#Bean
public PropertySourcesPlaceholderConfigurer loadResources() {
PropertySourcesPlaceholderConfigurer resourceConfigurer = new PropertySourcesPlaceholderConfigurer();
resourceConfigurer.setLocations(new ClassPathResource("file1"), new ClassPathResource("file2"));
return resourceConfigurer ;
}
But it failed to override spring configuration(spring configurations added in application.properties), i want to override these files after spring picks application.properties file.
Idea is to override spring configuration programmatically.
How this can be achieved?

I was able to achieve above using EnvironmentPostProcessor.
spring doc

Related

Define properties in a custom file, for Spring data JPA

I have a custom properties file for my spring boot application for database configurations. I use spring data JPA for persistence, By default spring boot choose application.properties to load the configurations.
How to avoid it and use any custom file, to read the database configuration on application startup
Example : database-connection.properties
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://ip:5432/HP
spring.datasource.username=hpadmin
spring.datasource.password=hp#12345
Thank you
You will avoid future complications if you use just one and the classic application.properties.
Spring requires more than just database configurations so replace the entire application.properties by a simple database-connection.properties is not a good idea.
Anyway, if you need to add more properties alongside application.properties you could use
one of the following approaches:
PropertyPlaceholderConfigurer
You could load extra properties alongside the application.properties or replace it entirely if you delete the application.properties
In your main class:
#Configuration
public class PropertiesConfiguration {
#Bean
public PropertyPlaceholderConfigurer properties() {
final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setIgnoreResourceNotFound(true);
final List<Resource> resourceLst = new ArrayList<Resource>();
resourceLst.add(new ClassPathResource("database-connection.properties"));
ppc.setLocations(resourceLst.toArray(new Resource[]{}));
return ppc;
}
Shell
You could replace the entire application.properties file at the moment of run of your jar with spring parameter --spring.config.location
java -jar app.jar --spring.config.location=/foo/bar/database-connection.properties
PropertySource
Similar to PropertiesConfiguration but without java code, just #annotations
#PropertySources({#PropertySource(value = "classpath:database-connection.properties")})
public class Application {

Creating a custom FactoryBean in Sprint Boot 2.3/Spring 5

I've got a spring-boot web application that's mostly working; my DataSource is properly configured by an external application.properties file.
Now I want to add properties to that file to help me instantiate and configure two instances of a class in my app. I have a APNsFactory that I currently instantiate manually and configure using JNDI, but I want to get away from JNDI calls:
#Bean
public
APNsFactory
apnsFactory()
throws
javax.naming.NamingException
{
sLogger.info("Configuring APNsFactory");
InitialContext ctx = new InitialContext();
APNsFactory f = new APNsFactory();
f.setProductionKeystorePath((String) ctx.lookup("java:comp/env/apns/prod/keystorePath"));
f.setProductionKeystorePassword((String) ctx.lookup("java:comp/env/apns/prod/keystorePassword"));
f.setDevelopmentKeystorePath((String) ctx.lookup("java:comp/env/apns/dev/keystorePath"));
f.setDevelopmentKeystorePassword((String) ctx.lookup("java:comp/env/apns/dev/keystorePassword"));
return f;
}
When running before in a standalone webapp container, Spring properly called that method and the JNDI context from the container’s <env-entry> tags was available.
I'm trying to update my APNsFactory to be a proper Spring FactoryBean<>, and I’ve given it a couple of #Autowire String variables that I want to be set by Spring Boot from the application.properties file.
For bonus points, I want this to be usable both in Spring Boot and in a standalone container like Tomcat or Resin.
For the life of me, I can't figure out how to get Spring to do this. There are dozens of examples for DataSources and other Beans already implemented by Spring, but none for a completely custom one, using application.properties, in a Spring Boot web environment.
I've seen some examples that use an XML config file, but I'm not sure how to do that with Spring Boot.
I don't think you need a factory bean here.
You already have spring boot that can read application.properties out-of-the-box:
So try the following:
Create key/values in the application.properties file:
myapp.keystore.path=...
myapp.keystore.passwd=...
// the same for other properties
Create ConfigurationProperties class
#ConfigurationProperties(prefix="myapp.keystore")
public class MyAppKeyStoreConfigProperties {
private String path; // the names must match to those defined in the properties file
private String passwd;
... getters, setters
}
In the class marked with #Configuration (the one where you create #Bean public APNsFactory apnsFactory()) do the following:
#Configuration
// Note the following annotation:
#EnableConfigurationProperties(MyAppKeyStoreConfigProperties.class)
public class MyConfiguration {
// Note the injected configuration parameter
#Bean public APNsFactory apnsFactory(MyAppKeyStoreConfigProperties config) {
APNsFactory f = new APNsFactory();
f.setProductionKeystorePath(config.getKeyPath());
and so on
}
}
I've intentionally didn't show the separation between production/dev stuff.
In spring boot you have profiles so that the same artifact (WAR, JAR whatever) can be configured to run with different profile and depending on that the corresponding properties will be read.
Example:
If you're running with prod profile, then in addition to application.properties that will be loaded anyway, you can put these keystore related definitions to application-prod.properties (the suffix matches the profile name) - spring boot will load those automatically. The same goes for dev profile of course.
Now I haven't totally understand the "bonus points" task :) This mechanism is spring boot proprietary way of dealing with configuration. In "standalone" server it should still have a WAR with spring boot inside so it will use this mechanism anyway. Maybe you can clarify more, so that I / our colleagues could provide a better answer

Split jackson configuration into separate properties

I'm using Spring Boot 2.2.5.RELEASE and would like to split my application.properties into separate files. There are already similar questions on StackOverflow but none of them seem to work for configuring Jackson.
My current non working solution is the following:
root/
- application.properties (without Jackson configuration)
- jackson-configuration.properties (includes Jackson configuration)
Jackson configuration class:
#Configuration
#PropertySource("/jackson-configuration.properties")
public class JacksonConfiguration {
}
Please note, I've tried different ways to specify the path including:
"/jackson-configuration.properties"
"jackson-configuration.properties"
"classpath:/jackson-configuration.properties"
"classpath:jackson-configuration.properties"
Spring Boot does not seem to use the configuration. If I copy it over into the application.properties - it works.
Content of jackson-configuration.properties:
spring.jackson.property-naming-strategy=SNAKE_CASE
spring.jackson.mapper.sort-properties-alphabetically=true
spring.jackson.deserialization.fail-on-unknown-properties=true
spring.jackson.parser.strict-duplicate-detection=true
spring.jackson.time-zone=Europe/Zurich
My application is annotated with #SpringBootApplication , so it should scan for additional properties.
/edit
I just realized the problem is the testing, not the productive code itself. If I start the application it works. What doess not work is testing with #JsonTest. I can fix this problem by adding the following line to my tests #ContextConfiguration(classes = {JacksonConfiguration.class}). But in turn, this causes the annotation #JsonComponent to stop working but only for the #JsonTest annotated classes.
See the documentation here. Here is an excerpt from the documentation
In order to resolve ${...} placeholders in definitions or
#Value annotations using properties from a PropertySource, you must
ensure that an appropriate embedded value resolver is registered in
the BeanFactory used by the ApplicationContext. This happens
automatically when using in XML. When
using #Configuration classes this can be achieved by explicitly
registering a PropertySourcesPlaceholderConfigurer via a static #Bean
method.
You need to create a bean like this
#Bean
public static PropertySourcesPlaceholderConfigurer devPropertyPlaceholderConfigurer() throws IOException {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocations(new PathMatchingResourcePatternResolver().getResources("file:pathtToFile"));
configurer.setIgnoreUnresolvablePlaceholders(true);
return configurer;
}

Spring Activiti workflow configure custom schema

I am using Spring Activiti workflow in my project and the engine is generating their own tables to my datasource. How can I configure it to generate these tables to a different schema instead of my default?
You need to over-ride default data-source for activiti.
You will need to add spring-boot-configuration-processor as maven dependency
and you need to define data-source for activiti like :
#Autowired
private DataSourceProperties properties;
#Bean(name = "datasource.activiti")
public DataSource activitiDataSource() {
return DataSourceBuilder.create(this.properties.getClassLoader())
.url(this.properties.getUrl())
.username(this.properties.getUsername())
.password(this.properties.getPassword())
.driverClassName(this.properties.getDriverClassName())
.build();
}
For detailed steps for changing data-source, follow this blog.

Spring Boot Override Properties Externally

I have a Spring Boot application that is getting deployed as a WAR to a Tomcat server. There is already a currently deployed Spring Boot application on Tomcat server that has an application.properties file on classpath that is overriding the one bundled in the WAR. I need to do the same thing for my application, but I can't use the name application.properties as it is already taken, and my application is trying to use the application.properties on the classpath from Tomcat, which is intended for the other Spring Boot application.
Is there a way I can tell Spring Boot to look for a properties file on the classpath called myapp.properties or something along those lines?
I tried doing the following, but it doesn't seem to work when being deployed as a WAR.
#SpringBootApplication
public class ParameterManagerApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ParameterManagerApplication.class)
.properties("spring.config.name:parameter-portal")
.build()
.run(args);
}
}
By default, Spring Boot looks for the application.properties file in these locations.
/config subdir of the working directory
The working directory
config package in the classpath
classpath root
So, the following worked for us when we placed myserver.properties under any of these locations.
public static void main(String[] args){
System.setProperty("spring.config.name","myserver");
SpringApplication.run(Application.class,args);
}
Otherwise, You can try setting the spring.config.location as below.
new SpringApplicationBuilder(Application.class)
.properties("spring.config.name:application,myserver",
"spring.config.location:classpath:/external/myproperties/")
.build().run(args);
We can also optionally define a custom source where we’re storing these properties, else the default location (classpath:application.properties) is looked up. So we now add the above annotations to the existing properties class:
#Configuration
#PropertySource("classpath:configprops.properties")
#ConfigurationProperties(prefix = "dev")
public class ConfigProperties {
// previous code
}
Now any properties defined in the property file that has the prefix dev and the same name as one of the properties are automatically assigned to this object.
#Simple properties
dev.host=mailer#mail.com
dev.port=9000
Check this

Resources