How to override Spring Boot library properties? - java

I would like to override the library properties that I've written in project that is using it. I'm using this Spring guide on creating library: https://spring.io/guides/gs/multi-module/
I would like to know how to override for example my.properties file in the project that uses my library.
Is it even possible?

Do not add application.properties files to a library. It could cause a myriad of problems. If you want to set a default property do it like this:
#ConfigurationProperties("foo")
public class FooConfig {
private int bar = 999;
// getter / setter
}
Every application should configure the library values for itself in its own application.properties file.

Seems you cannot. Since Spring itself also cannot
In the sample above we have configured the service.message for the test using the default attribute of the #SpringBootTest annotation. It is not advisable to put application.properties in a library because there might be a clash at runtime in the application that uses it (only one application.properties is ever loaded from the classpath). You could put application.properties in the test classpath, but not include it in the jar, for instance by placing it in src/test/resources.

Spring Boot property order precedence is described here:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
From the link:
Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order:
The order is 1-17 then. For example, 4 on the list (command-line arguments) overrides 15 on the list (your application.properties file) and so on.

Depends on how the library property file specifies properties. If the properties are looked up from environment/system first, then you can override in your code. If hard-coded, then not.
For example:
prop=${ENV_VAR:abc}
You can set ENV_VAR environment variable, or env-var system variable in your code to override the value of prop. If you don’t, the default value abc will be used.

Related

How to overwrite config in a Quarkus extension

Is there a way to overwrite a configuration in a Quarkus extension with a hard-coded value?
What I'm trying to do: I am creating a custom Quarkus extension for JSON logging, based on quarkus-logging-json but with additional (non static) fields. I reuse some classes from the extension's runtime library, so it is a Maven dependency of the runtime module of the extension (and the deployment also needs to be declared as a dependency to my deployment module, because the quarkus extension plugin checks this).
It seems to work fine, except that I now have 2 formatters, and the following line is logged:
LogManager error of type GENERIC_FAILURE: Multiple console formatters were activated
I would like to disable the quarkus-logging-json extension completely by hard-coding these values:
quarkus.console.json.enable=false
quarkus.file.json.enable=false.
Is there a way to do this?
Thank you.
An extension cannot override runtime configuration values, it can however set a default value using io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem

Java Microprofile change properties on already deployed app (Wildfly)

I have an ear artifact deployed on a wildfly server. On some beans I used the following configuration injection
#Inject
private Config config;
I want to change the properties specified on the "microprofile-config.properties" file on runtime. It is not necessary to change the file itself, I just want to change the properties. I think there might be a way using the console, but I cannot find if there is any.
If you take a look at the spec or even at articles like this, you will see that, by default, Microprofile config reads configuration values from the following 3 places in this order - i.e. from wherever it finds it first:
System.getProperties()
System.getenv()
The configuration file
So, you can override values in the configuration file in 2 ways:
Defining -D command line arguments to the VM (e.g. java -DXXX=yyy ...)
Defining system environment variables (e.g. export XXX=yyy in bash or set XXX=yyy in Windows)
Note that there are some rules for defining environment variables and matching them to actual configurations, e.g. for a configuration aaa.bbb.ccc you may need to set an environment variable as AAA_BBB_CCC. Read ch. 5.3.1 in the specs, and experiment a little.
You can always extend the configuration sources with your own custom ones (to read configuration from JNDI, DB, Zookeeper, whatever).

Disable spring-context-indexer by profile

I want to enable Spring Context Indexer on a project but I am having issues with Swagger3 (check here and here).
I understand the limitations and would like to enable it, at least, at the DEV profile where we do not need Swagger running.
My goal is to disable indexing on PROD environment. From docs:
you can fallback to a regular classpath arrangement (as though no index was present at all) by setting spring.index.ignore to true, either as a system property or in a spring.properties file at the root of the classpath.
My first approach (without success) was setting an env var (Windows 10) with the following:
SPRING_APPLICATION_JSON={"spring":{"index":{"ignore":true}}}
If I create a spring.properties file and set the value accordingly it works. But I can't figure how to use different properties for each profile, I imagined it was something like the application.properties file but I was wrong.
How can I achieve that?
EDIT:
Just to be clear, this config (spring.index.ignore) will just work if inside a spring.properties file, not an application.properties one. (Just double-checked before this edit)
Actually I have one application-prod.properties and one application-dev.properties.
I don't know the difference between spring.properties and application.properties but the first one doesn't seem to work with multiple profiles as the later.
Edit 2:
Just went through org.springframework.context.index.CandidateComponentsIndexLoader and it uses SpringProperties.getFlag(IGNORE_INDEX) to read the value.
SpringProperties class is clear about the file it uses:
Reads a spring.properties file from the root of the Spring library classpath, and also allows for programmatically setting properties through setProperty. When checking a property, local entries are being checked first, then falling back to JVM-level system properties through a System.getProperty check.
I think I will need to pass a property to Java runner during initialization. Will research a little bit more about it.
you can use different application.properties file as follow:
add the following files to the resource folder:
application.properties
spring.profiles.active=dev #place profile name you want to use
application-dev.properties
#dev properties
...
You can create many application-env.properties you may wish
application-env.properties
#env properties
...
Spring Boot supports profile-specific properties files. You have to name these files with the following format: application-{profile}.properties. You can activate a profile via JVM system parameter: -Dspring.profiles.active=dev. You can read more about this subject here: https://www.baeldung.com/spring-profiles

SpringBoot library project does not see main app properties

I have a setup like this:
Main SpringBoot project with application-default.properties which on our deployment server are partially overwritten by a deployment specific properties.
Shared SpringBoot library project which has its own properties.
And when I run my main project with the library project attached (via gradle sourceControl gitRepository) I can see that the properties in the library project are empty.
How can I make the library project use the properties passed down from the main application ?
If you want to merge properties, please consider this official page.
Option 1 - default properties in library
As I found previously (probably, it is fixed), if you have jar1 and jar2 (sorted alphabetically) and both of them have application.properties file, only first will be used. They aren't merged. So please be carefully there.
However you can use #PropertySource in your library, e.g. put default properties there into the custom file name (for example - defaults-for-jar2.properties or something like this, to avoid automatic loading by Spring).
In this case:
Property load logic outside of your library will be the same with current.
Your library will load file from #PropertySource and next they will be overridden (if you have this) by your application.
Option 2 - configuration properties
If you use Kotlin and Spring, you can use ConfigurationProperties. And you can define the default values there. Moreover, IntelliJ Idea will highlight the default and possible values (according to the type, because you can use not only String, but any custom enum class, Duration class, etc.).
Just from that link:
#ConstructorBinding
#ConfigurationProperties("blog")
data class BlogProperties(var title: String, val banner: Banner) {
data class Banner(val title: String? = null, val content: String)
}
#SpringBootApplication
#EnableConfigurationProperties(BlogProperties::class)
class BlogApplication {
// ...
}
Please note:
You should mention your settings data class in the library configuration.
You should configure kapt properly to have Intelli Sence in IDEs.

A Dependent Spring boot project application.properties not injecting default values

I have two spring boot projects, Project A and Project B, each with its own application.properties.
When the project is run individually the values from application.properties are injected properly. But when I am using one of the Project B as a dependency in Project A, the default values defined in application.properties of B are not being injected and I have to define the same properties again in the .properties file of A which is kind of redundant.
How do I avoid this? I want the default values in the properties file of B to be injected and I would only want to define the properties for B when I want to override the default values. Sorry for my english
AFAIK, there is no out-of-box solution for this. I would recommend two solutions and you can go with one more feasible for you:
Take out all properties common for all projects and put them in a seperate properties file, use them with #PropertySource.
Use spring cloud config to store common(or all) properties. You can also have some custom logic there to pick the correct property among multiple property files.
It's hard to say without your code provided. I guess you can try to use multiple .properties files for Project A application like following:
#PropertySources({
#PropertySource(name = "propsA", value = "classpath:propsA.properties"),
#PropertySource(name = "propsB", value = "classpath:propsB.properties")
})
public class ApplicationA {

Categories