I'm looking for a way to follow source of spring configuration from annotation.
E.g. Having below Bean is any way to e.g. click on my-components-service.books.configurations and be redirect or list yaml files which contains config which would be injected in runtime?
#Bean
#ConfigurationProperties(prefix = "my-components-service.books.configurations")
Map<ComponentType, BooksConfiguration> booksConfiguration() {
return new HashMap<>();
}
If #ConfigurationProperties is at the class level then there should be some gutter icons that will show where the properties have been set.
It doesn't look like this works when it's specified on a #Bean like in your example however. A possible workaround is to use a nested #Configuration class, though that may be undesirable.
Related
Suppose I have a #Configuration class or better yet a #ConfigurationProperties class.
I'd like the configuration to be loaded from a specific application-x.properties file.
How can I do that? (without defining a new Spring profile)
You have to use #PropertySources, ex: #PropertySource("classpath:foo.properties").
Check this to have more insight and see the other options.
https://www.baeldung.com/properties-with-spring
I am creating a spring-boot application which also creates bean for one of the classes of an external lib, this external java bean needs java.util.properties as one of the constructor parameter. Although I can use configurationPropeties with prefix to read properties from the spring boot loaded property file and convert it to java.util.properties.However, I don't want any additional prefix in the property file. is there any other way where I can convert the spring-boot loaded env or property source to java.util.properties
here is the code for reference
#Configuration
public class AppConfig {
#ConfigurationProperties(prefix = "some.prefix")
#Bean
public Properties getProperties() {
return new Properties();
}
#Bean
public ExternalClass externalClass() throws ConfigException {
return ExternalClass.getInstance(getProperties());
}
}
the above code work nicely, but I need to add an unnecessary prefix to the properties for conversion. could someone suggest any other approach apart from adding prefix to the propeties
Take a look at this documentation. It explains property binding techniques used in spring-boot.
Config
#Configuration
#PropertySources({
#PropertySource("classpath*:properties/test-database.properties")
})
public class DataSourceConfiguration {//...
}
Prop location
D:\Projects\opti\dao\src\main\resources\properties\test-database.properties
D:\Projects\opti\dao\src\main\resources marked as resource folder.
To avoid this kind of problem the issue is to set the jboss.server.config.dir in VM arguments like that :
-Djboss.server.config.dir="[jboss_repository]/server/[default-all-standard-standalone]/conf" –server
and u set PropertySource like this :
#Configuration
#PropertySource("file:${jboss.server.config.dir}/file.properties")
Or you set ur property like that
#PropertySource(value = "classpath:application.properties")
When executed, properties will be imported from the application.properties file, located in the classpath root.
It isn't clear well the your problem considering the details of your question, but a typical problem whit #PropertySource is that yuo have configure a spring bean for manage the properties. In old years in which xml was the best way for configure Spring you used a namespace configuration that configure a spring bean for use proeprties in your bean, mainly with #Value. In java config for benefit of same behaviour you have configure a bean like belove:
#Bean
public static PlaceholderConfigurerSupport propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
I hope that this can help you
I've created a lot of common small bean-definition containers (#Configuration) which I use to rapidly develop applications with Spring Boot like:
#Import({
FreemarkerViewResolver.class, // registers freemarker that auto appends <#escape etc.
ConfigurationFromPropertiesFile.class, // loads conf/configuration.properties
UtfContentTypeResponse.class, // sets proper Content-language and Content-type
LocaleResolverWithLanguageSwitchController // Locale resolver + switch controller
);
class MySpringBootApp ...
For example, one of such #Configurations can set up session storage for locale cookie with web controller to switch to selected language etc.
They are very fun to work with and reuse, but it would be really great to make it parametrized, which could allow lot more reusege. I mean something like:
Pseudo code:
#Imports( imports = {
#FreemarkerViewResolver( escapeHtml = true, autoIncludeSpringMacros = true),
#ConfigurationFromProperties( path = "conf/configuration.properties" ),
#ContentTypeResponse( encoding = "UTF-8" ),
#LocaleResolver( switchLocaleUrl = "/locale/{loc}", defaultLocale = "en"
})
So, I basically mean "configurable #Configurations". What would be the best way to make the configuration that way?
Maybe something more like this (again, pseudo code):
#Configuration
public class MyAppConfiguration {
#Configuration
public FreemarkerConfiguration freemarkerConfiguration() {
return FreemarkerConfigurationBuilder.withEscpeAutoAppend();
}
#Configuration
public ConfigurationFromPropertiesFile conf() {
return ConfigurationFromPropertiesFile.fromPath("...");
}
#Configuration
public LocaleResolverConfigurator loc() {
return LocaleResolverConfigurator.trackedInCookie().withDefaultLocale("en").withSwitchUrl("/switchlocale/{loc}");
}
Let me quote Spring Boot Reference Guide - Externalized Configuration:
"Spring Boot allows you to externalize your configuration so you can work with the same application code in different environments."
In my opinion the customization is not done at import time via annotation parameters like in your 2nd pseudo code block, instead the customization happens at run time e.g. in the configuration classes. Let me adapt your 3rd code block (only one function):
#Configuration
public class MyAppConfiguration {
#Autowired
private Environment env;
// Provide a default implementation for FreeMarkerConfigurer only
// if the user of our config doesn't define her own configurer.
#Bean
#ConditionalOnMissingBean(FreeMarkerConfigurer.class)
public FreeMarkerConfigurer freemarkerConfig() {
FreeMarkerConfigurer result = new FreeMarkerConfigurer();
result.setTemplateLoaderPath("/WEB-INF/views/");
return result;
}
...
#Bean
public LocaleResolverConfigurator loc() {
String defaultLocale = env.getProperty("my.app.config.defaultlocale", "en");
String switchLocale = env.getProperty("my.app.config.switchlocale", "/switchlocale/{loc}");
return LocaleResolverConfigurator.trackedInCookie().withDefaultLocale(defaultLocale).withSwitchUrl(switchLocale);
}
For LocaleResolverConfigurator the configuration is read from the environment, meaningful default values are defined. It is easy to change the default value(s) by providing a different value for a config parameter in any of the supported ways (documented in the first link) - via command line or a yaml file. The advantage over annotation parameters is that you can change the behavior at run time instead of compile time.
You could also inject the config parameters (if you prefer to have them as instance variable) or use a lot of other conditions, e.g. #ConditionalOnMissingBean, #ConditionalOnClass, #ConditionalOnExpression and so on. For example with #ConditionalOnClass you could check if a particular class is on your class path and provide a setting for the library identified by this class. With #ConditionalOnMissingClass you could provide an alternative implementation. In the example above I used ConditionalOnMissingBean to provide a default implementation for the FreeMarkerConfigurer. This implementation is only used when no FreeMarkerConfigurer bean is available thus can be overridden easily.
Take a look at the starters provided by Spring Boot or the community. A good read is also this blog entry. I learned a lot from spring-boot-starter-batch-web, they had an article series in a German Java magazine, but parts are also online, see Boot your own infrastructure – Extending Spring Boot in five steps (MUST READ) and especially the paragraph "Make your starter configurable by using properties".
Though I like the idea of having imports be parameterized, I think that as it stands now using #Import and #Configuration not a good fit.
I can think of two ways to use dynamic configurations, that don't rely on PropertySource style configuration.
Create a custom #ImportConfig annotation and annotation processor that accepts configuration properties that are hard-coded into the generated source files.
Use a BeanFactoryPostProcessor or BeanPostProcessor to add or manipulate your included beans respectively.
Neither is particularly simple IMO, but since it looks like you have a particular way of working. So it could be worth the time invested.
I have an authentication service that I want to autoconfigure at runtime but that will be mocked up for development and testing. I would like to use the #ConfigurationProperties feature to define the necessary parameters, but I also need to be able to only conditionally create the AuthenticationManager instances, depending on whether a live service is configured.
The approach I would like to take is to use something like #ConditionalOnBean(AuthProperties.class), but
Spring Boot creates a bean of my #ConfigurationProperties class regardless of whether the properties are present. I can apply validation annotations to the fields, but then the context won't start at all if a live service is not configured.
Is there a clean way to make a configuration section conditional on having the properties specified in an #ConfigurationProperties class without repeating the property names in #ConditionalOnProperty?
Can't you just use profile of your application-some_profile.properties file and then create your properties bean conditionally like this
#Profile("some_profile")
#Component
#ConfigurationProperties(prefix = "some.selector")
public Class YourConfiguration{
private property option;
}
this way it only gets created conditionally depending which profile you select live or mock.
Than you can either use selected profile for your #Configuration authentication classes for separate approaches or follow with #ConditionalOnBean. That's what profiles are for or maybe I misunderstood the question.
I had a similar problem and I could resolve it with this approach using Spring Boot and Java 8, hope it helps someone:
#Configuration
#PropertySources({
#PropertySource("classpath:integration.properties"),
#PropertySource(value = "classpath:integration-${spring.profiles.active}.properties", ignoreResourceNotFound = true)
})
#ConfigurationProperties(prefix = "integration")
public class IntegrationProperties {
private String user;
private String password;
private String projectId;
....
}
integration.properties
integration.user=User
integration.password=Password
integration.project-id=123
integration-prod.properties
integration.project-id=897
Spring Boot will create the bean using the properties file, and for production (using the profile prod) it will use the other file and override the project-id. The ignoreResourceNotFound = true will avoid the FileNotFoundException on startup when you are not using the prod profile.