PropertySourcesPlaceholderConfigurer can't resolve property - spring

I am reading document here
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-value-annotations
#Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(#Value("${catalog.name}") String catalog) {
this.catalog = catalog;
}
}
#Configuration
#PropertySource("classpath:application.properties")
public class AppConfig { }
And the following application.properties file:
catalog.name=MovieCatalog
A default lenient embedded value resolver is provided by Spring. It
will try to resolve the property value and if it cannot be resolved,
the property name (for example ${catalog.name}) will be injected as
the value.
What does "it cannot be resolved" mean? If I don't have this property in the application.properties, it gives me error:
Could not resolve placeholder 'catalog.name' in value "${catalog.name}"
Updated:
I figured it out. In Spring core, if property not found, it uses ${catalog.name}
But in SpringBoot, if property not found, it gives error.

Resolve means find. Sometime the resolution (finding) can be complicated.
An SpringBoot each property in application properties can also be injected with an environment variable. So catalog.name could be left out of apllication.properties and used as env var CATALOG_NAME.
AFAIK a value can also come in on a command line.

Related

#ConfigurationProperties returns property placeholder instead of null

I have the following #ConfigurationProperties property holder:
#ConfigurationProperties(prefix = "custom.service")
public class CustomServicePropertyHolder {
private String name;
}
and my application.properties looks like this:
custom.service.name=${remote.service.name}
custom.service.....=...
custom.service.....=...
remove.service.name is an environment variable received in the runtime.
However, when remote.service.name was not provided, the value of the EtlConfigurationHolder.name is a string "${remote.service.name}".
How to make the property to return null instead of this placeholder string ?
I also encountered such a problem ... And it has been present for a long time
Unresolved Placeholder Validation for Spring Boot Configuration Properties
https://github.com/spring-projects/spring-boot/issues/4302
https://github.com/spring-projects/spring-boot/issues/1768
I found only one place where at least some solution is attached
https://davidagood.com/spring-boot-fail-on-missing-env-vars/

#Value annotation is only loading default - not using property file

Problem
I think that I havn't understood something properly because my #Value is always loading the default calue.
Java Code
So I have the following:
#Value("${disableQuerySecurityDebug:false}")
private boolean disableQuerySecurityDebug;
And this is set to false always.
Property file: application-disableQuerySecurityDebug.properties
I have a properties file called application-disableQuerySecurityDebug.properties.
And I have the following entry inside the file:
disableQuerySecurityDebugMne=true
And I run the application with the following profile: disableQuerySecurityDebugMne
I was expecting the value to be set to true, but it is always false.
Update
Based on deadpool's answer, I ended up with the following:
#Profile("disableQuerySecurityDebug") #Data
#Configuration
public class DisableSecurityConfig implements DisableQuerySecurityDebug {
#Value("${disableQuerySecurityDebug:true}")
private boolean securityDisabled;
}
#Profile("!disableQuerySecurityDebug") #Data
#Configuration
public class EnableSecurityConfig implements DisableQuerySecurityDebug{
#Value("${disableQuerySecurityDebug:false}")
private boolean securityDisabled;
}
public interface DisableQuerySecurityDebug{
public boolean isSecurityDisabled();
}
#Value annotation is only used to inject properties values into spring Beans from yml or properties file
This annotation can be used for injecting values into fields in Spring-managed beans and it can be applied at the field or constructor/method parameter level.
If you want to inject values based on profile specific then use #Profile on class
#Profile("disableQuerySecurityDebug")
#Configuration
public class Config {
#Value("${disableQuerySecurityDebug:false}")
private boolean disableQuerySecurityDebug;
}
You could also specify it on the command line by using the following switch:
java -jar demo.jar --spring.profiles.active=disableQuerySecurityDebug

Can you or can't you use a property from a config file when using Spring #Condition?

I have read pretty much everything I can find on StackOverflow and other sites and I don't see a definitive answer anywhere.
I have a class that implements #Condition that I use in a #Configuration file to conditionally load some beans. I am doing something like this:
public class MyCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metdata) {
String property = context.getEnvironment().getProperty("some.prop.from.file");
boolean enable = Boolean.parseBoolean(property);
return enable;
}
}
When debugging I see that getting the property from the environment always returns null, even though the property is injected in other beans using #Value.
So my question can you or can't you attempt to get a property value from a file within a #Condition class? Can you only get System properties? I would think that this is a common use case that I would think Spring could handle.
Had to add the property to application.properties and not the other property files that are loaded during startup.

How to access a Spring Boot Application's name programmatically?

I've defined an application name using the bootstrap.yml file in my spring boot application.
spring:
application:
name: abc
How can i get this application name during runtime/programmatically ?
You should be able to use the #Value annotation to access any property you set in a properties/YAML file:
#Value("${spring.application.name}")
private String appName;
#Autowired
private ApplicationContext applicationContext;
...
this.applicationContext.getId();
Please, find this:
# IDENTITY (ContextIdApplicationContextInitializer)
spring.application.name=
spring.application.index=
In Spring Boot Reference Manual.
And follow with source code for that ContextIdApplicationContextInitializer class:
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
}
Where the default behavior is with this:
/**
* Placeholder pattern to resolve for application name
*/
private static final String NAME_PATTERN = "${vcap.application.name:${spring.application.name:${spring.config.name:application}}}";
Since the #Value annotation is discouraged in Spring Boot when referencing configuration properties, and because applicationContext.getId(); doesn't always return the value of spring.application.name another way is to get the value from the Environment directly
private final Environment environment;
...
public MyBean(final Environment environment) {
this.environment = environment;
}
...
private getApplicationName() {
return this.environment.get("spring.application.name");
}
Another possible way would be to create your own ConfigurationProperties class to get access to the value.
I'm not saying these are the best ways, and I hope/wish that there is a better way, but it is a way.
Note! If your using a SpringBootTest, you need to suplly the properties/yml.
Otherwise, the environment/appcontext does not load the config files.
The, your app name is not set.
Like so:
#PropertySource("classpath:application.properties")
#RunWith(SpringRunner.class)
#SpringBootTest
....
This post is aged but I hate unanswered questions.
So use the following snippet:
#Value("${spring.application.name [: defaultValue]}")
private String appName;
What is between [] is optional.
So I found a really ugly way to do this, but it works so I'm not searching further. Maybe this will help someone.
The basic premise is that spring Environment stores the value inside a propertySource.. It appears that bootstrap config is stored in the ResourcePropertySource and so you can get it from that. For me it is currently throwing an exception, but then I can get the value out of the exception, so I haven't looked any further:
try {
this.environment.getProperty("name", ResourcePropertySource.class);
} catch (ConversionFailedException e) {
String res = (String)e.getValue();
}
And then you can just do this for every property you are interested in.
Like I said ugly, but it works.

Spring 3.1 #PropertySources does not throw Exception if property does not exist

Although the name of a property in my Configuration class is wrong, Spring does not throw an Exception. The log shows that the key is not found.
2012-06-17 05:26:49,545 DEBUG | main | o.s.core.env.PropertySourcesPropertyResolver | Could not find key 'pegaso.cfdiRequest' in any property source. Returning [null]
I am using the property in an Environment class in my Configuraton Class
#Configuration
#PropertySource("classpath:application.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public FesaBean fesaBean() {
FesaBean fesaBean = new FesaBean();
fesaBean.setMyProperty(env.getProperty("pegaso.cfdiRequest"));
return fesaBean;
}
pegaso.cfdiRequest does not exist in application.properties. Still, I do not get an Exception.
env.getRequiredProperty("propertyName")
Environment implements PropertyResolver which has such method Environment.getRequiredProperty() solves the issue. If the property is not found a java.lang.IllegalStateException is thrown.
Per the API for Environment, it returns a null for values that cannot be resolved, so just make a null check in your specific case:
if (env.getProperty("pegaso.cfdiRequest")==null)... // variable not resolved

Resources