@EnableJpaRepositories annotation disables data.sql initialization script

My Spring Boot (v2.3.4) based application uses my custom library containing core entities and business logic. To use entities and repositories from this library I had to use @EnableJpaRepositories and @EntityScan annotations with proper packages provided.

I also wanted to initialize database with some required data (let's say the configuration) during application startup. I found that Spring Boot allows to use data.sql or data-${platform}.sql files to achieve that.

Long story short when using @EnableJpaRepositories annotation the data.sql script is not executed.

I did some digging in the code and found that when @EnableJpaRepositories annotation is not used then entityManagerFactory bean is of org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean type. This bean uses org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher bean post processor, which fires org.springframework.boot.autoconfigure.jdbc.DataSourceSchemaCreatedEvent event indicating the schema has been created. Class, which listens for this event is org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker. This listener invokes initSchema() method from org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer class. This method is responsible for whole initialization using data.sql script.

It looks like setting @EnableJpaRepositories annotation creates instance of different class for entityManagerFactory bean, which does not support this simple initialization.

My basic question is then how to make it all work with @EnableJpaRepositories annotation. I can always use Hibernate's import.sql file (which works fine) but I'm also trying to understand what exactly is going on under the hood I how can I control it.

UPDATE 1 28.09.2021

I did further investigation and @EnableJpaRepositories annotation does not change the instance type of entityManagerFactory but it causes silent exception (?) when creating org.springframework.scheduling.annotation.ProxyAsyncConfiguration bean (during creation of org.springframework.context.annotation.internalAsyncAnnotationProcessor bean). It looks like everything is related to @EnableAsync annotation, which I'm also using but didn't know it might be related. But it is - removing it makes the initialization work even with @EnableJpaRepositories.

UPDATE 2 28.09.2021

I've found full explanation for my issue. There are 4 conditions, which must be met to reproduce the issue:

  • @EnableJpaRepositories annotation in application configuration
  • @EnableAsync annotation in application configuration
  • Configuration implements AsyncConfigurer interface
  • Autowired any JpaRepository repository or any other bean which injects repository

Enabling asynchronous execution and implementing AsyncConfigurer makes the whole configuration to be instantiated before regular beans. Because Spring has to inject repository, it needs to instantiate entityManagerFactory bean too. Spring prints thenINFO level logs like below:

Bean 'entityManagerFactoryBuilder' of type [org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

One of not eligible BeanPostProcessors is DataSourceInitializedPublisher responsible for firing DataSourceSchemaCreatedEvent event. Without that event, data-${platform}.sql script won't be processed at all.

I'm not sure what is the role of @EnableJpaRepositories in that process but without it the problem does not occur.

Example

Minimal code to reproduce the issue (data.sql located in src/main/resources):

@Entity
public FileStore {
    ...
}

public interface FileStoreRepository extends extends JpaRepository<FileStore, Long> {
}

@Configuration
@EnableAsync
@EnableJpaRepositories
public class Configuration implements AsyncConfigurer {
    @Autowired
    private FileStoreRepository fileStoreRepository;

    ...
}

Solutions

There are two solutions I'm aware of:

  • Move AsyncConfigurer along with its overrided methods and @EnableAsync annotation to separate configuration class
  • Use @Lazy annotation on autowired bean like below:
@Lazy
@Autowired
private FileStoreRepository fileStoreRepository;

Similar problem was pointed by @Allen D. Ball and can be checked there.



from Recent Questions - Stack Overflow https://ift.tt/3AQZavO
https://ift.tt/eA8V8J

Comments

Popular posts from this blog

Today Walkin 14th-Sept

Spring Elasticsearch Operations

Hibernate Search - Elasticsearch with JSON manipulation