Filter #ConfigurationProperties in #Value - spring

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.

Related

How to optionally apply environment configuration?

I want to optionally apply a VPC configuration based on whether an environment variable is set.
Something like this:
custom:
vpc:
securityGroupIds:
- ...
subnetIds:
- ...
functions:
main:
...
vpc: !If
- ${env:USE_VPC}
- ${self:custom.vpc}
- ~
I'd also like to do similar for alerts (optionally add emails to receive alerts) and other fields too.
How can this be done?
I've tried the above configuration and a variety of others but just receive various different errors
For example:
Configuration error:
at 'functions.main.vpc': must have required property 'securityGroupIds'
at 'functions.main.vpc': must have required property 'subnetIds'
at 'functions.main.vpc': unrecognized property 'Fn::If'
Currently, the best way to achieve such behavior is to use JS/TS-based configuration instead of YAML. With TS/JS, you get full power of a programming language to shape your configuration however you want, including use of such conditional checks to exclude certain parts of the configuration. It's not documented too well, but you can use this as a starting point: https://github.com/serverless/examples/tree/v3/legacy/aws-nodejs-typescript
In general, you can do whatever you want, as long as you export a valid object (or a promise that resolves to a valid object) with serverless configuration.

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

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.

Is there a way to create an object of a specific type, based on a value of a string variable (not the string type)?

I'm trying to instance multiple objects of diverse types based on what you set on the config file.
Also, I'm trying to avoid to use the 'switch' statement with every Type of object that you can instance.
My original idea was use sort type of reflection, to create a object with a Type obtained from a config value.
For example:
These is a YAML Config example
workers:
- type: "Type1"
parameters:
param_0: "test"
param_1: 1000
- type: "Type2"
parameters:
param_0: "test"
param_1: 1000
When these settings are analyzed; at run-time, the program must instance a "Type1" object with the "Parameters"; and then another instance of a "Type2" object with its "Parameters".
Please let me know if you need more information about it.
PD: Sorry for my bad English.

SpelParseException: After parsing a valid expression, there is still more data in the expression: 'lcurly({)'

I am trying to condtionally create a component using #ConditionalOnExpression("not ${service.synchronous} && not ${service.disabled}").
I based this on Spring Boot SpEL ConditionalOnExpression check multiple properties, which provides a multi-property conditional as follows: #ConditionalOnExpression("${properties.first.property.enable:true} && ${properties.second.property.startServer:false}")
However, I keep getting:
Caused by: org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'lcurly({)'
Those properties are always set in my .properties file so I did not provide a default value with the colon notation. What am I doing wrong?
You will need to provide the default values for your properties like in the example you followed, so update the expression to be:
#ConditionalOnExpression("not ${service.synchronous:false} && not ${service.disabled:true}")
In most such cases the properties your app is reading are not what you expect them to be.
Set a breakpoint on all constructors of SpelParseException. In the debugger you will see the expression that is parsed, that will give show you exactly which properties you are really using.
Maybe you have to go search a little in the stack until you find the right location where you can see the expression.
My mistake was that I had not imported the test properties file in a Spring test.
After I added #TestPropertySource("classpath:/application.properties") to the test class, the properties from the properties file were used.

How do I use the appProperties with the ruby api-client

I can't determine how to add custom properties or search for them.
Everything I have tried is giving me a Error - #<Google::Apis::ClientError: invalid: Invalid query> when I attempt to search for them. I can successfully complete other queries but I don't know if the client is setup to work with appProperties (or even properties at all).
Basically I just need the correct syntax for searching and adding since it doesn't appear to be in the documentation.
Assuming you already have a reference to an authorized DriveService, you can search based on appProperties using a q-parameter (documented here), like this:
file_list = drive.list_files(
q: "appProperties has { key='my_app_key' and value='my_val' }",
fields: 'files(id, name, appProperties)',
spaces: 'drive')
If you omit the fields parameter then the search will still work but the properties themselves won't be returned.
Updating appProperties is definitely arcane and the documentation is opaque. What you need is the ID of the file, and a File value object as a container for the attributes to update. Something like this:
new_app_properties = { 'my_app_key' => 'my_val' }
update_f = Google::Apis::DriveV3::File.new(app_properties: new_app_properties)
drive.update_file(file_id, update_f)

Resources