spring - why define variable values of properties in application.properties - spring

I am trying to understand something about the following application.properties syntax in spring
some-api:
url: ${variable.url:http://localhost:8080}
I know that to get the value of the above we use (for example)
#Value("${some-api.url}")
private String url;
what's the point of declaring ${variable.url:VALUE} when I reference it with some-api.url ? where do you use this ?
also can you call this value in pom.xml ?

In your example properties file you are referring another property, like this is how your application.yml must be looking
variable:
url: http://host
some-api:
url: ${variable.url:http://localhost:8080}
and vaue after : is the default value when variable.url is not defined.
also can you call this value in pom.xml ?
No, you need some maven plugin which can read your properties file in order to do that.

Related

Set description from property file for swagger #schema in spring boot

I'm working on spring boot(v2.5.6) with dependency openapi-ui(v1.5.2) for swagger UI. I want to set description and other attribute such as required in #schema. The problem is I need to read this value from a property(resource-bundle). Also I want to read other attribute such as min/max/.. from some properties.
I'v tried below code but not worked:
#Schema( description ="{postalCode.description}" ,required ="{postalCode.required}")
String postalCode;
whereas postalCode.description is a property key in a resource bundle.
Is There any way to use some dictionary like properties for swagger?
You can add file with swagger properties and then add configuration for it in Application.java:
#PropertySource(value = "classpath:swagger-messages.properties", encoding = "UTF-8").
Then you have to use description ="${postalCode.description}" (add $)
and set springdoc.api-docs.resolve-schema-properties to true.
source: https://springdoc.org/faq.html

Filter #ConfigurationProperties in #Value

I have my property file like this:
integrations:
- operationCode: CD001
connectionFactoryName: cf1
senderName: sn1
host: 192.168.1.1
port: 1416
queueManager: QM_TSTIN
channel: JAVA.CHANNEL
username: user
password: pass
receiveTimeout: 10000
sendQueue: SEND
receiveQueue: RECEIVE
How can i get my integration entity by operationCode? This is how i try to do this. But it does not work.
#Value("\${integrations.?[operationCode == 'CD001'].receiveQueue}")
var receiveQueue: String? = null
This is not possible using the property placeholder syntax ${} and also not possible by the SPEL syntax #{} as far as I know.
The property placeholder is a very simple solution it provides direct access ${a.b.c} with the option of default value ${a.b.c:default_value}. In terms of syntax that's it (javadoc).
The Spring Expression Language is very powerful comparing to the property placeholder but can not access properties directly. You can access a property by #{'${a.b.c}'} but the a.b.c must be a leaf in the yaml it can not access internal nodes. So you can not use the #{'${a.b}'.c} as the a.b is an internal node. So even you could use the #{bean.collection.?[attribute1 > 5].attribute2} in SPEL you can not use that for properties.
I suggest the standard yml attributes instead of the collection:
integrations:
CD001:
operationCode: CD001
receiveQueue: RECEIVER_2
CD002:
operationCode: CD002
receiveQueue: RECEIVER_2
and then use the #Value("${integrations.CD002.receiveQueue}") to get the value.
Unfortunately as far as I know there is no expression to solve your problem if you can not change the yaml's format.

Is it possible to use variable in Spring property files?

I have some properties in my config.properties file in spring like:
adminip=182.178.22.21
websiteurl=//182.178.22.21:4056/test
I want to use adminip in other properties in the same file (config.properties) as variable; some thing like this:
adminip=182.178.22.21
websiteurl=//${adminip}:4056/test
is it possible?
actually adminip is redundant in other properties.
In spring-boot you can use placeholders like here https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-placeholders-in-properties
So your porperty will be
adminip=182.178.22.21
websiteurl=${adminip}:4056/test
this is not possible to do in *.properties file, but you could do adjustment to code and do smth like:
String adminip = ...;
String websiteurl = String.format("//%s:4056/test", adminip);

Spring matrix parameters

I have upgraded my spring version to 4.1.4 and now want to use Matrix parameters.
I have added below to enable support for matrix parameters in configuration file:
<mvc:annotation-driven conversion-service="applicationConversionService" enable-matrix-variables="true"/>
and in code I am accessing it as below in my method:
public ResponseEntity<String> transactions(#PathVariable("accountNumber") String accountNumber,
#MatrixVariable(required = true,value="sinceDate") String sinceDate){....}
and my url is : http://localhost:8080/spring_test/accounts/8293/transactions;sinceDate=2014-01-20;untilDate=2014-01-01;
But I am getting sinceDate value as null, which is declared with #MatrixVariable.
Please suggest if I am missing any steps?
Thanks,
Manasi
If you have your own AbstractHandlerMapping definition you should specify its <beans:property name="removeSemicolonContent" value="false"/>.
Otherwise I suggest you to debug the Spring code and figure out why removeSemicolonContent isn't reseted for the default RequestMappingHandlerMapping.
The break point should be in the UrlPathHelper#removeSemicolonContent
To make this worked you should place matrix variables in the URL just after the approriate pathVariable:
http://localhost:8080/spring_test/accounts/8293;sinceDate=2014-01-20;untilDate=‌​2014-01-01;/transactions

Spring, property file, empty values

I have configured spring security with a ldap server (but continue reading, it's not a problem if you have no knowledge about it, this is really a spring problem). All runs like a charm. Here is the line I use for that:
<ldap-server ldif="" root="" manager-dn="" manager-password="" url="" id="ldapServer" />
If I fill ldif and root attributes, it will run an embeded server:
<ldap-server ldif="classpath://ldap.ldif" root="dc=springframework,dc=org" manager-dn="" manager-password="" url="" id="ldapServer" />
If I fill other fields, it will run a distant server:
<ldap-server ldif="" root="" manager-dn="dc=admin,dc=springframeworg,dc=org" manager-password="password" url="ldap://myldapserver.com/dc=springframeworg,dc=org" id="ldapServer" />
All this stuff run correctly. Now I want to use Spring mechanism to load such parameters from a property file:
So I replace attribute values like this:
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="${ldap.server.url}" id="ldapServer" />
and create a property file with:
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=
ldap.ldif.path=
ldap.ldif.root=
Now, the funny part of the problem. If I fill the following properties in the file:
ldap.server.url=ldap://myldapserver.com/dc=springframeworg,dc=org
ldap.server.manager.dn=dc=admin,dc=springframeworg,dc=org
ldap.server.manager.password=password
ldap.ldif.path=
ldap.ldif.root=
It runs a distant server as expected.
If I fill the property file like this:
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=
ldap.ldif.path= classpath:ldap.ldif
ldap.ldif.root= dc=springframeworg,dc=org
It does not run, complaining that the ldap url is missing. But the problem is that if I change the spring configuration from:
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="${ldap.server.url}" id="ldapServer" />
to (by just removing the reference to the variable ${ldap.server.url})
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="" id="ldapServer" />
It runs !
My thoughs are that spring does not replace the attribute value with the property config one if this one is empty. But I find it strange.
Can you give me some clue to understand that ? And what's the best to do to configure my ldap server via a property file ?
EDIT: this is due to a poor design choice (look at accepted answer), an issue has been opened on jira :
https://jira.springsource.org/browse/SEC-1966
Ok, I think this is a spring security bug.
If I debug and look at the class LdapServerBeanDefinition, there is a method called "parse". Here is an extract:
public BeanDefinition parse(Element elt, ParserContext parserContext) {
String url = elt.getAttribute(ATT_URL);
RootBeanDefinition contextSource;
if (!StringUtils.hasText(url)) {
contextSource = createEmbeddedServer(elt, parserContext);
} else {
contextSource = new RootBeanDefinition();
contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
}
contextSource.setSource(parserContext.extractSource(elt));
String managerDn = elt.getAttribute(ATT_PRINCIPAL);
String managerPassword = elt.getAttribute(ATT_PASSWORD);
if (StringUtils.hasText(managerDn)) {
if(!StringUtils.hasText(managerPassword)) {
parserContext.getReaderContext().error("You must specify the " + ATT_PASSWORD +
" if you supply a " + managerDn, elt);
}
contextSource.getPropertyValues().addPropertyValue("userDn", managerDn);
contextSource.getPropertyValues().addPropertyValue("password", managerPassword);
}
...
}
If I debug here, all variables (url, managerDn, managerPassword...) are not replaced by the value specified in the property file. And so, url has the value ${ldap.server.url}, managerDn has the value ${ldap.server.manager.dn} and so on.
The method parse creates a bean, a context source that will be used further. And when this bean will be used, place holders will be replaced.
Here, we got the bug. The parse method check if url is empty or not. The problem is that url is not empty here because it has the value ${ldap.server.url}. So, the parse method creates a context source as a distant server.
When the created source will be used, it will replace the ${ldap.server.url} by empty value (like specified in the property file). And....... Bug !
I don't know really how to solve this for the moment, but I now understand why it bugs ;)
I cannot explain it, but I think you can fix your problem using defaulting syntax, available since Spring 3.0.0.RC1 (see).
In the chageg log you can read: PropertyPlaceholderConfigurer supports "${myKey:myDefaultValue}" defaulting syntax
Anyway, I think that the problem is because "" is valid value, but no value in the property file don't.
I think that url="" works because url attribute is of type xs:token in spring-security XSD and empty string is converted to null (xs:token is removing any leading or trailing spaces, so "" can be recognized as no value). Maybe the value of ${ldap.server.url} is resolved as empty string and that is why you've got an error.
You can try use Spring profiles to define different configurations of ldap server (see Spring Team Blog for details about profiles)
I believe there is an issue here while using place holders. The following will most probably solve the problem:
Create a class which extends PropertyPlaceHolderConfigurer and override its method convertPropertyValue()
in the method you can return the property as empty string if you find anything other than a string which is of type LDAP url i.e. ldap://myldapserver.com/dc=springframeworg,dc=org
Also you need to configure your new specialization of class PropertyPlaceHolderConfigurer in the context file.
Hope this helps.
You can define empty String in the application.properties file as following:
com.core.estimation.stopwords=\ \

Resources