Spring. load application.properties with sections - java

I ask you for help.
I have a file with properties:
[dbname1]
host= ...
port= ...
username= ...
password= ...
[dbname2]
…
[dbname3]
…
[.......]
There are more than 1 number of sections.
Name of DB may be any.
Can you tell me please what is better way to read properties from file with sections: to realize it with PropertySourcesPlaceholderConfigurer or any other standart way of Spring Boot?
Thank you!

You can't have sections in a properties file
https://docs.oracle.com/cd/E23095_01/Platform.93/ATGProgGuide/html/s0204propertiesfileformat01.html
You can use YAMLformat instead ( it's supported by spring boot )
https://www.baeldung.com/spring-yaml
YAML Format supports hierarchical properties definition and you can have override them per Profile in the same file

Related

Configuration of thymeleaf text template in spring boot application.properties failed

I'm trying to configure a simple thymeleaf text template in my spring boot configuration and got to the point where the thymeleaf variable placeholder and the spring boot configuration property placeholder interfer (afaik both use the SpEL) when the template contains a colon (e.g. "[(${#dates.format(date, 'dd-MM-yyyy HH:mm')})]" as spring boot tries to resolve the variable "#dates.format(date, 'dd-MM-yyyy HH" but uses default value "mm')" instead.
I tried to change the spring boot prefix of the PropertySourcesPlaceholderConfigurer, but then some of my included libraries no longer work as they use the ${} variables
Is there a way to extend thymeleaf to treat %{} like ${} ?
I want to avoid replacing the template i read from the config, as i configure those templates on various properties and classes
ad1: For configuration i use a custom mechanism that converts a xml file into yaml which will then be used for configuration, so basically you can say its a application.yml configuration file. I cannot use custom template files in this scenario as the customer must be able to configure the template in a custom xml editor. The templates are all just a few words (like the subject of an email e.g.)
Thank you 62mkv, this seems to usually be the solution, thats why i marked it as the answer.
Anyways it wasn't the solution in my case, as it still didnt work, which is because of the way i load the config using a custom PropertySourceLoader
JAXBContext context = JAXBContext.newInstance(PICONFIG.class);
PICONFIG config = (PICONFIG) context.createUnmarshaller().unmarshal(resource.getInputStream());
YAMLFactory factory = new YAMLFactory();
//factory.disable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID);
ObjectMapper mapper = new ObjectMapper(factory);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String yaml = mapper.writeValueAsString(config);
PropertySourcesPlaceholderConfigurer c;
return new YamlPropertySourceLoader().load(name,new ByteArrayResource(yaml.getBytes(StandardCharsets.UTF_8)));
I now decided to just use [(#{})] for my text templates and then replace the # in the setter of the configuration bean, which seems to work so far and wasn't to big of as issue as i refactored my code to use a common configuration class for the templates
You can protect your expression by wrapping certain placeholders, thus hiding them from Spring Boot PropertyResolver mechanism:
application.properties:
test-template=[(#{'$'}{#dates.format(date, 'dd-MM-yyyy HH:mm')})]
see full working code here: https://github.com/62mkv/spring-properties-thymeleaf.
This solution is "loaned" from here: https://github.com/spring-projects/spring-framework/issues/9628

Spring - yaml and .properties configurations

i've been working with Spring for some time and have a question regarding the very common configuration properties files (like the common application.properties that comes with every spring boot app you initialize). Recently, i also found that configurations like this can be done in yaml files. I have two questions:
When in a application.properties file, we write something like:
# application.properties
spring.debug = true
some-random-value = 15
does this mean that these values will be injected in the application context?
When we write something like:
# application.properties
spring.debug = true
does this mean, that somewhere, there is some class, that has an attribute that looks something like this? -->
#Component
class SomeClass{
#Value("spring.debug")
boolean shouldIRunInDebugMode;
...
}
2.a. If the answer to question 2 is yes, then how can I, looking at something like this:
# application.properties
spring.debug = true
find that class that is expecting that value. The same would apply to if i was looking at something like:
# application.yaml
someThidPartyLibraryName:
shouldWeLog: true
If i see a yaml configuration file, just looking at all the configuration there usually is not enough for me to know what is happening. How can i find the class that is being affected by this configuration, so that i can better understand what this config is doing?
Thank you!
The response is generally yes. If you declare a property in the application.properties or application.yaml is mainly, because you would use it later in the code, for example injecting in some bean with the support of #Value annotation. However, there are also many built-in properties (let's say for example server.port), which you usually don't have to declare and therefore you won't see explicitly in the code. Use an IDE to search the configuration properties and the manual to check the preconfigured ones in case of need.
Your understanding regarding spring value injections from application.properties is correct. #2 - is Yes. Any property from application.properties can be injected to any java class as #Value.
Regarding #2.a - Yaml is just another format on how you organize your variable hierarchy by indentations. That's a superset to the JSON structure.
For example,
in application.properties file you can add something like this
myapp.db.url=<dburl>
myapp.db.username=<dbuser>
myapp.db.password=<dbpassword>
the same can be represented in Yaml in a much efficient manner as below
myapp:
db:
url:<dburl>
username:<dbuser>
password:<dbpassword>
And in either case, for your Jave file you can inject as
#Value("myapp.db.url"
private String dbUrl;
Properties defined in yaml or a properties file may be accessed using the #Value annotation to inject, or using a #ConfigurationProperties class - see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-typesafe-configuration-properties for complete details.
Finding the property usage is supported by some IDEs - IntelliJ allows you to click through. Otherwise it's a search through the source. For #ConfigurationProperties, once you find the class then just look for code that calls its accessor methods.
Properties files and yaml files are used in Spring Boot for configurations. The main difference between the two is yaml provides structuring/grouping of configurations where as Properties are usually flat and may be repeating the same information:
For example;
Properties file
server.port = 8080
server.host = localhost
yaml file
server:
port: 8080
host: localhost
But in a Spring Boot AutoConfiguration class regardless of yaml or Properties used, a following looking ConfigurationProperties class will be used which will map server.port and server.host
#ConfigurationProperties(prefix = "server")
public class ServerConfiguration {
private int port;
private String host;
}
#Configuration
#EnableConfigurationProperties(ServerConfiguration.class)
public class ServerAutoConfiguration {
}
Hope this answers your questions.

Configuring data source URL in Spring without XML

I have a simple Web MVC application using Spring Boot that communicates with a database; the DB is H2 and has been in memory until now. I want to change that, and thus use a jdbc:h2:file:... URL.
Up until now, I have not needed to add any XML to configure my application, and I'd prefer it to stay that way if possible. But I can't figure out how to specify a different JDBC URL. I obtained and inspected the data source by passing it to an #Bean method:
org.apache.tomcat.jdbc.pool.DataSource#745e6f01{ConnectionPool[
defaultAutoCommit=null;
defaultReadOnly=null;
defaultTransactionIsolation=-1;
defaultCatalog=null;
driverClassName=org.h2.Driver;
maxActive=100;
maxIdle=100;
minIdle=10;
initialSize=10;
maxWait=30000;
testOnBorrow=false;
testOnReturn=false;
timeBetweenEvictionRunsMillis=5000;
numTestsPerEvictionRun=0;
minEvictableIdleTimeMillis=60000;
testWhileIdle=false;
testOnConnect=false;
password=********;
url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;
username=sa;
validationQuery=null;
validationQueryTimeout=-1;
validatorClassName=null;
validationInterval=30000;
accessToUnderlyingConnectionAllowed=true;
removeAbandoned=false;
removeAbandonedTimeout=60;
logAbandoned=false;
connectionProperties=null;
initSQL=null;
jdbcInterceptors=null;
jmxEnabled=true;
fairQueue=true;
useEquals=true;
abandonWhenPercentageFull=0;
maxAge=0;
useLock=false;
dataSource=null;
dataSourceJNDI=null;
suspectTimeout=0;
alternateUsernameAllowed=false;
commitOnReturn=false;
rollbackOnReturn=false;
useDisposableConnectionFacade=true;
logValidationErrors=false;
propagateInterruptState=false;
ignoreExceptionOnPreLoad=false;
}
(newlines mine)
The setup of that bean seems rather intricate, so I want to interfere with it as little as possible - just replace the default JDBC URL.
How can I configure individual properties for Spring to create the datasource? Preferably in Java, but if there is a concise XML way I'm happy as well. I just want to avoid adding 100 lines of boilerplate for something equivalent to url=...
A DataSource is auto configured by Spring Boot for you. To influence how and what there are several properties you can set. Those are prefixed with spring.datasource, for a list take a look at the Spring Boot Reference Guide for a full list.
In your case simply add the following to the application.properties file
spring.datasource.url=jdbc:h2:file:...
This will tell Spring Boot to use this URL instead of the default.
As H2 is considered an in-memory database and not a regular database, when using JPA this will lead to your database to be dropped when the application is stopped. To fix this simply add the following
spring.jpa.hibernate.ddl-auto=update
To specify a dialect simply add the following
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
or even simpler
spring.jpa.database=H2

Spring Boot default properties encoding change?

I am trying to find a way to set UTF-8 encoding for properties accessed via #Value annotation from application.property files in Spring boot. So far I have been successfully set encoding to my own properties sources by creating a bean:
#Bean
#Primary
public PropertySourcesPlaceholderConfigurer placeholderConfigurer(){
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocation(new ClassPathResource("app.properties");
configurer.setFileEncoding("UTF-8");
return configurer;
}
Such solution presents two problems. For once, it does NOT work with "application.properties" locations used by default by Spring Boot (http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config), and I am forced to use different file names.
And the other problem is, with it I am left with manually defining and ordering supported locations for multiple sources (eg. in jar vs outside jar properties file, etc) thus redoing a job well done already.
How would I obtain a reference to already configured PropertySourcesPlaceholderConfigurer and change it's file encoding at just the right time of application initialization?
Edit:
Perhaps I am doing a mistake somewhere else? This is what causes actual problem for me: When I use application.properties to allow users to apply personal name to emails sent from an application:
#Value("${mail.mailerAddress}")
private String mailerAddress;
#Value("${mail.mailerName}")
private String mailerName; // Actual property is Święty Mikołaj
private InternetAddress getSender(){
InternetAddress sender = new InternetAddress();
sender.setAddress(mailerAddress);
try {
sender.setPersonal(mailerName, "UTF-8"); // Result is Święty Mikołaj
// OR: sender.setPersonal(mailerName); // Result is ??wiÄ?ty Miko??aj
} catch (UnsupportedEncodingException e) {
logger.error("Unsupported encoding used in sender name", e);
}
return sender;
}
When I have placeholderConfigurer bean as shown above added, and place my property inside 'app.properties' it is resoved just fine. Just renaming the file to 'application.properties' breaks it.
Apparently properties loaded by Spring Boot's ConfigFileApplicationListener are encoded in ISO 8859-1 character encoding, which is by design and according to format specification.
On the other hand, the .yaml format supports UTF-8 out of the box. A simple extension change fixes the problem for me.
#JockX suggestion works perfectly. Also, the conversion from property to yaml is quite straightforward.
This:
spring.main.web_environment=false
email.subject.text=Here goes your subject
email.from.name=From Me
email.from.address=me#here.com
email.replyTo.name=To Him
email.replyTo.address=to#him.com
Would become:
spring:
main:
web_environment: false
email:
subject:
text: Here goes your subject
from:
name: From Me
address: me#here.com
replyTo:
name: To Him
address: to#him.com
Another approach would be Instead of renaming the complete file from .properties to .yml you can pick the props which need UTF-8 support and move them to .yml file. This way you need not rewrite ur .properties file.
I advice this because if you have props like
my.string.format= %s-hello-%s
This breaks in .yml files. You would have to write them as
my.string.format: |
%s-hello-%s
Which then leads to adding a new line in the property valye my.string.format when read in the Java code.

Properties framework in java apps

I have been using spring for a while as my IOC. It has also a very nice way of injecting properties in your beans.
Now I am participating in a new project where the IOC is Guice. I dont understand fully the concept how should I inject properties in to my beans using Guice.
The question : Is it actually possible to inject raw properties ( strings , ints ) into my guice beans. If the answer is no , than maybe you know some nice Properties Framework for java.
Because right now I wanted to use the ResourceBundle class for simple properties management in my app. But after using spring for a while this just dont seem seriously enought for me.
this SO post discusses the use of various configuration frameworks, also the use of properties. I'm not sure it's to the point exactly for your needs, but perhaps you can find something of value there.
Spring provides for injection of configuration information found in XML files. I don't want the people installing my software to have to edit XML files, so for the kind of configuration information more properly in a plain text file (such as path information), I've gone back to using java.util.Properties since it's easy to use and fits into Spring pretty well, if you use a ClassPathResource, which permits path-free location of the file itself (it just has to be in the classpath; I put mine at the root of WEB-INF/classes.
Here's a quick method that returns a populated Properties object:
/**
* Load the Properties based on the property file specified
* by <tt>filename</tt>, which must exist on the classpath
* (e.g., "myapp-config.properties").
*/
public Properties loadPropertiesFromClassPath( String filename )
throws IOException
{
Properties properties = new Properties();
if ( filename != null ) {
Resource rsrc = new ClassPathResource(filename);
log.info("loading properties from filename " + rsrc.getFilename() );
InputStream in = rsrc.getInputStream();
log.info( properties.size() + " properties prior to load" );
properties.load(in);
log.info( properties.size() + " properties after load" );
}
return properties;
}
The file itself uses the normal "name=value" plaintext format, but if you want to use Properties' XML format just change properties.load(InputStream) to properties.loadFromXML(InputStream).
Hope that's of some help.
Injecting properties in Guice is easy. After reading in some properties from a file or however, you bind them using Names.bindProperties(Binder,Properties). You can then inject them using, for example, #Named("some.port") int port.

Categories