Single application.properties for main and test module - spring

I do have a lot of shared properties across my main and test module. It seems that when running the modules the only properties that are picked up are located inside the <module>/resources/application.properties the documentation does not mention the resource folder, while there is nothing in my grade configuration.
Have anyone had any success with sharing properties across modules without having to:
* use spring.config.location
* copy the configuration as part of the gradle script
* have a custom configuration in IntelliJ to use the correct config file

You could create an application-test.properties file in src/test/resources and make all your tests use the test profile, which will overlay the default application.properties file values.
This allows you to use your defaults but change only the props you need different for testing.
This also allows you to create different test profiles for different types of tests - by simply creating a new file and specifying a different profile.
See Also: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html

Related

Spring Boot Managing Properties File

I am trying to revamp my microservice to maintain a single application yaml rather maintaining multiple profiles. Initially I was maintaining different profiles and the common configurations were repeated across the helm environment specific values yaml. Now the strategy is to move everything to values.yml and maintain environment specific values in config map. The problem I face is my application yml now looks very generic with placeholders and for the same reason the test runs fails as I cannot give a default value for each of the configurations in application.yml. The reason being, For Eg: mongodb cluster endpoint format is different in local to other environment. I managed to place a local specific yaml file under test/resources, but not sure it's the right approach. I need to anyway maintain a local specific yaml under main/resources for running locally. So essentially I am duplicating it under test resources as well. Is there any better way of pointing test to load the application-local.yml under main resources so that I can avoid the duplication or is there any better way of doing this as a whole?
1. Working with multiple configs in One File
You can add all your configurations in one property file as illustrated below
spring.application.name: test. ## Used for all profiles
---
spring.config.active.on-profile:dev
spring.database.host: localhost
spring.database.name: testing
---
spring.config.active.on-profile:prod. ##You can use spring.profiles:prod
spring.database.host: localhost
spring.database.name: testing
---
--- marks where yml document splits, while #--- marks where properties file splits.
Multi-document property files are often used in conjunction with the following activation properties
spring.config.activate.on-profile
spring.config.activate.on.on-cloud-platform
All property definitions defined without specifying the profile name are used on all profiles. In the above case spring.application.name will be used on all profiles dev or prod.
When running the application you can manually specify profile or you can set in within the yml or properties on properties that are used throughout the application.
spring.application.name: test
spring.profiles.active: prod
2. Testing your application
when running tests that need to access properties in yml(property)file there is
no need to redefine your configurations.Just add #ActiveProfile("profile-name")
on your tests.
for example:
#ActiveProfiles("dev")
#SpringBootTest(webEnvironmentSpringBootTest.WebEnvironment.RANDOM_PORT)

Ignore .spring-boot-devtools.properties in tests

Spring Boot devtools allow you to define global configuration outside of your application sources by placing a file .spring-boot-devtools.properties into your home directory, which takes precedence over the bundled configuration, according to:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
However, this file also applies when running unit tests, so if you have tests that depend on some configuration, either the defaults defined in bundled application.properties or in test-specific properties defined by #TestPropertySource, they are still overridden by the global values and your build breaks.
Is there some reasonable way how to either ignore the .spring-boot-devtools.properties or to exclude the devtools from the test classpath altogether (we're using Gradle)?

Simplifying deployment configs for SpringMVC project

We've multi module SpringMVC project, each having separate applicationContext.xml, currently we have to edit the applicationContext.xml files for every module before we deploy. It's painful and error prone. Is there a way to have only one property file that all other will contexts look at. Then we only have to edit one property file before we build and deploy. Thanks in advance.
It sounds like you should be using Spring's Profile support, which allows you to specify separate properties files per environment. You can pass the application an environment property spring.profiles.active and set it to say, "dev", "test", or "prod".
If you're using Spring Boot it can then automatically pick up distinct configuration per environment, application.dev.properties or application.prod.properties which will overwrite the standard application.properties with environment specific configuration.
If not using Spring Boot you would just have configure your Properties Sources per profile.
This is most definitely the preferred approach to changing configuration files at build or deploy time.
Reference: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-environment

How to make Spring Boot skipping some configurations

I have a Spring-Boot project which works with DB-connections and a lot of other stuff.
Now I added another "main-class" to the project. The thing is: by starting this class, all configuration settings (which come from application.yml) are loaded. But thats not what I want.
I want the project to start without trying to bind to any datasource...
But how?
Why do you add several main classes? Try using different profiles instead. And you can start your application with the -Dspring.profiles.active=? property.
Example:
Just add a application-test.properties and run your application with -Dspring-profiles.active=test and the properties in the test property file will be loaded. And potentially overwrite properties with the same key in application.properties.

Spring boot application.properties maven multi-module projects

We are using spring boot in a multi-module project.
We have a Domain access module which has the common domain object classes, repositories, together with configuration for the datasource, JPA, Hibernate, etc. These are configured using a application.properties. We put all this configuration into the common module to save duplicating these common configurations in the higher level modules.
This all works fine when building the domain module, so the configurations are loaded correctly in the test units.
However the problems start when we try to use the domain module in the higher layer modules; they have their own application.properties which means Spring loads them and not the the Domain module application.properties, which this means the data source is not configured because only the higher module application.properties are loaded.
What we would like is both the domain module and higher level application properties to be loaded by Spring. But we can't see any easy way to do this.
I'm thinking this must be a common problem, and wonder if there any recommended solutions for this problem?
As we are using spring-boot the solution should ideally use annotations instead of applictionContext.xml.
Maybe you should only use application.properties in the top-level aggregator project?
You can always use #PropertySource in the child projects to configure them with a name that is specific to their use case.
Or you can use different names for each project and glue them together in the top-level project using spring.config.location (comma-separated).
I agree with #Dave Syer. The idea of splitting an application into multiple modules is that each of those is an independent unit, in this case a jar file. Theoretically you could split each of those jar files into their own source repositories, and then use them across multiple projects. Let's say you want to reuse these domain classes in both a web and batch application, if all the APPLICATION level configuration is stored within each of the individual modules, it severely reduces their reusability.
IMO only the aggregating module should contain all of the configuration necessary to run as an application, everything else is simply a dependency that can be remixed and reused as necessary.
Maybe another approach could be to define specific profiles for each module and use the application.properties file just to specify which profiles are active
using the spring.profiles.include property.
domain-module
- application.properties
- application-domain.properties
app-module
- application.properties
- application-app.properties
and into the application.properties file of app-module
spring.profiles.include=domain,app
Another thing you can do (besides only using application.properties at the top-level as Dave Syer mentions) is to name the properties file of the domain module something like domainConfig.properties.
That way you avoid the name clash with application.properties.
domainConfig.properties would contain all the data needed for the domain module to be able to tested on it's own. The integration with the rest of the code can easily be done either using multiple #PropertySource (one for domainConfig.properties and one for application.properties) or configuring a PropertySourcesPlaceholderConfigurer bean in your Java Config (check out this tutorial) that refers to all the needed property files
in spring-boot since 2.4 support spring.config.import
e.g
application.name=myapp
spring.config.import=developer.properties
# import from other module
spring.config.import=classpath:application-common.properties
or with spring.config.activate.on-profile
spring.config.activate.on-profile=prod
spring.config.import=prod.properties
ref: https://spring.io/blog/2020/08/14/config-file-processing-in-spring-boot-2-4

Resources