How to use Spring Java properties default value in XML - java

I am looking how to use the Java default properties value in XML without specifying in application YML or what ever.
This is my java configuration and default I want to use this URL value until providing it from YML file.
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "test.sample")
public #Data class SampleProperties {
private String serverurl ="test.example.com";
}
When I try to use in XML
<property name="serverURL" value="${test.sample.serverurl}" />
Throwing
IllegalArgumentException : Could not resolve placeholder 'test.sample.serverurl' in value "${test.sample.serverurl}"

Your use of the placeholder in XML does not include a default value to use when it is missing
Default values can be provided with a :default-value suffix on the placeholder
<property name="serverURL" value="${test.sample.serverurl:http://localhost}" />
The example is complicated by the : in the default value, simpler ones might be
value="example:default"
value="test.sample.port:8080"
There is a probable duplicate Is there a way to specify a default property value in Spring XML?. Here is a decent tutorial on properties in Spring.

Related

What is the Best way to get the values from the Properties File in Spring?

I have used the following ways to get the values from the properties. But I would like to know which one of these is the best to use to follow the coding standard? Also, are there any other ways that we can get the values from the properties file in Spring?
PropertySourcesPlaceholderConfigurer
getEnvironment() from the Spring's Application Context
Spring EL #Value
Along with the other configuration classes (ApplicationConfiguration etc.) I create a class with the annotation #Service and here I have the following fields to access the properties in my file:
#Service
public class Properties (){
#Value("${com.something.user.property}")
private String property;
public String getProperty (){ return this.property; }
}
Then I can autowire the class and get the properties from my properties file
The answer is,
it depends.
If the properties are configuration values,
then configure a propertyConfigurer
(below is an example for a Spring xml configuration file).
<bean id="propertyConfigurer"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:configuration.properties</value>
<value>classpath:configuration.overrides.properties</value>
</list>
</property>
</bean>
When configured this way,
the properties from the last file found override those found earler
(in the locations list).
This allows you to ship the standard configuration.properties file bundled in the war file and store a configuration.overrides.properties at each installation location to account for installation system differences.
Once you have a propertyConfigurer,
annotate your classes using the #Value annotation.
Here is an example:
#Value("${some.configuration.value}")
private String someConfigurationValue;
It is not required to cluster the configuration values into one class,
but doing so makes it easier to find where the values are used.
#Value will be the simple and easy way to use, as it will inject value from property file to your field.
Both the older PropertyPlaceholderConfigurer and the new PropertySourcesPlaceholderConfigurer added in Spring 3.1 resolve ${…} placeholders within bean definition property values and #Value annotations.
unlike getEnvironment
using property-placeholder will not expose the properties to the
Spring Environment – this means that retrieving the value like this
will not work – it will return null
when you are using <context:property-placeholder location="classpath:foo.properties" /> and you use env.getProperty(key); it will always return null.
see this post for the problem using getEnvironment : Expose <property-placeholder> properties to the Spring Environment
Moreover, in Spring Boot you can use #ConfigurationProperties to define your own properties with hierarchical and type-safe in application.properties. and you don't need to put #Value for every field.
#ConfigurationProperties(prefix = "database")
public class Database {
String url;
String username;
String password;
// standard getters and setters
}
in application.properties:
database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
Quote from : properties with spring

Spring Property Placeholders with String Concatenation

My problem looks simple but I'm not able to resolve it. I have a properties file which contains configuration details of all environments (dev, qa, prod).
Example config.properties:
dev.maxLength=2000
qa.maxLength=4000
We have a parent Properties file which holds the host name, environment mappings.
Example hosts.properties:
host1=dev
host2=qa
The property name host1 is stored in a bean hostname.
<bean id="hostname"
factory-bean="localhostInetAddress"
factory-method="getHostName"/>
To resolve the config properties name I have to join the strings as follows,
${${**hostname**}.maxLength} which should be resolved as ${dev.maxLength}
I tried using SpEL with no success. I am getting Could not resolve placeholder Exception. How can I concatenate a bean value in property place holder? How are dynamic property names constructed?
Spring version 3.2
To concatenate the values parsed from Spring property placeholders, you need to escape their values using single quoutes ('') and wrap the placeholder expressions by a SpEL expression using #{}.
<bean id="myService" class=""com.services.MyService">
...
<property name="endpointAddress" value="#{'${server}' + ':' + '${port}' + '${endpoint}'}" />
</bean>
where:
server = http://domain.host.com
port = 7777
endpoint = /services/myservice
The result would be:
http://domain.host.com:7777/services/myservice
I solved the issue by changing PropertyPlaceholderConfigurer beans to Properties.
<util:properties/> are accessible in SpEL.
Example:
"#{prop[host+'.'+'maxLength']}"
where host is a string bean.
It would be better to have environment specific properties in a file of its own and use Spring Profiles.
For example, I have four xml files just for db configuration, local.db.xml, dev.db.xml, qa.db.xml and prod.db.xml.
Inside each db.xml, I set the profile to the appropriate value.
My local.db.xml has
<beans profile="db.local" .. >
For starting Tomcat, I specify the VM options as follows
-Dspring.profiles.active=db.local

Property expansion with PropertiesFactoryBean

I wish to expose a Properties Spring bean whose values have been expanded via the typical property expansion mechanism. I'm using Spring 3.1. Let me digress.
Given the following properties file:
server.host=myhost.com
service.url=http://${server.host}/some/endpoint
And this portion of Spring XML config file:
<bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:default.properties</value>
</list>
</property>
</bean>
<context:property-placeholder properties-ref="appProperties" />
I can write the following working code:
#Component
public class MyComponent {
#Autowired
#Qualifier("appProperties")
private Properties appProperties;
#Value("${service.url}")
private String serviceUrl;
// remainder omitted
}
The only problem is that if I obtain the service.url value from appProperties I get http://${server.host}/some/endpoint - ie the value is unexpanded. However, if I get the value of service.url from serviceUrl, the value has been expanded: http://myhost.com/some/endpoint.
Does anyone know of a good way to expose a Properties instance as a Spring bean whose values have been expanded?
Alternatively, if anyone can point me to a Spring bean (must be Spring 3.1) that will do the expansion for me, I'll accept this too! (Interestingly, if you manually pull the property values from the Environment or PropertySource you'll find that these too are unexpanded.)
Thanks,
Muel.
I'm pretty late to this, but it's been viewed enough times that i figured it warranted a quick response. What you're seeing is an artifact of how Spring handles property expansion. When the need for property expansion is found, only previously loaded sources are checked, not the currently loading property source. When the file loads, there are no previous sources, so ${server.host} does not expand. When you later reference ${server.url} via the #Value annotation, the property file source is loaded and can be searched as you expected. This is why the #Value annotation gets full expansion but the result queried from the property file does not.

Automatically Trim Trailing White Space for properties in Props file loaded into Spring

I'm using PropertiesFactoryBean to load properties from a typical Properties file. Is there anyway to get Spring to automatically trim trailing white space from the prop value?
As this can often be a source of confusion when using Spring Boot, I want to add that you do not need XML configuration to provide your own PropertyPlaceholderConfigurer.
Simply put this in your main class:
#Bean
public static PropertySourcesPlaceholderConfigurer createPropertyConfigurer()
{
PropertySourcesPlaceholderConfigurer propertyConfigurer = new PropertySourcesPlaceholderConfigurer();
propertyConfigurer.setTrimValues(true);
return propertyConfigurer;
}
This is sufficient for trimming the values from application.properties.
You can customize the Properties loading functionality by passing in a custom PropertiesPersister into your PropertiesFactoryBean configuration. The PropertiesPersister instance is used by the PropertiesFactoryBean to parse the Properties file data. The default implementation follows the native parsing of java.util.Properties. You can customize the parsing logic by providing your own implementation of the PropertiesPersister interface.
As Chad said, Spring solved this problem with version 4.3RC1. But you need to manually set on trim function with parameter "trimValues" like so (default if "false"):
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="trimValues" value="true"/>
<property name="locations">
<list>
...
</list>
</property>
I do not found any documentation about this but I deduce it from Spring API.
With latest Spring version(4.3+), you can simply call setTrimValues() with true when you create PropertySourcesPlaceholderConfigurer bean in your configuration. That will remove any extra leading or trailing spaces from the value you got from the properties file.
You can define your own property configurer:
package your.company.package;
public class TrimPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
#Override
protected String resolvePlaceholder( String placeholder, Properties props ) {
String value = super.resolvePlaceholder( placeholder, props );
return (value != null ? value.trim() : null );
}
}
Then you must define it in your bean_config.xml
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:main.properties" />
</bean>
<bean id="trimPropertyPlaceholderConfigurer" class="your.company.package.TrimPropertyPlaceholderConfigurer">
<property name="properties" ref="applicationProperties" />
</bean>
Another way if you're using #Value annotations to set the properties into the fields:
#Value( value = "#{applicationProperties['my.app.property'].trim()}" )
NullPointerException is thrown if the property doesn't exists in the file
One easy way to do it would be to "hack" the spEl Expression to force the use of the String.trim() function.
Let's say you have a property test.myvalue equal to azerty (with trailing spaces) in the application.properties file, then you could inject this property in your class like this :
#Value("#{'${test.myvalue}'.trim()}")
String myvalue;
The resulting myvalue will be equal to azerty (no trailing spaces) once injected in your class.
Obviously this trimming won't be set globally to all injected values in your app, and you'll have to do it to all injected value, but I think this approach gives more flexibility.

In Spring can you alter property placeholder values using a BeanDefinitionDecorator?

I have a BeanDefinitionDecorator that makes modifications to properties that a user would set on a bean. It works fine; except if the bean is using placeholders. I am trying to find a strategy to modify those values while still have access to the original value at runtime. An example of what this would look like in XML:
<bean id="bean">
<property name="jdbcUrl" value="${jdbc.url}" />
<d:spyDecorator />
</bean>
I know that user would be writing the jdbcUrl property as "jdbc:myDatabase". What I want to do is change their property to "jdbc:spy:myDatabase". This is easy if they are just using string literals for the property value, but if they are using property placeholders I am not sure how to change the value -- because I need the original value in order to supply the new value. They key is to keep the property rewriting transparent to the user.
Are there any possible solutions for this?
I think your namespace handler can register a BeanFactoryPostProcessor (implementing Orderer with order = Integer.MAX_VALUE to be the last post processor applied). Then your BeanDefinitionDecorator will register the beans being decorated for processing with that post processor (implement it in the post processor somehow), and post processor will apply the actual property modification to that beans.
You can use PropertyPlaceholderConfigurer to substitute property values for placeholders in bean properties, aliases, and other places. Note that the replacements happen AFTER the bean definitions have been loaded, so this mechanism does not apply to <import> elements
For example:
...
<bean id="ppc"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:build.properties</value>
<value>classpath:default-emmet-substitution.properties</value>
<value>classpath:default-danno-substitution.properties</value>
<value>classpath:default-dannotate-substitution.properties</value>
<value>classpath:substitution.properties</value>
</list>
</property>
</bean>
...
For more information refer to this section of the Spring Framework docs.
EDIT - I guess from your comment you are already familiar with how placeholder replacement works, and are using PropertyPlaceholderConfigurer to do the replacements. So now you need to choose between these strategies, or some combination:
Do the placeholder replacements yourself in your custom BeanDefinitionDecorator. That would work, though you'd be duplicating a lot of code.
Have the custom BeanDefinitionDecorator modify the placeholder names to different ones that will pull in different values; e.g. "${jdbc.url}" becomes "${spy.jdbc.url}".
Extend the PropertyPlaceholderConfigurer class to modify the substituted property values; i.e. override convertProperty or convertProperties. That has the potential problem that all placeholders will get the modified values ... not just the ones in beans that you have decorated.
Create a new PropertyResourceConfigurer class to substitute different property values depending on the context. Essentially, the processProperties needs to work like the method does in a PropertyPlaceholderConfigurer, but do something different if it sees bean properties or whatever that tell it to do the "spy" substitution.
A combination of 2) and 3) looks the most promising.

Categories