Spring boot: how to read specific property from application.yml and ignore others - spring

My goal is to read some property from application.yml file and ignore other properties. This is need for testing purposes - I want to read part of config and validate it. I want to ignore other properties because Spring Boot tring to handle it but this is no need for my test.
Example.
Config:
first:
property:
{cipher}value #for example Spring trying to handle cipher and throws exception
second:
property:
value
Class (using String for simplification):
#Configuration
public class Configuration {
#Bean
#ConfigurationProperties(prefix = "second.property")
public String secondProperty() {
return new String();
}
}
Test class:
#SpringBootTest
public class ConfigPropertiesCheckerIntegrationTest {
#Autowired
String secondProperty;
#Test
void checkAutoConfigEndpointProperties() {
assertThat(secondProperty, is(notNullValue()));
}
}
So question: how to ignore first.property and say Spring just skip it?

You can disable {cipher}ed properties decryption with spring.cloud.decrypt-environment-post-processor.enabled=false. E.g:
#SpringBootTest(properties = "spring.cloud.decrypt-environment-post-processor.enabled=false")

Related

Spring Boot - Nested Configuration Properties are not recognized

As the title says, my custom properties are not registered when Application is starting. Would you mind taking a look?
My custom.yml:
bridge:
url: xxx
authentication:
auth-url: xxx
user: xxx
My BridgeProperties.java:
#Component
#PropertySource("classpath:custom.yml")
#ConfigurationProperties(
prefix = "bridge"
)
public class BridgeProperties {
#NestedConfigurationProperty
protected ApiProperties apiProperties = new ApiProperties();
}
My ApiProperties.java:
public class ApiProperties {
protected String url;
protected ApiProperties.Authentication authentication;
// getter and setter
public ApiProperties() {
}
public static class Authentication {
protected String authUrl;
protected String user;
public Authentication() {}
// getter and setter
}
My Application's entry point:
#SpringBootApplication
#PropertySources(value = {
#PropertySource("classpath:application.yml"),
#PropertySource("classpath:custom.yml")
})
public class IntegrationService {
public static void main(String... args) {
SpringApplication.run(IntegrationService.class, args);
}
}
When printing to the command line, I get null instead of the values I assigned to url, auth-url, and user in the custom.yml.
As mentioned in the Baeldung Site:
It's also worth mentioning that YAML files do not support the #PropertySource annotation, so if we need to use this annotation, it would constrain us to using a properties file.
If you really need to import additional external file in yaml format, you have to implement your own PropertySourceFactory like in this article.
For me I do not see the advantage not using the default application.yml as you can define multiple sections managed by different Properties classes.
For example, if you just put your properties in the application.yml and if you compile with a recent JDK (>=jdk 14) you can even use the record for managing your properties in a very compact manner:
What you have to do is just to add the EnableConfigurationProperties annotation:
#SpringBootApplication
#EnableConfigurationProperties(BridgeProperties.class)
public class IntegrationService {
public static void main(String... args) {
SpringApplication.run(IntegrationService.class, args);
}
}
and define a record for mapping your yaml properties:
#ConfigurationProperties(prefix = "bridge")
public final record BridgeProperties(String url, Authentication authentication) {
public record Authentication(String authUrl, String user){
}
}
Remember you can also define environment variable in profiles like application-dev.yml if you start your app with profile dev and another one e.g. for production application-prd.yml if your profile for production is named prd. You can still keep the common properties in the application.yml.
If you really want to go in the external file path, I suggest to switch to .properties as the #PropertySource supports it natively.

Mapping an array of properties in spring boot and injecting into a prototype scope

I am very new to spring boot and here is how my yaml looks like
configs:
-
collection: col1
groupId: groupId1
topic: topic1
-
collection: col2
groupId: groupId2
topic: topic2
I would like to have 3 classes with their scope defined as a prototype and use the property from the yaml something like
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class mongoListener {
public mongoListener(#Value("${config.collection}") String collectionName) {
//do something
}
}
Similarly, have 2 more classes that would use groupID and topic as well. I am stuck here on how to design.
It will be of great help if anyone can explain how to achieve this.
Please try:
Put your application.yaml that consists of your yaml configuration into /src/main/resources/.
Use the property by #Value annotation like:
public mongoListener(#Value("${configs[0].collection}") String collectionName) {
// collectionName is 'col1'
//do something
}
[EDIT 1]
You can create singleton beans different from each other in name like:
#Configuration
public class MyConfiguration {
#Bean("mongoListener_A")
public mongoListener mongoListener_A(#Value("${configs[0].collection}") String collectionName) {
return new mongoListener(collectionName);
}
#Bean("mongoListener_B")
public mongoListener mongoListener_B(#Value("${configs[1].collection}") String collectionName) {
return new mongoListener(collectionName);
}
// ... and so on
}
[EDIT 2]
You can read your yaml configurations into java objects by using #ConfigurationProperties annotation.
#Data //lombok annotation.
#Component("myConfigs")
#ConfigurationProperties
public class Configs {
private final List<Config> configs;
#Data //lombok annotation.
public static class Config {
private String collection;
private String groupId;
private String topic;
}
}
You can create your mongoListeners from that objects like:
#Configuration
public class MyConfiguration {
#Bean
public List<mongoListener> mongoListeners(#Qualifier("myConfigs") Configs configs) {
return configs.getConfigs().stream()
.map(Config::getCollection)
.map(mongoListener::new)
.collect(Collectors.toList());
}
// ... and so on
}
The beans are still singleton but you can create an arbitrary number of instances depending on your yaml file.
See Also
Use YAML for External Properties - Spring Boot Reference Documentation “How-to” Guides
Spring #Value with arraylist split and obtain the first value

Do not want to load application.yml when testing with Spring Boot

How can I tell Spring to load only application-test.yml and not application.yml file ?
I have a config class:
#ActiveProfiles("test")
#SpringBootConfiguration
public class MongoTestConfig {
#Autowired
MongoOperations operations;
...
}
And a test class:
#RunWith(SpringRunner.class)
#DataMongoTest
#SpringBootTest(classes = MongoTestConfig.class)
public class TagDefinitionRepositoryTest {
...
#Test
....
}
I've tried to add :
#TestPropertySource(locations = {"classpath:application-test.yml"})
#ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
To my config class but it doesn't work: Spring still load application.yml
I don't think you can tell Spring Boot to ignore application.yml completely. What you can do though is to override all the non desired properties using test specific property files.
Based on the code snippet you posted, any property in application-test.yml will override the equivalent property in application.yml.
Spring Boot considers application-test.yml specific to the profile "test" (which has a higher priority over the default application.yml). No annotation #TestPropertySource is needed.
But if you want to choose another name for your properties file, then you can use #TestProertySource, since files indicated in #TestProperySource parameters have higher priority over the others.
You might want to have a look at Spring Boot external configuration rules for resolving properties
I've end up using #SpringBootTest instead of #DataMongoTest
#SpringBootConfiguration
#ComponentScan(basePackages = {"com.package.services"})
#EnableMongoRepositories(basePackages = {"com.package.repositories"})
public class MongoTestConfig {
private static final MongodStarter starter = MongodStarter.getDefaultInstance();
#Bean
public MongoClient mongoClient() throws IOException {
MongodExecutable _mongodExe;
MongodProcess _mongod;
_mongodExe = starter.prepare(new MongodConfigBuilder()
.version(Version.Main.V3_2)
.net(new Net("localhost", 12345, Network.localhostIsIPv6()))
.build());
_mongod = _mongodExe.start();
MongoClient _mongo = new MongoClient("localhost", 12345);
return _mongo;
}
#Bean
public MongoDbFactory mongoDbFactory() throws IOException{
return new SimpleMongoDbFactory(mongoClient() , "test");
}
#Bean
public MongoTemplate mongoTemplate() throws IOException {
return new MongoTemplate(mongoDbFactory());
}
And my test class is:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyRepositoryTest {
...

Kotlin spring-boot #ConfigurationProperties

I'm trying to create the following bean AmazonDynamoDBAsyncClientProvider. I've application.properties that defines endpoint and tablePrefix which I'm trying to inject using #ConfigurationProperties
Following is the code snippet for the same. When I run my spring-boot app it doesn't work.
I've tried doing the same ConfigurationProperties class using a regular java class which does set those properties but when it comes to AmazonDynamoDBAsyncClientProvider, the properties are empty. What am I missing here?
#Component
open class AmazonDynamoDBAsyncClientProvider #Autowired constructor(val dynamoDBConfiguration: DynamoDBConfig){
#Bean open fun getAmazonDBAsync() = AmazonDynamoDBAsyncClientBuilder.standard()
.withEndpointConfiguration(
AwsClientBuilder.EndpointConfiguration(dynamoDBConfiguration.endpoint, dynamoDBConfiguration.prefix))
.build()
}
here is the kotlin bean that I'm trying to autowire with configuration
#Component
#ConfigurationProperties(value = "dynamo")
open class DynamoDBConfig(var endpoint: String="", var prefix: String="")
finally heres the regular java bean that does get populated with ConfigurationProperties but when it gets Autowired I see those properties being empty/null
#Component
#ConfigurationProperties("dynamo")
public class DynamoDBConfiguration {
private String endpoint;
private String tablePrefix;
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getTablePrefix() {
return tablePrefix;
}
public void setTablePrefix(String tablePrefix) {
this.tablePrefix = tablePrefix;
}
}
Have you tried getting rid of the #Component annotation on your ConfigurationProperties class?
Here is what I have done with Kotlin and Spring, hope it helps.
I am trying to leverage the kotlin-spring and kotlin-allopen gradle plugin
dependencies {
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion"
}
apply plugin: 'kotlin-spring'
apply plugin: 'kotlin-noarg'
noArg {
annotation("your.noarg.annotation.package.NoArg")
}
They do make spring development with kotlin a lot easier.
#ConfigurationProperties("dynamo")
#NoArg
data class DynamoDBConfiguration(var endpoint: String, var prefix: String)
I tried your configuration class and it gets populated. I think your mistake is in the way you are trying to create the bean, the function needs to be in a class annotated with #Configuration, this should work:
#Configuration
class Beans {
#Bean
fun getAmazonDBAsync(config: DynamoDBConfiguration) =
AmazonDynamoDBAsyncClientBuilder.standard()
.withEndpointConfiguration(
AwsClientBuilder.EndpointConfiguration(config.endpoint, config.prefix)
)
.build()
}
Spring will inject the config for you, as long as you annotate the config with #Component, like you did above.
I had a similar problem and fixed it this way:
I defined the configuration properties class with lateinit vars:
#ConfigurationProperties(prefix = "app")
open class ApplicationConfigProperties {
lateinit var publicUrl: String
}
Then configured a bean in my spring boot application:
#SpringBootApplication
open class Application {
#Bean open fun appConfigProperties() = ApplicationConfigProperties()
}

Convert Spring bean configuration into XML configuration

i am working on BIRT reporting tool. which is need to called by spring MVC.
i got one example from spring which is here. in this example, configuration is done via bean. can anyone help me convert this configuration in to xml based configuration ?
#EnableWebMvc
#ComponentScan({ "org.eclipse.birt.spring.core","org.eclipse.birt.spring.example" })
#Configuration
public class BirtWebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/reports").setViewName("birtView");
}
#Bean
public BirtView birtView() {
BirtView bv = new BirtView();
// bv.setReportFormatRequestParameter("ReportFormat");
// bv.setReportNameRequestParameter("ReportName");
bv.setBirtEngine(this.engine().getObject());
return bv;
}
#Bean
public BeanNameViewResolver beanNameResolver() {
BeanNameViewResolver br = new BeanNameViewResolver();
return br;
}
#Bean
protected BirtEngineFactory engine() {
BirtEngineFactory factory = new BirtEngineFactory();
return factory;
}
}
I wants a similar configuration in xml file.
There's really no tool for extracting Spring annotations to Spring bean context xml file. You'll have to do it by hand, shouldn't be too hard as all the Spring annotations functionality can be duplicated into Spring context xml tags.
if you want to use spingmvc, so no need the configuration files.
my solution is that in Birt Script i call the impl java file like this :
sampleService = new Packages.com.example.warlock.service.SampleServiceImpl();
pojo = new Packages.com.example.warlock.entity.Sample();
iterator = sampleService.getSamples().iterator();
because my SampleService is a interface and SampleServiceImpl is impl java, the two java file are not config as #Bean.
At first i want to get the data from ModelMap but failed, so i skip the controller and straight to call Service, then final call the DAO to get the Data from DB

Resources