How to define #Value as optional - spring

I have the following in a Spring bean:
#Value("${myValue}")
private String value;
The value is correctly injected. However, the variable needs to be optional, it is passed in as a command line parameter (which is then added to the Spring context using a SimpleCommandLinePropertySource), and this argument will not always exist.
I have tried both the following in order to provide a default value:
#Value("${myValue:}")
#Value("${myValue:DEFAULT}")
but in each case, the default argument after the colon is injected even when there is an actual value - this appears override what Spring should inject.
What is the correct way to specify that #Value is not required?
Thanks

What is the correct way to specify that #Value is not required?
Working on the assumption that by 'not required' you mean null then...
You have correctly noted that you can supply a default value to the right of a : character. Your example was #Value("${myValue:DEFAULT}").
You are not limited to plain strings as default values. You can use SPEL expressions, and a simple SPEL expression to return null is:
#Value("${myValue:#{null}}")

If you are using Java 8, you can take advantage of its java.util.Optional class.
You just have to declare the variable following this way:
#Value("${myValue:#{null}}")
private Optional<String> value;
Then, you can check whether the value is defined or not in a nicer way:
if (value.isPresent()) {
// do something cool
}
Hope it helps!

If you want to make the configuration property optional just pass an empty string like this:
#Value("${app.optional.value:}")

I guess you are you using multiple context:property-placeholder/ declarations?
If so, this is a known issue since 2012, but not fixed, apparently due to both lack of interest and no clean way of fixing it. See https://github.com/spring-projects/spring-framework/issues/14623 for discussion and some ways to work around it. It's explained in an understandable way by http://www.michelschudel.nl/wp/2017/01/25/beware-of-multiple-spring-propertyplaceholderconfigurers-and-default-values/

Related

How to define a second environment variable when the first one wasn't resolved in Spring?

Suppose I have configuration property called app.database.url. I need to search for the URL in two places, so I created resolvable property like that:
app.database.url=${APP_DATABASE_URL:DEFAULT_URL}
However instead of searching for the second environment variable with key DEFAULT_URL, spring resolves this property as a string with value DEFAULT_URL. Is is possible to tell spring that the second argument is also should be resolved by environment variables?
I think you can just use this:
app.database.url=${APP_DATABASE_URL:${DEFAULT_URL}}

How to resolve dynamic property name using Spring SPEL?

I've an instance variable the value of which should be set by looking up a dynamic property name.
Class Test {
#Value("#{T(java.lang.String).format('filter.%s.disable', getClass().getSimpleName())}")
private boolean disable;
}
disable should evaluate to true when filter.Test.disable = true and false otherwise. I also want to set a default value false if the property is not defined, which is usually done using the following syntax, but I'm not sure in this case.
#Value("${property:default}")
I'm getting the error:
Caused by: java.lang.IllegalArgumentException: Invalid boolean value
[filter.BeanExpressionContext.disable]
Also tried #Value("${'dcs.cloud.filter.'#{getClass().getSimpleName()}'.disable'}") and some other combinations of # and $ to no avail.
The SPEL doc shows useless parser.parseExpression calls to evaluate expressions, which uses a different syntax, and no one does in reality. Looks like they picked out code from the unit tests instead of real examples.
You can't access the class in which the expression is declared that way. getClass() there acts on the root object for the expression evaluation (the BeanExpressionContext in this case).
It's not clear why you can't just use filter.Test.disable here (unless, perhaps you are trying to get the actual class when Test is subclassed).
You can't do that.
It might be easier to implement EnvironmentAware and set the boolean by getting the property from the environment.

Get Class of Map in FreeMarker

I want to get a variable's class type in freemarker, used var.class.simpleName;
but if var is a Map, freemarker will process class as a key to find value in var.
it throw exception. how can I do this ? thanks for any suggestion.
First I have to ask why do you need that, because FreeMarker templates aren't supposed to know even if var is Map at all. Maybe your data-model is not what the template needs.
Anyway, for now, I would write a custom TemplateMethodModelEx for this purpose, something that you can use like ${classOf(var)}. Inside the TemplateMethodModelEx implementation you will receive a TemplateModel as the argument value, and then you can check if it's an AdapterTemplateModel, and if so you can get back the original object and get its class. (If it's not a AdapterTemplateModel, then it perhaps isn't even a wrapped Java object, so it doesn't make sense to ask what the class of the original object is.) However, the DefaultObjectWrapper with incompatibleImprovements set to less than 2.3.22 doesn't give AdapterTemplateModel to wrapped Map-s... so in 2.3.21 you will still have to use BeansWrapper, but you can at least set simpleMapWrapper to true.
In 2.3.22 it will be actually possible to write ${var?api.class}... you might use the nightly build. Though it only supposed to solve the problem where you can't access business methods because the primary type of the business class is Map.

How to use a method as an argument of another method when they have different types in java?

I need to add a method inside this add(null) method but the method has a string argument like the following
private double mymethod(String writing) // This is the method which must replace
// the null value inside the add(null) method
but since it has a String argument this gives an error! what could i do in order to fix this problem?
From what you have I think that features is a Collection of Doubles - is that right?
And what you want to do is the following:
features.add(mymethod("some string"));
If thats the case I dont see the problem I'm afraid - where is the error being thrown?
Provided your mymethod returns a valid double I cant see what else would cause you a problem here.

Spring Validation - BindingResult

I am trying to understand what BeanPropertyBindingResult does in the following code. Unfortunately, the javadoc is quite useless.
Please take a look at the following code:
BeanPropertyBindingResult errors = new BeanPropertyBindingResult(item, "item");
validator.validate(item, errors);
My questions are:
As far as I can see, BeanPropertyBindingResult is basically some kind of a Map that can contain key/value pairs of (field name, error text). Is this correct, or is the truth more complicated?
When I create a new BeanPropertyBindingResult, why do I need to provide it (as the constructor's first parameter) with the object I am going to validate? As far as I can see, in the second line above, validator.validate(item, errors); the validator gets the object anyway.. so why doing it twice?
The javadoc says about the constructor's second parameter:
objectName - the name of the target object
yes, but why do I need that name? What am I supposed/able to do with it...?
1) Yes, that is my understanding too, even if it is technically a list. -- The most importent part is List<ObjectError> errors defined in the superclass AbstractBindingResult.
2) Because it is demanded by the BindingResult Interface. -- I know this is not a good answer, but If this interfaces requires that method, then ther is no otherway to implement it BTW: I think I have seen some example before where the Autor used null for that field, but I am not 100% if it works correct, but most of the code seams to be able to handle the null value.
3) If you use that binding result for example in a jsp to show the error messages for different input fields, then this must match the model attribute name.
Assume you have a command object with a field name. And a JSP page where the input filed is associated to myCommand.name. Then you need the name myCommand as some kind of prefix for the binding errors. -- It is hard to explain, I hope you understand what I mean

Resources