Reputation: 189
I'm not using spring-boot in this app. I'm testing profiles to use different datasource in integration tests.
I have entity User as follow:
@Table(name = "user_inf")
@Entity
@NamedQuery(name="User.findById", query="select u from User u where u.id=:id")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "userName", length = 25)
private String userName;
@Column(name = "userEmail", unique = true, length = 320)
private String userEmail;
}
for that entity I have the service and dao(Service only invokes dao method)
UserDao :
@Repository
@Transactional
public class UserDaoImpl implements UserDao {
@PersistenceContext
private EntityManager entityManager;
@Override
public User findById(Long id) {
TypedQuery<User> query = entityManager.createNamedQuery("User.findById", User.class);
query.setParameter("id", id);
return query.getSingleResult();
}
}
User service :
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Override
public User getUser(Long id) {
return userDao.findById(id);
}
}
@Configuration
@PropertySource(value = {"classpath:database/jdbc.properties"})
@EnableTransactionManagement
@ComponentScan({"com.example.test.repository", "com.example.test.service"})
public class SpringConfig {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
private static final String PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE = "hibernate.jdbc.fetch_size";
private static final String PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE = "hibernate.jdbc.batch_size";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String ENTITY_MANAGER_PACKAGES_TO_SCAN = "com.example.test.entity";
@Autowired
private Environment env;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
@Bean
@Profile("test")
public DataSource dataSourceForTest() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.test.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
@Bean
public PlatformTransactionManager jpaTransactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject());
return transactionManager;
}
private HibernateJpaVendorAdapter vendorAdaptor() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource mainDataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdaptor());
entityManagerFactoryBean.setDataSource(mainDataSource);
entityManagerFactoryBean.setPackagesToScan(ENTITY_MANAGER_PACKAGES_TO_SCAN);
entityManagerFactoryBean.setJpaProperties(jpaHibernateProperties());
return entityManagerFactoryBean;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private Properties jpaHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH, env.getProperty(PROPERTY_NAME_HIBERNATE_MAX_FETCH_DEPTH));
properties.put(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_FETCH_SIZE));
properties.put(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE, env.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put("hibernate.hbm2ddl.auto", "none");
return properties;
}
}
Property file which is used for datasource and hibernate (jdbc.properties) contains following :
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdatabase
jdbc.username=Bruce
jdbc.password=givanchy
jdbc.test.url=jdbc:mysql://localhost:3306/testdatabase1
hibernate.max_fetch_depth = 3
hibernate.jdbc.fetch_size = 50
hibernate.jdbc.batch_size = 10
hibernate.show_sql = true
hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
Entry point for application :
public class EntryClass {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);
User user =userService.getUser(1L);
System.out.println("userName is "+user.getUserName());
}
}
It works as it should. But in test source I have only one test for service to understand how profiles work
@SpringJUnitConfig(SpringConfig.class)
@ActiveProfiles("test")
class UserServiceImplTest {
@Autowired
private UserService userService;
@Test
void getUser() {
User user = userService.getUser(5L);
Assertions.assertEquals("Vector", user.getUserName());
}
}
And I get "No qualifying bean" exception because there are two beans of datasource type, but I set which profile it should use?Can you explain why It doesn't work?
Upvotes: 0
Views: 782
Reputation: 3423
When you launch it normally, the datasource bean with 'test' profile is not created. (becasue there is no test profile set.)
When you run it as a test, then both datasource beans are created. The default is created because there is no any condition on it, and the other is becasue its annotated with the test profile.
Simply add @Profile("!test")
to the default bean. This way it will be created only if the test profile is NOT active.
Upvotes: 0