0

this is kind of a duplicate question (Database initialisation before bean creation) but the given answer is somehow not working for me.

For testing purposes I am using a h2-db and therefore I am also looking for a way that (h2)-database scripts are being executed before bean-initialisation, so I have the data ready for integration-tests

In theory the DependsOn behaviour is what I am looking for but for some reason its not working.

Under src/test/resources i have two sql scripts (data.sql and import.sql script)

application.yaml looks the following:

spring:
 config:
  activate:
   on-profile: test
 datasource:
  driver-class-name: org.h2.Driver
  url: jdbc:h2:mem:undgesund;DB_CLOSE_DELAY=-1
 jpa:
  hibernate:
   ddl-auto: none
   naming:
     physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
 generate-ddl: false
 sql:
 init:
   mode: always

I have a bean declared in a @Configuration class

@Configuration
public class ConfigClass { 

 @Bean
 @DependsOn("dataSource")
 public Map<Integer, SomeEntity> entityMap() {
    log.info("loading values into memory...");
    final List<SomeEntity> someEntities = this.dao.getAllEntities();
    for(SomeEntity someEntity: someEntities) {
        this.someEntityMap.put(someEntity.id(), someEntity);
  }
 }
}

DaoClass is basic and looks like that:

@Service
public class Dao {

  @Autowired
  private SomeEntityRepository someEntityRepository //basic JpaRepository
  public List<SomeEntity> getAllEntities {
    return entityRepository.findAll();
}

And I have an test-class

@ActiveProfiles("test")
@ExtendsWith(SpringExtension.class)
@DataJpaTest()
@Import({ConfigClass.class})
class SomeTestClass {

  @Autowired
  private SomeEntityRepository someEntityRepository

  @Test
  public void repoTest() {
    assertTrue(someEntityRepository.findAll() > 0)
  }

What happens now is, that when I am executing the test and the @Bean entityMap gets initialised, the repo is returning no data. But when the test gets executed the repo returns some data and the tests succeeds.

How is it possible that the sql-scripts are getting executed so that data is in the h2-db and when @Bean entityMap is being created, data is actually getting returned?

podoi17
  • 39
  • 9
  • Initialization of the datasource (execution the `schema.sql` and `data.sql`) happens after the `DataSource` is created, else there is no way to execute those scripts. When the `entityMap` is created there is no guaranty that those scripts have run. – M. Deinum Aug 22 '22 at 11:44
  • so it means that its not possible to have the data ready when the Beans are getting created? – podoi17 Aug 22 '22 at 12:00
  • 1
    I didn't say that, I said there is no guaranty that it is executed. If you want to build a cache you should use a listener which executes after the context has fully started. – M. Deinum Aug 22 '22 at 12:03
  • so I tried to do something like `@EventListener(classes = {{Various SpringContextEvents}}@Bean public Map entityMap()` Unfortunately did not work.... Weird that this is so hard to accomplish – podoi17 Aug 24 '22 at 09:22
  • That will, imho obviously, not work. You cannot put an `@EventListener` on an `@Bean` method (well you could but it will not work as intended). You need to place this on a regular method that will fill the cache. Not on a methdo that returns the cache as a bean. – M. Deinum Aug 24 '22 at 10:01

1 Answers1

0

Didn't tried that but you can try to use H2's INIT feature

so you could have something like this (I'm not sure if it reads from java classpath or not):

spring:
 datasource:
  driver-class-name: org.h2.Driver
  url: jdbc:h2:mem:undgesund;DB_CLOSE_DELAY=-1;INIT=runscript from 'schema.sql';runscript from 'data.sql'

EDIT: seems like if you prefix the files with classpath: it should work.

url: jdbc:h2:mem:undgesund;DB_CLOSE_DELAY=-1;INIT=runscript from 'classpath:schema.sql';runscript from 'classpath:data.sql'
bilak
  • 4,526
  • 3
  • 35
  • 75