I'm using spring-jpa. I have 2 tests.
#Test
#Transactional
public void testFindAll() {
List<Engine> eList = engineService.findAll();
Engine e = eList.get(0); //this engine id=3
List<Translation> tList = e.getTranslations();
for(Translation t : tList) {
...
}
}
This method fails with this exception:
org.hibernate.LazyInitializationException: failed to lazily initialize
a collection of role: xxx.Engine.translations, could not initialize
proxy - no Session
However, this method works just fine:
#Test
#Transactional
public void testFindOne() {
Engine e = engineService.findOne(3);
List<Translation> tList = e.getTranslations();
for(Translation t : tList) {
...
}
}
Why translation list is successfully loaded in one case, but not in another?
EDIT: service/repo code:
public interface EngineRepository extends JpaRepository<Engine, Integer>
{
}
.
#Service
#Transactional
public class EngineService
{
#Autowired
private EngineRepository engineRepository;
public List<Engine> findAll()
{
return engineRepository.findAll();
}
public Engine findOne(Integer engId)
{
return engineRepository.findOne(engId);
}
}
.
public class Engine implements Serializable {
...
#OneToMany
#JoinColumn(name="ID", referencedColumnName="TRAN_ID", insertable=false, updatable=false, nullable=true)
#LazyCollection(LazyCollectionOption.EXTRA)
private List<Translation> translations;
...
}
Config:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"xxx.dao"})
#ComponentScan(basePackages = {"xxx.dao", "xxx.service", "xxx.bean"})
#PropertySource("classpath:application.properties")
public class SpringDataConfig {
#Autowired
private Environment environment;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(environment.getProperty("db.url"));
dataSource.setDriverClassName(environment.getProperty("db.driverClass"));
dataSource.setUsername(environment.getProperty("db.username"));
dataSource.setPassword(environment.getProperty("db.password"));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getProperty("hibernate.showSQL"));
properties.put("hibernate.format_sql", environment.getProperty("hibernate.formatSQL"));
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan("xxx.model");
entityManagerFactoryBean.setJpaVendorAdapter(hibernateJpaVendorAdapter);
entityManagerFactoryBean.setJpaProperties(properties);
return entityManagerFactoryBean;
}
#Bean
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
I think the problem here is that the session gets closed after the first line in the first case. You should check out the JpaRepository implementation of findAll().
Integration Testing with Spring
It seems you're failing to provide a Spring Context within your TestCase, what that means? The #Transactional is being ignored. Therefore you end up with the closed session exception, because there is no transaction.
Take a look how to configure a TestCase with a Spring Context here
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from AppConfig and TestConfig
#ContextConfiguration(classes = {AppConfig.class, TestConfig.class})
public class MyTest {
#Autowired
EngineService engineService;
#Test
#Transactional
public void testFindOne() {}
#Test
#Transactional
public void testFindAll() {}
}
Related
I having a configuration problem that cause the error below. I know there are a tons of similar problem but I read a lot of answer that stackoverflow suggest with my title but I don't find the right answer yet.
Description:
Field collaborateurJpaRepository in com...infrastructure.persistence.user.UserRepositoryImpl required a bean of type 'com...infrastructure.persistence.jurisdiction.CollaborateurJpaRepository' that could not be found.
Action:
Consider defining a bean of type 'com...infrastructure.persistence.jurisdiction.CollaborateurJpaRepository' in your configuration.
Before to give some details of the code, I think it could be nice that I describe you brievly the context.
I work on a client project which has 8 maven modules (DDD methods) because at the end of the year 4 modules will be separate in an other server.
Recently we create a second oracle database so I had to create multiple configuration to refer to the good dataSource.
I think the problem is due to bad datasource configuration that block the bean spring instanciation.
We are using spring boot version 1.5.7.release.
First Infrastructure configuration
#Configuration
#ComponentScan(basePackages = "com...jade")
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "jadeEntityManager", transactionManagerRef = "jadeTransactionManager")
#EntityScan(basePackages = { "com...jade", "org.springframework.data.jpa.convert.threeten" })
#Profile({"ARA_JADE_CONF", "LOCAL_JADE_CONF"})
public class InfrastructureConfig {
private final static int JDBC_FETCH_SIZE = 1000;
#Autowired
private Environment environment;
#Bean
public LocalContainerEntityManagerFactoryBean jadeEntityManager() throws SQLException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSourceJade());
em.setPackagesToScan(new String[] {"com...jade"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
#Primary
public OracleDataSource dataSourceJade() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setUser(environment.getProperty("db.datasource.jade.username"));
dataSource.setPassword(environment.getProperty("db.datasource.jade.password"));
dataSource.setURL(environment.getProperty("db.datasource.jade.url"));
dataSource.setImplicitCachingEnabled(true);
dataSource.setFastConnectionFailoverEnabled(true);
return dataSource;
}
#Bean(name="jdbcTemplateJade")
public JdbcTemplate jdbcTemplateJade() throws SQLException {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceJade());
jdbcTemplate.setResultsMapCaseInsensitive(true);
jdbcTemplate.setFetchSize(JDBC_FETCH_SIZE);
return jdbcTemplate;
}
#Bean
public PlatformTransactionManager transactionManager() throws SQLException{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(jadeEntityManager().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
} ...
Seconde Infrastructure configuration
#Configuration
#ComponentScan(basePackages = "com.bnpparibas.sit.risk.art")
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "artEntityManager", transactionManagerRef = "artTransactionManager")
#EntityScan(basePackages = { "com...art", "org.springframework.data.jpa.convert.threeten" })
#Profile({"LOCAL_ART_CONF,'ARA_ART_CONF"})
public class ArtInfrastructureConfig {
private final static int JDBC_FETCH_SIZE = 1000;
#Autowired
private Environment environment;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean artEntityManager() throws SQLException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSourceArt());
em.setPackagesToScan(new String[] {"com...art.infrastructure.persistence"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
#Primary
public OracleDataSource dataSourceArt() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setUser(environment.getProperty("db.datasource.art.username"));
dataSource.setPassword(environment.getProperty("db.datasource.art.password"));
dataSource.setURL(environment.getProperty("db.datasource.art.url"));
dataSource.setImplicitCachingEnabled(true);
dataSource.setFastConnectionFailoverEnabled(true);
return dataSource;
}
#Bean
#Primary
public PlatformTransactionManager artTransactionManager()throws SQLException{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(artEntityManager().getObject());
return transactionManager;
}
#Bean
#Primary
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}...
Interface link to Entity.
#DDD.Repository
#Repository
public interface CollaborateurJpaRepository extends CrudRepository<Collaborateur,String>{
#Query("FROM ART_PARAM.ART_USER u WHERE u.refogUID = :uid")
Collaborateur findCollaborateurById(#Param("uid") String uid);
}
Class that contain the autowired interface to retrieve some data of the second database.
#DDD.RepositoryImpl
#Repository
#Primary
public class UserRepositoryImpl implements UserRepository {
#Autowired
private CollaborateurJpaRepository collaborateurJpaRepository;
#Override
//#Cacheable(cacheNames = CacheConfig.CACHE_JURIDICTION, key = CacheConfig.CACHE_KEY_UTILISATEUR_ID)
#Transactional("entityManagerFactoryArt")
public User retrieveUser(UserId userId) {
if(userId.getValue() == null) {
return null;
} else {
Collaborateur collaborateur = collaborateurJpaRepository.findOne(userId.getValue());
return new User(collaborateur.getRefogUID(),collaborateur.getRefogFirstName(),collaborateur.getRefogLastName(),collaborateur.getProfile(),collaborateur.isActiveUser(),collaborateur.isBankingSecrecy());
}
}
I am working on spring boot multi tenancy application. I have configured multi datasources as shown below :
application.properties
spring.multitenancy.datasource1.url=jdbc:mysql://localhost:3306/db1
spring.multitenancy.datasource1.username=root
spring.multitenancy.datasource1.password=****
spring.multitenancy.datasource1.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.multitenancy.datasource2.url=jdbc:mysql://localhost:3306/db2
spring.multitenancy.datasource2.username=root
spring.multitenancy.datasource2.password=****
spring.multitenancy.datasource2.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.multitenancy.datasource3.url=jdbc:mysql://localhost:3306/db3
spring.multitenancy.datasource3.username=root
spring.multitenancy.datasource3.password=****
spring.multitenancy.datasource3.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
DataSourceBasedMultiTenantConnectionProviderImpl.java
#Component
public class DataSourceBasedMultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
private static final long serialVersionUID = 8168907057647334460L;
private static final String DEFAULT_TENANT_ID = "tenant_1";
#Autowired
private DataSource dataSource1;
#Autowired
private DataSource dataSource2;
#Autowired
private DataSource dataSource3;
private Map<String, DataSource> map;
#PostConstruct
public void load() {
map = new HashMap<>();
map.put("tenant_1", dataSource1);
map.put("tenant_2", dataSource2);
map.put("tenant_3", dataSource3);
}
#Override
protected DataSource selectAnyDataSource() {
return map.get(DEFAULT_TENANT_ID);
}
#Override
protected DataSource selectDataSource(String tenantIdentifier) {
return map.get(tenantIdentifier);
}
}
MultitenancyProperties.java
#ConfigurationProperties("spring.multitenancy")
public class MultitenancyProperties {
#NestedConfigurationProperty
private DataSourceProperties datasource1;
#NestedConfigurationProperty
private DataSourceProperties datasource2;
#NestedConfigurationProperty
private DataSourceProperties datasource3;
public DataSourceProperties getDatasource1() {
return datasource1;
}
public void setDatasource1(DataSourceProperties datasource1) {
this.datasource1 = datasource1;
}
public DataSourceProperties getDatasource2() {
return datasource2;
}
public void setDatasource2(DataSourceProperties datasource2) {
this.datasource2 = datasource2;
}
public DataSourceProperties getDatasource3() {
return datasource3;
}
public void setDatasource3(DataSourceProperties datasource3) {
this.datasource3 = datasource3;
}
}
MultiTenancyJpaConfiguration.java
#Configuration
#EnableConfigurationProperties(JpaProperties.class)
public class MultiTenancyJpaConfiguration {
#Autowired
private DataSource dataSource;
#Autowired
private JpaProperties jpaProperties;
#Autowired
private MultiTenantConnectionProvider multiTenantConnectionProvider;
#Autowired
private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
Map<String, Object> hibernateProps = new LinkedHashMap<>();
hibernateProps.putAll(jpaProperties.getHibernateProperties(dataSource));
hibernateProps.put(Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
hibernateProps.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
hibernateProps.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
hibernateProps.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");
return builder.dataSource(dataSource).packages(HotelEntity.class.getPackage().getName()).properties(hibernateProps).jta(false).build();
}
}
Application launcher
#SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
#EnableConfigurationProperties(MultitenancyProperties.class)
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
When I run the boot application, all tables are created in only first data source.
1) How can I create tables in all data sources on application startup?
2) How to see connections opened/closed for each of the data sources?
3) Is there a better way of configuring multi tenancy application using spring boot for better performance?
As #Alex said, you need differnt EntityManagers, TransactionManager and Datasources. Here is how I would do it
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "dataSource1EntityManagerFactory",
transactionManagerRef = "dataSource1TransactionManager",
basePackageClasses = dataSource1Repository.class)
public class DataSource1Config extends SqlConfig{// Put all common code in base class SqlConfig. If not remove it
#Bean
#Primary
public DataSource dataSource1() {
//create dataSource using MultitenancyProperties::getDataSource1
}
#Primary
#Bean(name = "dataSource1TransactionManager")
PlatformTransactionManager dataSource1TransactionManager(EntityManagerFactory dataSource1EntityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(dataSource1EntityManagerFactory);
return txManager;
}
#Primary
#Bean(name = "dataSource1EntityManagerFactory")
LocalContainerEntityManagerFactoryBean dataSource1EntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource1());
em.setPackagesToScan(dataSource1Repository.class.getPackage().getName(), dataSource1ModelClass.class.getPackage().getName());
em.setPersistenceUnitName("dataSource1Db");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
}
You can create two other classes like this. Remember to use #Primary on only one instace of datasource, transactionmanger and entitymanager(doesn't matter which one). Another word of caution, make sure Repository classes are in different packages for all three databases.
Try adding the following properties:
spring.jpa.generate-ddl=true
You need 2 different persistence factories, not one, each should produce different EntityManagers for different datasources. Also each entity mapping should be marked to been used only with one entity manager.
See full solution here:
http://www.baeldung.com/spring-data-jpa-multiple-databases
I am using JPA in my application, and it works once I query for objects, however it throw error javax.persistence.TransactionRequiredException: No transactional EntityManager available once I tried to save or update an object.
This is the java configuration:
#Configuration
#EnableTransactionManagement(proxyTargetClass = true)
#PropertySource("classpath:dao.properties")
public class JpaConfig {
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
.....................
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.dialect", ...........)
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setJpaProperties(jpaProperties);
entityManagerFactoryBean.setPackagesToScan("com....");
return entityManagerFactoryBean;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
Note I use proxyTargetClass = true in the #EnableTransactionManagement, since I do not want to create the useless interfaces in my application.
And this is the concrete implemention of the dao:
#Transactional
#Repository
public abstract class AbstractJPADao<I, E> {
#Autowired
#PersistenceContext
protected EntityManager entityManager;
private Class<E> type;
public AbstractJPADao() {
type=....
}
#Override
public Result<E> find(I id) {
E e = entityManager.find(type, id);
return Result.newInstance().setContent(e);
}
#Override
public Result<E> find(Map<String, Object> condition) {
Query q = entityManager.createQuery(".......));
return Result.newInstance().setContent(q.getResultList());
}
#Override
public E save(E element) {
entityManager.persist(element);
return element;
}
#Override
public E update(E element) {
entityManager.merge(element);
return element;
}
#Override
public void delete(E element) {
entityManager.remove(element);
}
}
#Repository
#Transactional
public class DepartmentDao extends AbstractJPADao<String, Department> {
#Override
protected String selectCause(Map<String, Object> condition) {
return "";
}
}
And the controller as the client of the dao:
#Controller
#RequestMapping("/api/deps")
public class DepartmentCtrl {
#Autowired
private DepartmentDao departmentDao;
#RequestMapping(value = "", method = RequestMethod.POST)
public Result create(#Valid Department department, BindingResult bindingResult) {
if (!bindingResult.hasErrors()) {
departmentDao.save(department);
return Result.newInstance().setContent(department);
}
throw new RuntimeException("...");
}
}
Is there anything wrong?
dao.properties:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/proj
jdbc.username=root
jdbc.password=
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.hbm2ddl.auto=update
#hibernate.ejb.naming_strategy=true
hibernate.show_sql=true
hibernate.format_sql=true
Try renaming method transactionManager to txManager in the class JpaConfig
Autowiring goes by the name txManager
Edit
Also the framework could be expecting a no argument method for txManager. Can you try changing to
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
As noticed Tiny, you have two annotations #Autowired and #PersistenceContext over the protected field of type EntityManager in AbstractJPADao.
Try removing #Autowired. #PersistenceContext is enough to inject the EntityManager.
I'm working with Spring and in it spring-data-jpa:1.7.0.RELEASE and hibernate-jpa-2.1-api:1.0.0.Final. My database is a MySQL. In a integration test, when I save an entity, the entityRepository.save() method does not return a update version of it (with the auto-incremented id populated for example), thus I can see it is in the database.
Here's my configuration class:
//#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "core.repository")
#Configuration
#PropertySource("classpath:application.properties")
public class JPAConfiguration {
#Autowired
private Environment env;
private
#Value("${db.driverClassName}")
String driverClassName;
private
#Value("${db.url}")
String url;
private
#Value("${db.username}")
String user;
private
#Value("${db.password}")
String password;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setDatabasePlatform(env.getProperty("hibernate.dialect"));
final LocalContainerEntityManagerFactoryBean em =
new LocalContainerEntityManagerFactoryBean();
em.setJpaVendorAdapter(vendorAdapter);
em.setPackagesToScan(new String[]{"core.persistence"});
em.setDataSource(dataSource());
em.afterPropertiesSet();
return em;
}
#Bean
public EntityManager entityManager(EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
#Bean
public JpaTransactionManager transactionManager(final EntityManagerFactory emf) {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
}
Here's my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {JPAConfiguration.class})
//#Transactional
//#TransactionConfiguration(defaultRollback = true)
public class AgencyRepositoryIntegrationTests {
#Autowired
AgencyRepository agencyRepository;
#Test
public void testThatAgencyIsSavedIntoRepoWorks() throws Exception {
Agency c = DomainTestData.getAgency();
Agency d = agencyRepository.save(c);
// here d equals to c but both have id 0.
Collection<Agency> results = Lists.newArrayList(agencyRepository.findAll());
//here results != null and it does contain the agency object.
assertNotNull(results);
}
}
I end up commenting the Transactional annotations (both in the test and in the configuration class) due to research other questions in stackoverflow, but it did not work.
Thanks
Try to uncomment your #Transactional annotation and run. I can't see any visible problem in your snippet but there is something inside me (and it's not hunger) saying that your transaction demarcation is not right. I had similar problems like this before and it was just #transaction annotations missing or transaction misconfiguration.
Use saveAndFlush method to make sure that the entity is in the database.
Make sure to add #Transactional to your methods if a NoTransactionException appears.
I want to use Spring Data JPA to do the ORM. I have the following declared repository interface:
public interface SegmentRepository extends JpaRepository<Segment, Integer> {
// query methods ...
}
Following is the Java Config class:
#Configuration
#EnableJpaRepositories("com.example.cap.repositories")
#EnableTransactionManagement
public class CAPRepositoryConfig {
#Bean
public DataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(org.postgresql.Driver.class.getName());
ds.setUsername("postgres");
ds.setPassword("password");
ds.setUrl("jdbc:postgresql://localhost:5432/postgres");
ds.setInitialSize(10);
return ds;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
Map<String, Object> jpaProperties = new HashMap<String, Object>();
jpaProperties.put("eclipselink.weaving", "false");
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.example.cap.repositories");
factory.setDataSource(dataSource());
factory.setJpaPropertyMap(jpaProperties);
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
}
And the Segment class is defined in com.example.cap.repositories as:
#Entity
public class Segment {
#Id
private int segmentID;
private int caseID;
private Timestamp segStartTime;
private Timestamp segEndTime;
//setter and getters
}
But when I run the JUnit test using auto injected bean SegmentRepository, I got null point exception for the bean repository:
#ContextConfiguration(classes=CAPRepositoryConfig.class)
public class CAPRepositoryTest {
#Autowired
private SegmentRepository repository;
#Test
public void testRepository() {
Segment seg = repository.findOne(123); //null pointer exception for repository
}
}
According to the Spring Data JPA documentation, the SegmentRepository bean repository should be auto injected as long as I specify #EnableJpaRepositories in the Java Config class. But why do I get null pointer exception for repository in the JUnit test class? Since SegmentRepository is an interface rather than a class, I cannot create the instance through Java Config class.
I think you forget SpringJUnit4ClassRunner which makes #Autowired in tests work:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=CAPRepositoryConfig.class)
public class CAPRepositoryTest { ... }
When I work with test classes and I need to do an unit test, I prefer instantiate the class because although you have an interface you need to have to an implementation class too. In my case I do something like this:
#ContextConfiguration(classes=CAPRepositoryConfig.class)
public class CAPRepositoryTest {
private SegmentRepository repository;
#Before
public void testRepository() {
repository = new SegmentRepositoryImpl();
}
#Test
public void testRepository() {
Segment seg = repository.findOne(123);
}
}