I have a configuration property that needs to be sent to another system as part of a post body.
lets say for example if have an application.properties file with
my.property.raw=${parameter:some-identifier}
I also have a #ConfigurationProperties annotated class that might look like this
#ConfigurationProperties(prefix = "my.property")
public class Properties {
private String raw;
// getters and such
}
The problem i have is that Spring will see ${parameter:some-identifier} and immediately assumes i want it to be injected with a property names "parameter" and if its not there, put "some-identifier". i have tried to set the property to ${parameter:${parameter:some-identifier}} but Spring seems to have accounted for recursive property injection and it still comes out as "some-identifier".
I know i can write some code around that and replace the ":" with something else and change it back after the fact but i'm trying to make this work without any code change.
So in summation, Spring boot sees this as a configuration property ${parameter:some-identifier} upon injection into the ConfigurationProperties annotated class, the value ends up being some-identifier. What i want to happen is the value in the Properties class after Spring does its variable replacement process is ${parameter:some-identifier} as this injectable format of a value is intended for a down stream system that is expecting that format. Preferably, without changing any code. Maybe there is some special formatting i can use to tell spring to ignore this specific property.
Thanks for your time! and yes i realize this is probably the opposite of what people normally want from Spring.
As stated by #Kayaman this is indeed a duplicate of
Escape property reference in Spring property file
The solution i pulled from there, with some modification, was this:
${dollar:$}{parameter:some-identifier}
https://stackoverflow.com/a/48897422/4621716
I did this because i also don't have control over the process that is generating that application.properties beyond changing existing values.
I hope this helps and i wish i could give #Kayaman credit for pointing me in the right direction but i guess i'll accept my own answer. Thanks.
Related
I have a java app that uses guice to do configuration.. I dont think this is what it is intended for but its what has been done and I only need to make a small change so I would prefer not to remove guice.
Basically, java properties are bound to variables, I want to bind some to an environmental variables or to a java property.
This is what I currently have
bindConstant().annotatedWith(Names.named("value")).to(properties.getProperty("java.property.value"));
this is what I would like to do
bindConstant().annotatedWith(Names.named("value")).to(System.getenv("JAVA_PROPERTY_VALUE"));
Is there a way to combine the two? I cannot do both. Or, is this just a default and I basically have what I need already? ie if I do bindConstant to System.getenv that value will be used unless its overwritten in the properties file (in my case the string constant is not the full property name so I am unsure how it works now).
I really do not know much about how guice works, I believe an injector is created where this code is and later used to do things like...
#Inject(optional = true)
#Named("value)
private String value;
I basically want that value to default to the one in the properties file, but be overridden by the env property value if its present.
I have tried simply using the env var value if it exists otherwise the property value, ie
bindConstant().annotatedWith(Names.named("value")).to(System.getenv(envVarName) != null && !System.getenv(envVarName).trim().isEmpty() ? System.getenv(envVarName) : properties.getProperty(propertyName));
Which works as expected when the environmental variable is defined and the property is not defined, but when both are defined the property is always used.
Which just leads me to the fact that I know very little about guice and how it works, I have in code a very explicit binding between the property name and this method, but, it just seems to be a default value, something after that is overwriting my value with the one from the property file.
This is super basic, but it's how we do things:
get Properties (sys.properties)
some.random.prop=localhost
iterate through System.getEnv() overriding all the Properties
// Convert SOME_RANDOM_PROP to some.random.prop
properties.put(parseKey(entry.getKey()), entry.getValue());
Now your properties should be defaulted to app.properties and overwritten with matching env.properties, then just bind all he properties.
Names.bindProperties(binder(), properties);
The caveat here is that now System.getEnv() pointless, but since you're using Guice for all your injections this shouldn't really be an issue.
I am wondering if there is a pattern that forces the user of my component to set a property after it is autowired. For example i have this:
#SpringComponent
#PrototypeScope
public class MyAutowiredClass {
private String myVariabeThatTheUserShouldSet;
public MyAutowiredClass(someOtherStuff ...(not my StringVariable)){
}
}
In this example how to i force myVariabeThatTheUserShouldSet to be set from the user of this component?
Well it's a bit complicated. If it wasn't in spring context you could just add that variable to the constructor and make it "required" like that. So to achieve that in a Spring context I would advise the following:
If possible pass that value as part of the dependency injection instead of trying to work around it. I understand it is something dynamic but still usually it would have business meaning and there is a way to do it. For example if you want the current user email you can add some Service that retrieves that value and pass that service to your component and extract that value from there. Or if you want some company configuration you can add a Service that gives you that value etc. It is the "Spring" way and I would lean towards that.
A simpler solution would be to add that required field to the methods signature of the methods that actually need it. It will overload the signatures by one field but it would force the users to pass a value. If you need that field for a couple of methods and not for the correct work of the component then it would be the easiest to implement/understand solution.
Add a setter for that value and throw exception if it is not set. That would be the worse though because will require try/catches if the exception is checked and if it is not people will forget to set the field so I would avoid that solution.
In spring, we can use #value annotation to refer a property value that is defined in the property file. In this approach, the way it would be something like
To have a separate property file and define the property name and value
To list this property class path in a spring config file
Finally referring the value in a class with #value annotations as
#value("{key_name}") String abc;
Other hand , we can try simply define that property value as a constant in the class something like the below and use it in the class.
public static final String key_name = "1q2w3e";
Since we have this simple approach, why we are using #value annotation approach as defined above.
Please help me to understand in detailed about it.
Using configuration values from external sources (e.g. property files) has many advantages. Some of them:
You can change the configuration without recompiling your code.
You can have multiple instances of the same binary-code running with different configuration values.
Configuration values can not only come from property-files that are bundled with your application, but from different sources like system-properties, environment-values, a database or any other custom source.
As a general rule only use constant values for things that will never change like the value of PI.
There's a big disadvantage in using the second method. Think of a scenario where you changed the language. If you were relying on the first approach you'd have to go through each class and change the value assigned to key_name. Now, if you were using the second method you'd only have to change the value assigned to key_name in one place, and that's in the properties file which is much simpler and make things more manageable.
Just another Java problem (I'm a noob, I know): is it possible to use dynamic property binding in a Custom Control with a dynamic property getter in a Java bean?
I'll explain. I use this feature extensively in my Custom Controls:
<xp:inputTextarea id="DF_TiersM">
<xp:this.value><![CDATA[#{compositeData.dataSource[compositeData.fieldName]}]]></xp:this.value>
This is used in a control where both datasource and the name of the field are passed as parameters. This works, so far so good.
Now, in some cases, the datasource is a managed bean. When the above lines are interpreted, apparently code is generated to get or set the value of ... something. But what exactly?
I get this error: Error getting property 'SomeField' from bean of type com.sjef.AnyRecord which I guess is correct for there is no public getSomeField() in my bean. All properties are defined dynamically in the bean.
So how can I make XPages read the properties? Is there a universal getter (and setter) that allows me to use the name of a property as a parameter instead of the inclusion in a fixed method name? If XPages doesn't find getSomeField(), will it try something else instead, e.g. just get(String name) or so?
As always: I really appreciate your help and answers!
The way the binding works depends on whether or not your Java object implements a supported interface. If it doesn't (if it's just some random Java object), then any properties are treated as "bean-style" names, so that, if you want to call ".getSomeField()", then the binding would be like "#{obj.someField}" (or "#{obj['someField']}", or so forth).
If you want it to fall back to a common method, that's a job for either the DataObject or Map interfaces - Map is larger to implement, but is more standard (and you could inherit from AbstractMap if applicable), while DataObject is basically an XPages-ism but one I'm a big fan of (for reference, document data sources are DataObjects). Be warned, though: if you implement one of those, EL will only bind to the get or getValue method and will ignore normal setters and getters. If you want to use those when present, you'll have to write reflection code to do that (I recommend using Apache BeanUtils).
I have a post describing this in more detail on my blog: https://frostillic.us/f.nsf/posts/expanding-your-use-of-el-%28part-1%29
Can I use a Java custom annotation to add some code to a set or get method on a bean property to cleanse the property from bad html being input by my users? I've been looking for examples but I've not seen something that I feel I can extend.
You could define a custom annotation to add a validator to your setter, but is there a reason why you don't want to just embed validation into your bean without an annotation? The annotation mechanism might be difficult for others to understand if they ever need to work with your code.
I would do it this way: Rather than have your property be a String, define your own HtmlString (assuming an equivalent class doesn't already exist in a standard library) which can only be instantiated with valid HTML. Then, have your bean property be of that type. This would solve the validation problem in your component.
Define validation methods in the HtmlString to fit your requirements, so that every HtmlString instance is valid HTML; then, simply define a toString method. This method would likely be much easier for others to follow.