SpringBoot Load profile properties from classpath - spring-boot

My Question:
It is possible to load an configuration application-persist.yml from the classpath during startup?
The application-persist.yml is part of my external lib and contains the spring.datasource configuration
myexternallib.jar
- config
- application-persist-dev.yml
spring:
datasource:
jdbc-url: url-to-dev-database
username: xxx
password: xxx
driver-class-name: org.postgresql.Driver
- application-persist-prod.yml
spring:
datasource:
jdbc-url: url-to-prod-database
username: xxx
password: xxx
driver-class-name: org.postgresql.Driver
In my spring boot project the myexternallib.jar is included as a dependency
and I want to load the configuration from classpath:
The application.yml of my project:
spring:
profiles:
include: persist
active: dev, persist-dev
The Problem is: When i start my application, the Startup failed with an exception:
Caused by: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
because the application-persist-dev.yml is not read correctly during startup.
How can i fix it?

Spring Boot's reference documentation is very clear at this point:
java -jar myproject.jar --spring.config.location=classpath:/application-persist.yml

Related

quarkus - switching from "default" to "PersistenceUnit" causes "Unsatisfied dependency"

Quarkus 2.7.4
I had my app working with default datasource config. When I tried to switch to using persistence units it stopped working. I've got to the point where I get this error...
[ERROR] [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.persistence.EntityManager and qualifiers [#PersistenceUnit(value = "ds")]
[ERROR] - java member: uk.co.me.filter.CheckFilter#entityManager
[ERROR] - declared on CLASS bean [types=[uk.co.me.filter.CheckFilter, javax.ws.rs.container.ContainerRequestFilter, java.lang.Object], qualifiers=[#Default, #Any], target=uk.co.me.filter.CheckFilter]
[ERROR] The following beans match by type, but none have matching qualifiers:
[ERROR] - Bean [class=org.hibernate.Session, qualifiers=[#javax.enterprise.inject.Default, #Any]]
What am I missing?.
I had my default config working...
quarkus:
datasource:
db-kind: mssql
username: user
password: pwd
jdbc:
url: jdbc:sqlserver://localhost:1433
Then I tried to convert it to a persistent unit...
quarkus:
datasource:
ds:
db-kind: mssql
username: user
password: pwd
jdbc:
url: jdbc:sqlserver://localhost:1433
hibernate-orm:
datasource: ds
packages: uk.co.me.filter
And I added the annotation to my class
#Inject #PersistenceUnit("ds") EntityManager entityManager;
First it complained about couldn't find default models so I added the original config back in. That resolved the error (I realise not the best, but hey, just trying to get things moving). Now I get the above error when trying to build the quarkus-run.jar
On the configuration snippet you add, you only configure a ds named datasource but not a ds named persistence unit so only the default one exist.
You need to configure Hibernate ORM or multiple persistence unit as explained here: https://quarkus.io/guides/hibernate-orm#multiple-persistence-units
In your case something like this:
quarkus:
datasource:
ds:
db-kind: mssql
username: user
password: pwd
jdbc:
url: jdbc:sqlserver://localhost:1433
hibernate-orm:
ds:
datasource: ds
packages: uk.co.me.filter

Spring-Boot Test loading application.propertites wrong - 2.4.2

I was using Spring-Boot 2.2.4.RELEASE version and I decided to upgrade to 2.4.2 version since is not a released version. My problem started because I have two configuration file, one that I use configserver and another that I have a in memory database configured to class test.
src/main/resources/application.properties:
...
spring.profiles.active=#activatedProperties#
spring.config.import=optional:configserver:#url#
src/test/resources/application.yml:
spring:
jpa:
database-platform: org.hibernate.dialect.H2Dialect
show-sql: true
properties:
hibernate.format_sql: true
....
datasource:
driver-class-name: org.h2.Driver
platform: h2
name: CUP_ORCHESTRATOR
url: jdbc:h2:mem:CUP_ORCHESTRATOR;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS CUP_ORCHESTRATOR
initializaion-mode: embedded
username: sa
password:
Before the update when I ran the Spring-Boot test class, it always took the correct configuration file, but now it is getting src/main/resources/application.properties for test:
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.closeupinternational.cpoprocesscontrol.test.WorkflowServiceTest
18:39:28.943 [main] ERROR o.s.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Unable to load config data from 'optional:configserver:http://localhost:8888'
WorkflowServiceTest:
#SpringBootTest(properties = "spring.cloud.config.enabled=false")
#TestPropertySource("classpath:application.yml")
#Slf4j
public class WorkflowServiceTest {
#MockBean
private SenderConfig senderConfig;
What changed from one version to another that broke my project?
Change application.yml to application.properties as the TestPropertySource annotation only works for .properties files.

Spring TransactionManagement with Atomikos

I am trying to boot up a spring application with Atomikos maven dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
Am also autowiring as following
#Autowired
JtaTransactionManager jtaTransactionManager;
application.yaml file is as follows
spring:
mvc:
throw-exception-if-no-handler-found: true
resources:
add-mappings: false
jta:
atomikos:
connectionfactory:
ignore-session-transacted-flag: false
unique-resource-name: xa.amq
min-pool-size: 10
max-pool-size: 20
datasource:
unique-resource-name: xa.db
min-pool-size: 10
max-pool-size: 20
test-query: "select 1"
properties:
default-jta-timeout: 50000
datasource:
url: jdbc:mysql://mydatabasehost:3306/test
driverClassName: com.mysql.jdbc.Driver
username: test
password: test
initialization-mode: always
It starts fine with above yaml configurations.
However, for my use case, I want my transaction manager to skip using the default spring datasource and instead I want to dynamically register datasource beans after the start up. I wanted to know if that is possible. If I remove my datasource settings from above yaml file, I get following error
15:15:19.322 [main] WARN com.atomikos.jdbc.AtomikosXAConnectionFactory - XAConnectionFactory: failed to create pooled connection - DBMS down or unreachable?
java.sql.SQLException: Database not available
at org.apache.derby.jdbc.BasicEmbeddedDataSource40.setupResourceAdapter(Unknown Source)
at org.apache.derby.jdbc.EmbeddedXADataSource.getXAConnection(Unknown Source)
at com.atomikos.jdbc.AtomikosXAConnectionFactory.createPooledConnection(AtomikosXAConnectionFactory.java:28)
at com.atomikos.datasource.pool.ConnectionPool.createPooledConnection(ConnectionPool.java:98)
at com.atomikos.datasource.pool.ConnectionPool.addConnectionsIfMinPoolSizeNotReached(ConnectionPool.java:86)
at com.atomikos.datasource.pool.ConnectionPool.init(ConnectionPool.java:60)
at com.atomikos.datasource.pool.ConnectionPool.<init>(ConnectionPool.java:49)
at com.atomikos.datasource.pool.ConnectionPoolWithConcurrentValidation.<init>(ConnectionPoolWithConcurrentValidation.java:23)
at com.atomikos.jdbc.AbstractDataSourceBean.init(AbstractDataSourceBean.java:294)
at org.springframework.boot.jta.atomikos.AtomikosDataSourceBean.afterPropertiesSet(AtomikosDataSourceBean.java:49)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:307)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1251)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760)
This is not an Atomikos limitation because it allows dynamic addition of datasources.
It looks like Spring Boot's convention-over-configuration trying to create a default datasource if you have none. I am not a Spring Boot expert so I am not sure if this can be suppressed. However, there is probably no harm in using a dummy default datasource in your configuration if that help.
Best regards

ehcache giving error after migrating spring boot from 1.5.12 to 1.5.13

I have configured spring boot 1.5.12 + ehcache and everything was working fine until I upgraded spring boot to 1.5.13
application.yml has the below entry
spring:
cache:
jcache:
provider: org.ehcache.jsr107.EhcacheCachingProvider
config: ehcache.xml
my ehcache.xml is located under resources directory
The error I am receiving is:
Caused by: java.lang.IllegalArgumentException: Cache configuration does not exist 'ServletContext resource [/ehcache.xml]'
at org.springframework.util.Assert.isTrue(Assert.java:92)
at org.springframework.boot.autoconfigure.cache.CacheProperties.resolveConfigLocation(CacheProperties.java:117)
at org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration.createCacheManager(JCacheCacheConfiguration.java:113)
at org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration.jCacheCacheManager(JCacheCacheConfiguration.java:97)
at org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration$$EnhancerBySpringCGLIB$$e5c3a047.CGLIB$jCacheCacheManager$1(<generated>)
at org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration$$EnhancerBySpringCGLIB$$e5c3a047$$FastClassBySpringCGLIB$$a6ae7187.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358)
at org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration$$EnhancerBySpringCGLIB$$e5c3a047.jCacheCacheManager(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 47 common frames omitted
It looks like spring boot has started searching for ehcache.xml using servletContext resolver.
p.s. I had made no change in any of source code except the spring boot upgrade to 1.5.13
Am I missing some required configuration here?
I had figured out the fix for this problem. We need to specify the prefix classpath: with the file name to make it work.
My application.yml would look like this now
spring:
cache:
jcache:
provider: org.ehcache.jsr107.EhcacheCachingProvider
config: classpath:ehcache.xml
Hope that helps.

Configure specific in memory database for testing purpose in Spring

How do I configure my Spring Boot application so that when I run unit tests it will use in-memory database such as H2/HSQL but when I run Spring Boot application it will use production database [Postgre/MySQL] ?
Spring profiles can be used for this. This would be a specific way:
Have environment specific properties files:
application.properties:
spring.profiles.active: dev
application-dev.properties
spring.jpa.database: MYSQL
spring.jpa.hibernate.ddl-auto: update
spring.datasource.url: jdbc:mysql://localhost:3306/dbname
spring.datasource.username: username
spring.datasource.password: password
application-test.properties
spring.jpa.database: HSQL
Have both MySQL and H2 drivers in pom.xml, like this:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
Last but not the least, annotate Test classes with #ActiveProfiles("test").
Another approach is to add the annotation #AutoConfigureTestDatabase to you test class.
My tests usually look like this:
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
public class MyRepositoryTest {
#Autowired
MyRepository repository;
#Test
public void test() throws Exception {
// Tests...
}
}
Note that the embedded database dependency needs to be added in the pom.xml file.
For embedded database this annotation is not necessary it will work even if only the dependency is added in pom file.
With #SpringBootTest magic, you just need to do following two changes.
Add 'h2' test dependency in pom.xml
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
Use #AutoConfigureTestDatabase
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MySpringBootApplication.class)
#AutoConfigureTestDatabase
public class SpringBootTest{
#Autowired
private RequestRepository requestRepository;
}
Now all the spring jpa bean/repositories used in test will use h2 as backing database.
2019-04-26 13:13:34.198 INFO 28627 --- [ main]
beddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource'
DataSource bean with embedded version
2019-04-26 13:13:34.199 INFO 28627 --- [ main]
o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition
for bean 'dataSource'
2019-04-26 13:13:36.194 INFO 28627 --- [ main]
o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database:
url='jdbc:h2:mem:2784768e-f053-4bb3-ab88-edda34956893;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false',
username='sa'
Note: I still have 'spring-jpa' properties defined in 'application.properties' and I don't use any profiles. #AutoConfigureTestDatabase will override existing jpa configurations with test defaults AutoConfigureTestDatabase.Replace.
Simplest solution:
1) in src/main/resources have application.properties (production config):
spring.datasource.url=jdbc:mysql://localhost:3306/somedb
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect
and application-test.properties with HSQL config like:
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.database = HSQL
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.HSQLDialect
spring.datasource.driverClassName = org.hsqldb.jdbcDriver
spring.datasource.url= jdbc:hsqldb:mem:scratchdb
spring.datasource.username = sa
spring.datasource.password =
2) Add HSQL dependency in pom.xml if you don't have it already.
3) Annotate your test class with #ActiveProfiles("test").
Worked like charm in my case.
#Sanjay has one way to put it but I find it confusing. You could just as well have only a production profile that you enable when you're in production, something like:
spring.jpa.hibernate.ddl-auto: update
spring.datasource.url: jdbc:mysql://localhost:3306/dbname
spring.datasource.username: username
spring.datasource.password: password
And don't specify anything else. If you add an embedded database in test scope, it will be available in your tests. If you run your tests with the default profile (no customization whatsoever), it won't find any database information (since these are stored in the production profile). In that case, it will try to find an embedded database and start it for you. If you need more customization for some reason, you can have a application-test.properties for those (you'll need to add ActiveProfiles("test") to your test(s).
Simple solution if building with maven: just place an application.properties file under src/test/resources and edit as appropriate for testing.
The Spring (Boot) Profile mechanism is a pretty powerful tool that, in scope, goes way beyond "swapping settings between test time and run time". Although, clearly, as demonstrated, it can do that also :)
This solution enables common settings for develop and test. Is based on this solution:
Override default Spring-Boot application.properties settings in Junit Test
application.properties in src/main/resources/application.properties
#common settings for DEVELOPMENT and TEST:
......
......
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:postgresql://localhost:5432/databasename
spring.datasource.username=postgres
spring.datasource.password=somepassword
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = none
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
test.properties (src/main/resources/application.properties) which overrides and adds properties in application.properties:
spring.datasource.url=jdbc:h2:mem:testdb;MODE=PostgreSQL
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=false
settings in pom.xml for H2 and Postgre databases
<!-- h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- postgress -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
In test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#TestPropertySource(locations = "classpath:test.properties")
public class ModelTest {
}
I have a multi-module Gradle SpringBootApplication with below Modules
employeemanagerApp - Where my SpringApplication main class
employeemanagerIntTests - Where i have my cucumber tests
My requirement was to use MySQL DB when the application boots up and H2 during my Cucumber Integration testing
Solution: In my employeemanagerApp module, src/main/resources i placed the application.properties with below content
#My SQL Configuration
spring.datasource.url=jdbc:mysql://localhost:3306/employeemanager
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
And in the Integration Test Module (employeemanagerIntTests) src/test/resources I placed the application.properties with below content
#H2 In-Memory DB Configuration
spring.datasource.url=jdbc:h2://mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.format_sql=true
And in my Step Definition Class i added only these annotations
#CucumberContextConfiguration
#SpringBootTest(classes = SpringBootApplicationMainClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
In the build.gradle file i added H2 dependency
testImplementation 'com.h2database:h2:1.4.200'
So when I ran my tests, H2 was active and all tests with Create, Update, Read and Delete were successful

Resources