简体   繁体   中英

Spring Boot Data JPA issues with DB/2 Configuration and JUnit

I am working on a project which wants to use spring-boot-data-jpa. The local (IDE) database can be H2. However, for all servers (dev/test/prod), we are forced to use DB/2 (unfortunately!).

We can't seem to get it things working with DB/2. We get an error like this:

java.lang.IllegalStateException: Failed to load ApplicationContext....
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No   
qualifying bean of type [...Repository] found for
dependency: expected at least 1 bean which qualifies as autowire candidate for this 
dependency. Dependency annotations: {}

when running the unit tests (JUnit). Note, the blank {} annotation. Which on the face of it seems like an "obvious" issue. The repository bean can not be loaded or found on the classpath. However, when we run this with H2 configuration, it works just fine.

So, the next logical conclusion seems to be the repositories configuration (data source, etc.) is not set up correctly. However, we can use the same configuration values in a non spring boot application and it works fine!

So then I was thinking it could be something with the either the differing classloaders or cglib proxies not using the "real" implementation class. SO questions like these:

However, the correct answers for those questions do not resolve the issue. So here is my post/question.

How do figure out the root cause of this issue? I have tried to walk through the code (spring and our code) in the debugger but can't narrow down a cause.

So then I tried this, I took the sample spring boot jpa and modified it to use specific properties for DB/2 and I can get the same failure. So it seems like my configuration must be wrong or there is a bug in the spring code. I have looked at the configuration with someone else and we don't see the problem. We tried this configuration in another (non-spring boot app) and it works.

Here is a patch file that shows the differences between the original jpa sample and the modified one with the configuration changes. Note, we removed the DB2 server details. Hopefully, this makes the issue reproducible for anyone and then can assist in figuring out the cause.

TIA,

Scott

edit 1 --- add configuration details here directly instead of a patch file ---

Java Configuration

@Configuration
@ComponentScan
@EnableAutoConfiguration
@PropertySource("classpath:application.properties")
public class SampleDataJpaApplication {

     public static void main(String[] args) throws Exception {
     SpringApplication.run(SampleDataJpaApplication.class, args);
     }
 }

Properties File

spring.jpa.hibernate.naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.hibernate.dialect: org.hibernate.dialect.DB2Dialect
#spring.jpa.database-platform: DB2Platform
spring.jpa.show-sql: true
spring.jpa.generate-ddl: true

spring.datasource.driverClassName: om.ibm.db2.jcc.DB2Driver
spring.datasource.url: jdbc:db2:someDB2-db:5000
spring.datasource.username: fakeuser
spring.datasource.password: fakepassword
spring.datasource.schema:schema-name

Unit Test Configuration

@RunWith(SpringJUnit4ClassRunner.class)
@PropertySource("classpath:application.properties")
@ContextConfiguration(classes = SampleDataJpaApplication.class, loader =       AnnotationConfigContextLoader.class)
public class CityRepositoryIntegrationTests {
 //....
}     

This should be nearly identical to the patch file just changing the user/password/jdbc URL to hide the specifics of the environment.

As far as I can see, the JUnit setup is not correct. To let Boot work correctly you have two choices:

  1. Use @SpringApplicationConfiguration instead of @ContextConfiguration

    Boot configures the ApplicationContext bootstrap process quite a bit, eg to enable the default configuration files being picked up. Using the custom annotation will automatically activate that stuff for the JUnit executions as well.

  2. Configure @ContextConfiguration with the appropriate listeners yourself

    In your case you at least need the ConfigFileApplicationContextInitializer in addition to all the default ones registered.

As the second option is rather cumbersome, I highly recommend to go with option one and see where that leads you.

Oliver,

I can't seem to find the annotation @SpringApplicationConfiguration using the spring-boot-starter-test JAR as defined in the how-to. I'm using spring boot 0.5.0.M6. Below are the dependencies in my Maven POM. Anything I'm missing here?

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>

EDIT : After looking through the Spring Boot sample projects I found a different approach to getting Junit and Spring test to play nicely with each other. If you can define your class like the following things should work identical to what Oliver has mentioned in his reply for option 1. Notice the "loader" argument needs to be present to correctly configure listeners and backing beans correctly.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyDataApplication.class, loader = SpringApplicationContextLoader.class)
public class MyServiceTest {

I have similar problem with integration tests in Spring Boot and I can confirm @user3166395 solution.

This configuration works for me:

import org.springframework.boot.test.SpringApplicationContextLoader;
import org.springframework.test.context.ContextConfiguration;
...

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyDataApplication.class, loader = SpringApplicationContextLoader.class)
public class MyServiceTest {

   @Autowired
   CityRepository cityRepository;

}

This requires test dependency to:

org.springframework.boot:spring-boot-starter-test:0.5.0.M7

I cant achieve working test with SpringApplicationConfiguration

Hey guys a little late to the party but to be clear about your error (since I copied it, I had the same):

spring.datasource.driverClassName: **om**.ibm.db2.jcc.DB2Driver

should be

spring.datasource.driverClassName: **com**.ibm.db2.jcc.DB2Driver

This worked for me so far.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM