Configuration beans are not initialized - java

I don’t quite understand how this can be, but methods marked as #Bean are not initialized when I run them through the WebApplicationInitializer. In the debugger, you can only get to the #Autowired setters inside the #Configuration classes, but I don't see the initialization of the beans. When I start Spring context with Junit, it works fine.
Exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.hibernate.SessionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
WebServiceDispatcherServletInitializer
public class WebServiceDispatcherServletInitializer implements WebApplicationInitializer {
private static final String SERVICE_DISPATCHER_SERVLET = "service_dispatcher_servlet";
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(WebServiceConfig.class, RootConfig.class, PersistenceConfig.class);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new CXFServlet());
dispatcher.addMapping("/services/*");
}
}
UPD: PersistenceConfig
#Configuration
#ComponentScan("com.softcomputer")
#PropertySource({"classpath:persistence-postgres.properties"})
#EnableTransactionManagement
public class PersistenceConfig {
private Environment environment;
#Autowired
public void setEnvironment(Environment environment) {
this.environment = environment;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory);
return transactionManager;
}
#Bean
#Profile("postgres")
public DataSource postgresDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(requireNonNull(environment.getProperty("jdbc.postgres.driverClassName")));
dataSource.setUrl(requireNonNull(environment.getProperty("jdbc.postgres.connection_url")));
dataSource.setUsername(requireNonNull(environment.getProperty("jdbc.postgres.username")));
dataSource.setPassword(requireNonNull(environment.getProperty("jdbc.postgres.password")));
return dataSource;
}
#Bean
#Profile("postgres")
public LocalSessionFactoryBean postgresSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(postgresDataSource());
sessionFactory.setPackagesToScan(
new String[]{"com.softcomputer", "com.softcomputer.testdomain"});
sessionFactory.setHibernateProperties(postgresAdditionalProperties());
return sessionFactory;
}
private Properties postgresAdditionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", requireNonNull(environment.getProperty("hibernate.postgres.hbm2ddl.auto")));
hibernateProperties.setProperty("hibernate.dialect", requireNonNull(environment.getProperty("hibernate.postgres.dialect")));
hibernateProperties.setProperty("hibernate.show_sql", requireNonNull(environment.getProperty("hibernate.postgres.show_sql")));
hibernateProperties.setProperty("hibernate.default_schema", requireNonNull(environment.getProperty("hibernate.postgres.default_schema")));
hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", requireNonNull(environment.getProperty("hibernate.postgres.globally_quoted_identifiers")));
return hibernateProperties;
}
}
UPD1: Beans in WebServiceConfig.class are not initialized either. But RootConfig.class is initialized fine (all config classes has #Configuration annotation)
UPD2: Maybes WebApplicationInitializer.onStartup expect another configuration, as szatkus said. Then what kind of startup should be used to run new CXFServlet() with such Configuration classes?

LocalSessionFactoryBean doesn't implement SessionFactory interface. Maybe try:
#Bean
#Autowired
public SessionFactory sessionFactory(LocalSessionFactoryBean sessionFactoryBean) {
return bean.getObject();
}

Related

RESTful webservice using Java Streams and Spring Boot

I try to implement a RESTful WebService that is able to stream millions of records directly from database.
I'm using SpringBoot 2.2.5, Hibernate 5 and PostgreSQL 11
According to this post:
https://www.airpair.com/java/posts/spring-streams-memory-efficiency
one step is needed to set the flag "allowResultAccessAfterCompletion" to true.
But how can I do this in Spring Boot?
So far I do not have any SessionFactory, EntityManagerFactory, Datasource, ... configuration in my application. Everything is autoconfigured by SpringBoot.
If I add the proposed configuration below, the application won't start because of missing SessionFactory.
#Configuration
#EnableTransactionManagement
public class DataConfig {
#Autowired #Bean
public PlatformTransactionManager txManager(SessionFactory sf) {
HibernateTransactionManager mgr = new HibernateTransactionManager(sf);
mgr.setAllowResultAccessAfterCompletion(true);
return mgr;
}
... (the rest of your data config, including the LocalSessionFactoryBean) ...
}
If I provide a SessionFactory bean by unwrapping it from EntityManagerFactory, I get another exception:
Unsatisfied dependency expressed through field 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'getSessionFactory': Requested bean is currently in creation: Is there an unresolvable circular reference?
Does anyone have a working configuration for my setup?
Can't this flag simply be set by some configuration value in application.properties?
Thank you!
First of all you need to decide whether you need to use Hibernate or Spring JPA for your project. Work with the framework and not against it. Using jpa classes are preferred over hibernate classes by most people today.
Since you are using springboot , the best approach is to work with the framework and use spring-boot-starter-data-jpa which will automatically configure all your necessary beans at startup. In that case, you could provide your own custom beans to override parameters as you want.
In the sample code that you provided in the question, you are using Hibernate classes directly , so you will have to manually create all the necessary beans as spring won't work with you for that unless you disable the auto-configurations which might be causing the circular dependency issue for you.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories("com.sample.spring.repository")
#PropertySource("classpath:database.properties")
public class DataConfig {
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
#Autowired
Environment environment;
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.sample.spring");
lfb.setJpaProperties(hibernateProps());
return lfb;
}
#Bean
DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(environment.getProperty(PROPERTY_URL));
ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
return ds;
}
Properties hibernateProps() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
}
#Bean
JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
You can very well provide your own the SessionFactory as well in which case spring boot will not create another one for you. Following is excerpt from Bootstrapping Hibernate 5 with Spring article, feel free to tweak it as per your needs
#Configuration
#EnableTransactionManagement
public class HibernateConf {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(
{"com.baeldung.hibernate.bootstrap.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("sa");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setAllowResultAccessAfterCompletion(true);
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty(
"hibernate.hbm2ddl.auto", "create-drop");
hibernateProperties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.H2Dialect");
return hibernateProperties;
}
}
Another approach is to use BeanPostProcessor if you know that spring boot is already creating a HibernateTransactionManager in it's own lifecycle. Following is what the outline of the this BeanPostProcessor would look like
public class HTMPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof HibernateTransactionManager) {
((HibernateTransactionManager)bean).setAllowResultAccessAfterCompletion(true);
}
return bean; // you can return any other object as well
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean; // you can return any other object as well
}
}
Hope this helps!!

NoSuchBeanDefinitionException: No qualifying bean of type JpaVendorAdapter found for dependency

I'm trying to setup Java-based hibernate in memory database and start using it from a test, but when Hibernate beans are loaded Application context fail with. The point if this exercise is to setup simple service with CRUD operations using CrudRepository for a few classes and WRITE
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.orm.jpa.JpaVendorAdapter] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:813)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 72 more
Related configuration and source code:
hibernate.properties
jdbc.driverClassName = org.hsqldb.jdbcDriver
jdbc.url = jdbc:hsqldb:mem:press
jdbc.username = user
jdbc.password =
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.show_sql = false
hibernate.format_sql = false
HibernateConfig.java - which fails to load
#Configuration
#EnableTransactionManagement
#PropertySource(value = { "classpath:hibernate.properties" })
public class HibernateConfig {
#Autowired
private Environment environment;
#Bean
public EntityManagerFactory entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("net.agilob.press.entity");
return lef.getNativeEntityManagerFactory();
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "net.agilob.press.entity" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("create-drop"));
return properties;
}
#Bean
#Autowired
public HibernateTemplate getHibernateTemplate(SessionFactory sessionFactory) {
HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
return hibernateTemplate;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
AppConfig.java - file loaded as configuration for test
#Configuration
#ComponentScan(basePackages = "net.agilob.press.entity")
#EnableJpaRepositories(basePackages = "net.agilob.press.entity.repository")
#Import(HibernateConfig.class)
public class AppConfig {
#Bean
public PostService getPostService() {
return new PostService();
}
}
PostServiceTest.java - this one should create instance(s) of Post, save it in memory database and extract later (just to see it works):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)
#Transactional
public class PostDAOTest {
#Autowired
private PostService postService;
#Before
public void setUp() {
Post post = new Post();
post.setContent("body");
post.setDescription("description");
post.setIntroduction("introduction");
post.setTitle("title");
post.setTitleBrowser("title browser");
postRepository.save(post);
}
#Test
public void testList() {
// checks if spring wiring was correct
assertNotNull("Problem with spring beans", postRepository);
assertFalse(postRepository.findTop10ByTitleOrderByIdAsc().isEmpty());
}
}
PostService:
#Service("postService")
#Transactional
public class PostService {
#Autowired
private PostRepository postRepository;
...
}
PostRepository:
public interface PostRepository extends BaseRepository<Post, Long> {
}
I tried to create one more #Beans annotated method in HibernateConfig that was bulding JpaVendorAdapter instance but when I run the test it was failing with:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManager]: Factory method 'createSharedEntityManager' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 59 more
Caused by: java.lang.NullPointerException
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.initProxyClassLoader(SharedEntityManagerCreator.java:199)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.<init>(SharedEntityManagerCreator.java:191)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:163)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:120)
at org.springframework.orm.jpa.SharedEntityManagerCreator.createSharedEntityManager(SharedEntityManagerCreator.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 60 more
my pom.xml
so I think something else is wrong in the setup.
Any help how to design and setup it in a better way very appreciated.
In order for your entityManagerFactory to know the provider class as well as jpa dialect, you need to set jpaVendorAdaptor on your entityManagerFactory bean. This can be done as
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setDatabase(Database.HSQL);
jpaVendorAdapter.setDatabasePlatform(MySQL5Dialect.class.getName());
jpaVendorAdapter.setGenerateDdl(false);
return jpaVendorAdapter;
}
and calling this method inside your entityManagerFactory as follows :
lef.setJpaVendorAdapter(jpaVendorAdapter());
Are you sure that you have all required dependencies?
Is HibernateJpaVendorAdapter available on your classpath?
Try to add dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>

Why is my entitymanager in Playframework 2.5 still null?

I want to use Playframework 2.5 together with Spring and JPA. I found the following template https://github.com/jamesward/play-java-spring where it works perfectly, unfortunately it’s not for Playframework 2.5. So I decided to adapt this template and create my own one for Playframework 2.5. However, my entitymanager in my controller Application is still null. What am I doing wrong? My code looks like the following:
AppConfig.java
package config;
#Configuration
#ComponentScan({"daos","services","controllers","models"})
public class AppConfig {
}
DataConfig.java
package config;
#Configuration
#EnableTransactionManagement
public class DataConfig
{
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPackagesToScan("models");
entityManagerFactory.setJpaVendorAdapter(vendorAdapter);
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setJpaPropertyMap(new HashMap<String, String>(){{
put("hibernate.hbm2ddl.auto", "create-drop");
put("hibernate.dialect","org.hibernate.dialect.PostgreSQLDialect");
}});
entityManagerFactory.afterPropertiesSet();
return entityManagerFactory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory());
return transactionManager;
}
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
return dataSource;
}
}
Global.java
package config;
#Singleton
#Configuration
public class Global
{
private ConfigurableApplicationContext context;
#Inject
public Global(ApplicationLifecycle lifecyle)
{
this.context = new AnnotationConfigApplicationContext(AppConfig.class, DataConfig.class);
lifecyle.addStopHook(()-> {
context.close();
return CompletableFuture.completedFuture(null);
});
}
}
Application.java
package controllers;
#Controller
#Transactional
#Component
public class Application extends play.mvc.Controller
{
#PersistenceContext
private EntityManager em;
#Transactional
public Result index()
{
System.out.println("******************* EM " + this.em +" *************************");
return ok(index.render());
}
}
Thank you for your help!

Spring Configuration creating two beans instead of one

I'm writing a RESTful web service using Spring MVC, using Java Configuration. My configuration file is below. My issue is this -- I discovered that 2 instances of "myService" bean is being created, instead of just one instance. I'm not sure why? How can I adjust the configuration to create only one?
Can anyone point me in the right direction? Thanks!
Here's my configuration class....
#Configuration
public class MyConfig {
#Bean(name = "dataSource")
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
// datasource set up
return dataSource;
}
#Autowired
#Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DriverManagerDataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionBuilder.scanPackages("com.mypackages");
sessionBuilder.addProperties(getHibernateProperties());
return sessionBuilder.buildSessionFactory();
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.enable_lazy_load_no_trans", "true");
properties.put("hibernate.id.new_generator_mappings", "true");
return properties;
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);
return transactionManager;
}
#Bean
public MyMainBean MyMainBean() {
MyMainBean bean = new MyMainBean();
bean.setService(myService());
bean.setValidator(myValidator());
return bean;
}
#Bean(name = "myService")
public MyService myService() {
MyService s = new MyService();
s.setDao1(myDao1());
s.setDao2(myDao2());
s.setCopyUtil(copyUtil());
return s;
}
#Bean
public MyDao1 myDao1() {
return new MyDao1();
}
#Bean
public MyDao2 myDao2() {
return new MyDao2();
}
#Bean
public CopyUtil copyUtil() {
return new CopyUtil();
}
#Bean
public ReportValidator reportValidator() {
ReportValidator validator = new ReportValidator();
validator.setService(myService());
return validator;
}
#Bean
public XMLValidator xmlValidator() {
XMLValidator validator = new XMLValidator();
validator.setService(myService());
return validator;
}
}
Actually, Spring is smart when wiring beans and should only call the myService() function once, and then pass the result to the other myService() calls, resulting in only one bean of MyService.
Make sure you really are getting 2 instances of MyService, e.g. by adding a log in the constructor of the MyService class.
If you truly see more than one constructor log statement, make sure that you are not declaring other MyService beans in other #Configuration classes, or that you are not using any component annotation on the MyService class (i.e. don't use #Service, #Component, #Repository).
If you declare the class with #Service, it effectively instantiates the class and adds it to the context. When you declare it again with #Bean you end up with 2 instances, so don't mix them.
Also, you don't need to use those #Autowired annotations here, or even calls to other beans, because the following will also work:
#Configuration
public class DbConfiguration {
#Bean
public MovieDao dao() {
return new MovieDao();
}
#Bean
public MovieService service(MovieDao dao) {
return new MovieService(dao);
}
}
Spring will see that you need a MovieDao to build a MovieService and it will instantiate the dao first and pass it to the service bean. You don't even need to add #Service or similar annotations to your classes!
It really is that good, hope these tips help ;)

#Autowired bean not being found

I'm getting errors trying to inject resource dependencies into my unit testing.
My approach has been to write a TestConfig.java to replace the applicationContext.xml for production which manages the connections of the beans. So that I can run it with an in-memory database and just test components.
TestConfig.java
#Configuration
#EnableTransactionManagement
public class TestConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl("jdbc:hsqldb:mem:testdb");
ds.setUsername("sa");
ds.setPassword("");
return ds;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
LocalContainerEntityManagerFactoryBean lcemfb
= new LocalContainerEntityManagerFactoryBean();
lcemfb.setDataSource(this.dataSource());
lcemfb.setPackagesToScan(new String[] {"com.dao","com.data"});
lcemfb.setPersistenceUnitName("MyTestPU");
HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
lcemfb.setJpaVendorAdapter(va);
Properties ps = new Properties();
ps.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
ps.put("hibernate.hbm2ddl.auto", "create");
lcemfb.setJpaProperties(ps);
lcemfb.afterPropertiesSet();
return lcemfb;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager tm = new JpaTransactionManager();
tm.setEntityManagerFactory(this.entityManagerFactoryBean().getObject());
return tm;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor()
{
return new AutowiredAnnotationBeanPostProcessor();
}
}
ProductsDaoTest.java
#ContextConfiguration(classes = { TestConfig.class })
#RunWith(SpringJUnit4ClassRunner.class)
public class ProductsDaoTest {
#Resource(name="com.dao.ProductsDao")
private ProductsDao testDao;
#Test
public void testSaveProduct() {
Product productA = new Product();
testDao.save(productA);
Set<Product> products = testDao.getAllProducts();
assertNotNull(products);
}
}
The error is Error creating bean with name 'com.dao.ProductsDaoTest': Injection of resource dependencies failed
So it can't find the ProductDao Bean which is a #Repository with a #Autowired sessionFactory.
So my guess is that because I'm not naming the beans using xml it can't find it, though I thought it should automatically pick it up from setPackagesToScan(). So is there a way to manually insert the Bean mapping so that it can be found?
Also more generally is this a reasonable way to go about testing Spring DAO configurations?
Regards,
Iain
I think you are trying to use wrong name of your DAO bean in #Resource annotation. Have you explicitly specify name of the ProductsDao bean using #Qualifier? If no, then as I remember by default the name of the bean will be productsDao. So you should inject your DAO like:
#Resource(name="productsDao")
private ProductsDao testDao;
If you have only one ProductDAO implementation then simply write:
#Autowired
private ProductsDao testDao;
or
#Inject
private ProductsDao testDao;
In case if you want to give specific name to DAO then use next construction:
#Respository
#Qualifier(name="specificName")
public class ProductDAO...
EDIT:
As Boris noted you should also specify which package to scan for defined beans (classes annotated with #Component, #Service, #Repository...). For this you should add #ComponentScan annotation to your configuration class definition.
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = {"package_to_scan"})
public class TestConfig {...}

Categories

Resources