Overriding dependencies property value in Spring - java

In my Spring project I am using a dependency project developed in Spring. This dependency has its own properties file and have defined a property which points to localhost. Now in my setup, I want this property to be pointing to another URL but not localhost. I am trying to override this in my properties file using addFirst method of property sources, but the dependency still loads the original property value.
ConfigurableEnvironment environment = applicationContext.getEnvironment();
//here i overload the props
environment.getPropertySources().addFirst(
new ResourcePropertySource("classpath:conf/app.properties"));
LOG.debug("dependency property: " + applicationContext.getEnvironment().
getProperty("server.hostname")); // here it prints the overloaded value in app.properties
When I print the overloaded property I get the overloaded property value, but when the program gets executed it points to localhost. Is this the way to override dependent properties ? Spring version is 3.2

The point is, that in the ProperySources the last one wins.
(Its like in a Database, the last one that writes wins).
Try to use simply add.

Related

Can you override a library's Spring property placeholders?

We are working on moving our application to use only Spring-Boot application.properties files. The old way we were doing was that each library/dependency would have their properties stored in a dedicated properties file like res/environment/some-library-override.properties. The values would then be retrieved in the library using #Value("$some-library-{PROPERTY_NAME}").
However, since moving all of these override properties to dedicated application.properties files, it is no longer resolving the properties and we get errors like java.lang.NumberFormatException: For input string: "$some-library-{PROPERTY_NAME}".
I assume this is because it is still expecting the property to be in that dedicated properties file.
Is there a solution to this that doesn't involve modifying the library/dependency? Is it possible to have it ignore the prefix and only look for the PROPERTY_NAME in the application.properties files?
if you have declared propertie var likeproperty.name=XXXX or added environment var like PROPERTY_NAME=XXXX.
you need to use this way
#Value("some-library-${property.name}")
// will inject value "some-library" + "XXXX"

Implement property source precedence in Spring Cloud Config Server client

I need to implement client code in java for using spring cloud config server. The client side is not a spring app nor a web service.
We will have an application.properties file. We will have an app-specific file. And we will have environment-specific files for both of them. My understanding of spring config precedence rules is that the precedence, from lowest to highest should be:
application.properties (lowest)
specificApp.properties
application-dev.properties
specificApp-dev.properties (highest)
However, when I call the service with http://localhost:8888/specifcApp/dev, the property sources are returned in the opposite order from the above:
0: specificApp-dev.properties
1: application-dev.properties
2: specificApp.properties
3: application.properties
I am not certain, but I believe that the intention is that the order returned indicates the precedence from lowest to highest (the last one wins). If that is true, then this is indicating that application.properties has precedence over the others. That is the opposite of what I would expect.
I have yet to find spring documentation that covers this completely all in one location. There is confusing information scattered around. But in this document, it says, "...profile-specific files always [override] the non-specific ones, whether or not the profile-specific files are inside or outside your packaged jar.
What are the actual precedence rules, and what does the order of the property sources in the response indicate?
The second part of the question is, how can I iterate over the configService property sources in ANY order?
I found the sample code below. However, the problem is that CompositePropertySource.getPropertySources() returns a Collection. In other words, there is no way to get an ordered list from CompositePropertySource. (The sources are stored internally in CompositePropertySource in a Set.)
final CompositePropertySource compositePropertySource
= (CompositePropertySource)environment.getPropertySources().get("configService");
if (compositePropertySource != null && compositePropertySource.getPropertySources() != null) {
// compositePropertySource.getPropertySources() is not ordered!
for (final Object mapPropertySourceObject : compositePropertySource.getPropertySources()) {
final MapPropertySource propertySource = (MapPropertySource)mapPropertySourceObject;
if (propertySource != null) {
p.putAll(propertySource.getSource());
LOG.info("fetched remote properties");
}
}
}
To summarize:
What is the precedence rule supposed to be?
What does the order of property sources indicate in the Json raw server response?
How can I access the actual order of the property sources that make up the configService composite property source?
I am using Spring Boot 1.5.14.RELEASE and Spring Cloud Edgware.SR4.
Edit: I see now that the CompositePropertySource propertySources set is of type
LinkedHashSet, so it does have an order. And CompositePropertySource.getPropertyNames(), it's clear that properties from property sources later in the list will override those earlier in the list. If that's true, then application.properties takes precedence over the app- or profile-specific configurations. I don't see how that can be the expected behavior. It means that no property can be overridden, in effect.
Edit #2: I am testing this using a Git repo. All four of the files are in the same folder within the repo.
Edit #3: I realized some properties influence this. When I submitted this, I should have stated that I was launching the client with JVM options: -Dspring.profiles.active=dev -Dspring.profiles.default=dev and -Dspring.cloud.config.profile=dev. I also tried it with just -Dspring.cloud.config.profile=dev.
Update: I am closer to a solution.
I tried the following:
Rename application.properties to application-default.properties.
Rename specificApp.properties to specificApp-default.properties.
Then I ran with -Dspring.profiles.active=dev,default. I had no -Dspring.profiles.default property and no -Dspring.cloud.config.profile property.
In this case, they were returned in this order:
specificApp-default.properties
application-default.properties
specificApp-dev.properties
application-dev.properties
This is still not what I would expect. It means that the shared application properties will override (i.e. take precedence over) the appSpecific properties. I would expect the following order, but am getting closer to a solution, I think:
application-default.properties
specificApp-default.properties
application-dev.properties
specificApp-dev.properties
or even this order:
application-default.properties
application-dev.properties
specificApp-default.properties
specificApp-dev.properties

Spring Boot external properties not loaded

I'm starting with Spring Boot, so am first going through the Spring Boot reference Guide
I'm currently having a look at the Externalized Configuration
My goal is to have a simple Component to read the value out of application.properties, which, if I'm not mistaken, should be loaded automatically, without any further configuration.
The example in the reference is as follows:
import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*
#Component
public class MyBean {
#Value("${name}")
private String name;
// ...
}
with the following explanation:
On your application classpath (e.g. inside your jar) you can have an
application.properties that provides a sensible default property value
for name. When running in a new environment, an application.properties
can be provided outside of your jar that overrides the name; and for
one-off testing, you can launch with a specific command line switch
(e.g. java -jar app.jar --name="Spring").
Seems simple enough. So, I have created following Component:
#Component
public class Admin {
#Value("${name}")
private String name;
public String getName(){
return "ReadName_" + name;
}
}
And, in my recources folder, the following application.properties file (which, I verified, is copied into my .jar)
name=myName
So, if I follow the logic in the reference (which is also mentioned in this post: Read application.properties, and run my application.
The code compiles and runs without error, but each time I print the value of getName() from an instance of Admin on my screen, it just gives a "ReadName_null" instead of "ReadName_myName", the value in the properties file.
As the reference states, in 24.2:
By default SpringApplication will convert any command line option
arguments (starting with ‘--’, e.g. --server.port=9000) to a property
and add it to the Spring Environment. As mentioned above, command line
properties always take precedence over other property sources.
So, just to check, I run my .jar file with both the application.properties with the key present, and add --name=passedName as a command line argument.
Even though this value should be automatically added to the environment, and overrule anything (or in my case: nothing) that is currently there, and I expect the getName() to return "ReadName_passedName", it still returns "ReadName_null".
EDIT: I print the command line arguments I pass while booting, so I know that the argument is indeed read by the system as "--name=passedName"
Is there anything obvious I'm missing here?
If you do new Admin (), you are creating a new instance of Admin and not a spring bean. So you don't get any advantages which spring provides(for example Dependency Injection) And hence the value is null.
Instead you should Autowire it in your class. This way spring will inject the instance of Admin that it has created (with injected values)
#Autowired
Admin admin;
And before you ask, yes by default all beans are singleton(unless specified otherwise). So no matter whereever you Autowire Admin, you will get the same instance.
This is a broad topic, you should read about it.

Java bean gets property name instead of value

I have a .properties file with bunch of properties in it. Here's an example:
mes.mail.debug=true
cookie.sso.domain = .stuffStuff.com
blabla.endpoint = blabla.com
test.value.property = myValue
The problem is with the last one (Which I have just added to the project we're working on).
I read the properties using #Value("${PropertyName}") annotation and it was working perfectly until lately, when I use the same thing, the variable gets the propertyName instead of its value:
#Value("${test.value.property}")
private String mProperty;
so, mProperty gets "test.value.property" where what I'm looking for is for it to get "myValue".
What's happening exactly? Is there something wrong with my project? I have tested in my friend's computer and it works perfectly.
By the way, i'm using Spring Tool Suite.
EDIT: It turns out that it doesn't detect the changes I make in the properties file. So if I change an old property's value; it acts as if nothing happened.
Does anyone has any idea why it's doing like this?
When you declare a Property Placeholder Configurer to load the properties files, you can set it to ignore unresolvable placeholders.
This means that if the property you are injecting with #Value is not found, its name (or key) will be assigned to the variable.
In your case, this option is enabled and the file that has been loaded by the application is not the one you are editing.
To see from where the file is been loaded, check the placeholder configurer location property.

How to Change init-parameters at Runtime?

If I modify the XML to change the value of init parameter
I see the changes only when web-app is redeployed.
My question is cant I get around this by setting the values at run time.Is there any API that allow me to change the values dynamically.
It's called init-parameter for a reason. So, you can't.
But you can change values at runtime, that's no problem.
After reading the init parameters put them as attributes of the ServletContext (ctx.setAttribute("name", value))
Create a small (password-protected) page that lists all attributes of the ServletContext and gives the ability to change them.
Maybe you could use apache commons configuration, specifically have a look at Automatic Reloading...
Make use of properties files instead and write code so that it 1) reads the value from it everytime, or 2) can reload the value on command, or 3) reloads the file automatically at certain intervals.
If you put the properties file somewhere in the webapp's runtime classpath or add its path to the webapp's runtime classpath, then you can easily access/load it as follows:
Properties properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
String value = properties.get("key");

Categories