How to use systemproperties to get property by using Spring EL and #Value() - spring

#Configuration
#PropertySource("classpath:test.properties")
public class Config {
#Bean
public CompactDisc cd(#Value("#{ systemProperties['artist']}") String artist) {
HotelCalifornia hotelCalifornia = new HotelCalifornia();
hotelCalifornia.setArtist( artist);
return hotelCalifornia;
}
#Bean
public CdPlayer player(CompactDisc cd) {
CdPlayer player = new CdPlayer();
player.setCd(cd);
return player;
}
}
The property is in the test.properties file. I cant get the property "artist" from the systemProperties.But I can get it if i use #autowired to instantiate a environment bean.How can i deal with it?

you dont have to do anything. the spring recognizes property is first it will check in the system properties, then the class level properties and then properties initialized using property placeholder.
so try using #Value("${artist}") provided you have artist set in the systems property somehow.

Related

Retrieve YML / YAML properties

I have a external yaml properties files that I have loaded and I want to retrieve. But the suggested way to get YAML is like so:
#Value("${some.var}");
and this isn't working.
I am loading the files in like so:
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
String userHome = System.getProperty('user.home');
ArrayList<String> locations = new ArrayList<String>(
Arrays.asList(
"${userHome}/.boot/beapi_server.yml",
"${userHome}/.boot/beapi.yml",
"${userHome}/.boot/beapi_db.yml",
"${userHome}/.boot/beapi_api.yml"
)
);
Collections.reverse(locations);
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
for (String location : locations) {
String finalLocation = location.toString();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new FileSystemResource(finalLocation));
propertySourcesPlaceholderConfigurer.setProperties(Objects.requireNonNull(yaml.getObject()));
}
return propertySourcesPlaceholderConfigurer;
}
The actuator/configprops also don't show the properties.
What am I doing wrong? A bit frustrated.
Ok so I figured it out and wanted to post the answer for others to see.
After loading the external files into your PropertySources, you can now access them through #ConfigurationProperties annotation by referencing the YML structure prefix head and then just access the properties directly through assignment
// 'tomcat' if the top level prefix in my yml file
#ConfigurationProperties(prefix="tomcat")
class something{
ArrayList jvmArgs
}
Now lets look at my yml:
tomcat:
jvmArgs:
-'-Xms1536m'
-'-Xmx2048m'
-'-XX:PermSize=256m'
-'-XX:MaxPermSize=512m'
-'-XX:MaxNewSize=256m'
-'-XX:NewSize=256m',
-'-XX:+CMSClassUnloadingEnabled'
-'-XX:+UseConcMarkSweepGC'
-'-XX:+CMSIncrementalMode'
-'-XX:+CMSIncrementalPacing'
-'-XX:CMSIncrementalDutyCycle=10'
-'-XX:+UseParNewGC'
-'-XX:MaxGCPauseMillis=200'
-'-XX:MaxGCMinorPauseMillis=50'
-'-XX:SurvivorRatio=128'
-'-XX:MaxTenuringThreshold=0'
-'-server'
-'-noverify'
-'-Xshare:off'
-'-Djava.net.preferIPv4Stack=true'
-'-XX:+EliminateLocks'
-'-XX:+ExplicitGCInvokesConcurrent'
-'-XX:+UseBiasedLocking'
-'-XX:+UseTLAB'
And we see this will directly assign the value jvmArgs to the ArrayList JvmArgs in the class above. Simple.
So, rather simple and elegant solution once you know how... but knowing how is the trick isn't it :)
i'm using yaml configuration too. in my case, you have to create a configuration class then you can autowired it.
this is my code:
PdfConfig.java
#Component
#ConfigurationProperties(prefix = "pdf")
#EnableConfigurationProperties
public class PdfConfig {
private String licensePath;
private Watermark watermark;
// setter getter goes here
}
PdfServiceImpl.java
#Service
public class PdfServiceImpl implements PdfService {
#Autowired
private PdfConfig pdfConfig;
}
application-local.yml
#### Pdf Config ####
pdf:
license-path: classpath:license/development/itextkey.xml
watermark:
image-path: classpath:static/img/logo.png
opacity: 0.2f
enabled: true
If you want to learn about setting spring yaml, you can go to this link spring-yaml
Hope this helped!

how to load property file in to spring boot project with annotations?

I have written queries in property file. I want to read the property file in to one class with annotations in spring boot. How can i read it? And is there any better approach for writing queries in spring boot project?
If you add your properties in application.properties file, you can read them inside the spring boot classes like:
#Service
public class TwitterService {
private final String consumerKey;
private final String consumerKeySecret;
#Autowired
public TwitterService(#Value("${spring.social.twitter.appId}") String consumerKey, #Value("${spring.social.twitter.appSecret}") String consumerKeySecret) {
this.consumerKey = consumerKey;
this.consumerKeySecret = consumerKeySecret;
} ...
You can annotate fields in your components by #Value("${property.name}")
Else, you can use Properties Object in java.util package.
For example, i have a mode property, which values are dev or prod, i can use it in my beans as follow :
#Value("${mode:dev}")
private String mode;
The other approach is by using :
Properties pro = new Properties();
pro.load(this.getClass().getClassLoader().getResourceAsStream());
You can use #PropertySource to read the properties from a file and then pass them to a bean. If you have a file called "queries.properties" that has a property like:
query1: select 1 from foo
Then your config might look like:
#PropertySource("classpath:queries.properties")
#Configuration
public class MyConfig {
#Bean
public DbBean dbBean(#Value("${queries.query1}") String query) {
return new DbBean(query);
}
}

creating custom PropertySourcesPlaceholderConfigurer using property loaded dynamically

I am facing some challenge creating PropertySourcesPlaceholderConfigurer based on some value that is available in another property file.
I have a property file, custom-{environment}.property, which contains a value, that is needed to set location of PropertySourcesPlaceholderConfigurer.
My CustomConfiguration looks something like:
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setLocation(customLocation);
//Custom url location based on a String available in the properties file. This is the problem area
return propertySourcesPlaceholderConfigurer;
}
I want to populate this customLocation from the properties file. Tried autowiring Environment, but it's failing as environment is null when placeholderConfigurer() is getting called. Tried using #PropertySource("custom-${environment}.property") and then #Value("**customLocation**"), but that's also not working.
Please let me know how this can be done. Thanks in advance.
I would suggest adding an ApplicationContextInitializer to load your property files instead of a plain #PropertySource. First load your custom-{environment}.properties next your configurable properties file.
public class PropertySourceInitializer implements ApplicationContextInitializer {
private static final String DEFAULT_CONFIG_FILE = "classpath:custom-${environment}.properties";
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
final ConfigurableEnvironment env = applicationContext.getEnvironment();
final MutablePropertySources mps = env.getPropertySources();
//
Resource resource = applicationContext.getResource(env.resolvePlaceholders(DEFAULT_CONFIG_FILE));
mps.addLast(new ResourcePropertySource(resource.getDescription(), resource));
String additional = env.getProperty("name.of.property");
if (StringUtils.hasText(additional) {
Resource additionalResource = applicationContext.getResource(env.resolvePlaceholders(additional));
if (additionalResource.isReadable() ) {
mps.addLast(new ResourcePropertySource(resource.getDescription(), resource));
}
}
}
}
Trying to get it to work with a #PropertySource will be much harder as the phases in which the PropertySourcesPlaceHolderConfigurer is created is different then the one in which the #PropertySource annotations are scanned. Staged loading of #PropertySource (which is basically what you want) is quite difficult. Spring Boot also has its own loading mechanism (which actually is also a ApplicationContextInitializer.
Can you try setting your location as a system property?
#Value("#{ systemProperties['myapp.location'] }")
private String location;
You need to set "myapp.location" as system property.

Is it possible to have non String type values in a Spring Environment PropertySource

I'm trying to add ConfigSlurper's ConfigObjectinto an application context Environment in order to provide configuration values to the context.
The MapPropertySorce itself only expects its values to be of type Object only. But in the end property resolution fails as the EnvironmentAccessor will try to cast each ConfigObject to String.
So basically the question is, is there support for non String property resource values? Any supporting classes there (different EnvironmentAccessor?)
class ConfigSlurperLearningSpec extends Specification {
def configurationResource = new ClassPathResource("/META-INF/de.troi/application.configuration")
ConfigObject configuration = new ConfigSlurper().parse(configurationResource.getURL())
def "use as application context property source"() {
expect:
AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext()
context.register(PropertySourceInjection)
context.getEnvironment().getPropertySources().addLast(new MapPropertySource("mapConfiguration", configuration))
context.refresh()
String configuredValue=context.getBean('testBean')
configuredValue=='create'
}
}
#Configuration
class PropertySourceInjection {
#Value("#{environment['entityManagerFactory']['jpaPropertyMap']['hibernate.hbm2ddl.auto']}")
Object hibernateHbm2ddlAuto;
#Bean
String testBean() {
return new String(hibernateHbm2ddlAuto.toString())
}
}
It is definitely possible to inject non-string objects via ConfigSlurper.
Take a look at (shameless plug) https://github.com/ctzen/slurper-configuration

Customize #PropertyResource handling behavior for java annotation based configuration

I wish to customize the handling of the property source, while using java annotation based intializing a spring web application.
#Configuration
#PropertySource("ldap.properties")
#Repository
public class LdapDao {
...
#Autowired
public void setEnv(Environment env) throws NamingException {
this.url = env.getProperty("url").trim();
this.user = env.getProperty("user").trim();
this.password = env.getProperty("password).trim();
this.initializeLdapContext();
}
...
}
In this case, spring will look for the property source on classpath. If the property source is declared as:
#PropertySource("file:/${conf.dir}/ldap.properties")
ldap.properties is searched under the directory specified by the system property "conf.dir".
I need the behavior where the property resource is first searched under the directory specified by the system property "conf.dir". If it is not found there, its location defaults to classpath.
Any suggestion on how to achieve this behavior?
Use this
#PropertySource({"ldap.properties", "file:/${conf.dir}/ldap.properties"})
and you will get last one, just add in yours propConfig code
PropertySourcesPlaceholderConfigurer propConfig = new PropertySourcesPlaceholderConfigurer();
//.....
propConfig.setIgnoreResourceNotFound(true);
propConfig.setIgnoreUnresolvablePlaceholders(false);
propConfig.setLocalOverride(true);
//....

Resources