Unable to Inject DAO class in Spring BO [duplicate] - java

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 7 years ago.
I am unable to inject my DAO class in Spring MVC:
This is my DAO class:
package com.pankaj.bookslibrary.dao;
#Component
public class BooksLibraryDAO
{
#PersistenceContext
private EntityManager em;
public void saveBook(Book book)
{
em.persist(book);
}
}
This is my BO class which calls DAO:
package com.pankaj.bookslibrary.controller;
#Service
public class BooksLibraryBO
{
#Autowired
private BooksLibraryDAO booksLibraryDAO;
public void saveBook(Book book)
{
booksLibraryDAO.saveBook(book);
}
The above line gives NullPointerException as booksLibraryDAO is null.
Here are the relevant lines from my dispatcherServlet config file:
<beans xmlns=...3.0.xsd">
<context:component-scan base-package="com.pankaj.bookslibrary" />
<context:annotation-config/>
<bean id="dataSource"....</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="persistenceUnitName" value="BooksLibrary_PersistenceUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
</bean>
</property>
</bean>
<bean id="transactionManagerNonJTA" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="defaultTimeout" value="1800"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManagerNonJTA" />
I am not sure what I have missed.
This is how I am making a call from the controller:
BooksLibraryBO bo = new BooksLibraryBO();
bo.saveBook(book);

The packages the classes are in differs from the package you scan for annotations. Add the packages to the list of base-packages to scan for!
As M.Deinum explained, you are creating the BooksLibraryBO yourself, spring do not know that instances and will not process the annotations.

Related

LazyLoadingException appears when I try to get an object from ManyToOne relation

Here's my entity:
#Entity
public class Answer implements Serializable {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="user")
private CoreUsers user;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="person")
private Person person;
}
the service:
#Transactional
public class AnswerService {
#Autowired
private AnswerRepository repository;
public List<Answer> getAnswers(Long id) {
return repository.findByMessagesidOrderBySenddateDesc(id);
}
}
the repo:
#Repository
public interface AnswerRepository extends JpaRepository<Answer, Long> {
List<Answer> findByMessagesIdOrderBySenddateDesc(Long id);
}
the applicationContext.xml
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
<entry key="hibernate.enable_lazy_load_no_trans" value="true" />
<entry key="hibernate.current_session_context_class" value="thread" />
<entry key="org.hibernate.cacheable" value="false" />
</map>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="showSql" value="false" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
</property>
<property name="persistenceUnitName" value="cccPersistenceUnit" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
I load a collection of Answer (List) in the JSF bean through my service class. When I try to obtain a Person object from the collection — everything is okay, but when I try to obtain a User object from the collection — hibernate throws LazyInitializationException. What am I doing wrong?
Am I right, that hibernate tries to obtain the user object out of hibernate session?
Pls feel free to ask any addition information.
Thanks for any helps!
before create the thread, I googled many times
UPD.
I set the entities up to Eager loading, and noticed that my app tries to load unexist ID from user table. That was the problem :)
You can get your complete objects tree with :
import org.springframework.transaction.annotation.Transactional;
#Transactional
public List<Answer> getAnswers(Long id) {
return repository.findByMessagesidOrderBySenddateDesc(id);
}

Why autowiring spring repositories doesn't work?

I have a controller where I autowire repository:
#Controller
#RequestMapping("/account")
#EnableJpaRepositories
public class AccountController {
#Autowired
private AccountRepository accountRepo;
//methods
}
My repository extends CrudRepository
#Repository
public interface AccountRepository extends CrudRepository<Account, Integer> {
Account findOne(int primaryKey);
}
I use xml to configure my project. Here it is:
<jpa:repositories base-package="com.library.repositories"
entity-manager-factory-ref="entityManager"></jpa:repositories>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManager" />
</bean>
<bean id="entityManager"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.library.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<!-- <prop key="hibernate.hbm2ddl.auto">create-drop</prop> -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/library" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
Why it doesn't work? The error I receive is that AccountController cannot autowire bean AccountRepository.
EDIT
I've refactored my configuration to annotation based and everything works. In my XML version I probably didn't scan some classes and it resulted with error.
May be you need to have #EnableJpaRepositories annotation on a configuration class with #Configuration annotation instead of Controller class.
Also, make sure your Configuration classes are under a scanned package.

Mybatis with Spring NullPointerException Autowired field

I'm trying to integrate Mybatis with spring. Here you can see my application context of Spring
<context:annotation-config />
<context:component-scan base-package="com" />
<tx:annotation-driven />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/DB" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:/com/mybatis/mybatis-config.xml" />
<!--<property name="transactionFactory" ref="springManagedTransactionFactory" />-->
</bean>
<!--
<bean id="springManagedTransactionFactory" class="org.mybatis.spring.transaction.SpringManagedTransactionFactory">
<constructor-arg index="0" ref="dataSource" />
</bean> -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="registroClimaMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.mybatis.dao.RegistroClimaMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
First of all I have commented springManagedTransactionFactory in XML because it's giving me an exception
Error creating bean with name 'springManagedTransactionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
Here is my interface RegistroClimaMapper. I do not have any annotation here because I have defined the context:component scan.
public interface RegistroClimaMapper {
void insertarRegistroClima(RegistroClima registro) throws SQLException;
List<RegistroClima> getRegistrosClima() throws SQLException;
List<RegistroClima> getRegistrosClima(#Param("Validado") boolean Validado) throws SQLException;
}
I try to use this interface in a ManagedBean and when I'm going to use registroClimaPersistence inside a method of TablaRegistroClimaBean I get a NullPointerException
#ManagedBean(name = "tablaRegClimaBean")
#ViewScoped
public class TablaRegistroClimaBean implements Serializable {
#Autowired
private RegistroClimaMapper registroClimaPersistence;
public void setRegistroClimaPersistence(RegistroClimaMapper registroClimaPersistence) {
this.registroClimaPersistence = registroClimaPersistence;
}
}
As seen here: http://javadox.com/org.mybatis/mybatis-spring/1.1.1/org/mybatis/spring/transaction/SpringManagedTransactionFactory.html#SpringManagedTransactionFactory%28%29, SpringManagedTransactionFactory has a default constructor, but none that takes a datasource. You need to pass the datasource to the newTransaction() method, but not to the constructor: http://javadox.com/org.mybatis/mybatis-spring/1.1.1/org/mybatis/spring/transaction/SpringManagedTransactionFactory.html#newTransaction(javax.sql.DataSource,%20org.apache.ibatis.session.TransactionIsolationLevel,%20boolean)
Change the piece of code to
<bean id="springManagedTransactionFactory" class="org.mybatis.spring.transaction.SpringManagedTransactionFactory">
<!--<constructor-arg index="0" ref="dataSource" />-->
</bean>
or completely remove the constructor-arg.
What NullPointerException do you get? It might come from you just defining the RegistroClimaMapper interface, but not implementing this interface in any bean. Please add a Bean that implements this interface and the Autowired annotation should work.

#Transactional in unit test prevents #PostLoad from being invoked

I have the following test:
public class Book
{
public boolean postLoadInvoked;
#PostLoad
private void onPostLoad()
{
postLoadInvoked = true;
}
}
public class MyIntegrationTest extends AbstractIntegrationTest
{
#Autowired
private BookDAO bookDAO;
#Test
public void loadBooks()
{
Book book = bookDAO.findOne(...);
assertTrue(book.postLoadInvoked);
}
}
This test passes as-is, but if I add the #Transactional annotations to the test class, it fails:
#Transactional
#TransactionConfiguration(defaultRollback=true)
public class MyIntegrationTest extends AbstractIntegrationTest
Why does configuring the test with #Transactional affect the JPA callback methods?
EDIT
The DAO is just a Spring Data repository, so has no logic:
public interface BookDAO extends
JpaRepository<Book, Long>,
QueryDslPredicateExecutor<Book> {}
The transaction manager also has a standard configuration:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.mangofactory.example</value>
</list>
</property>
<property name="persistenceUnitName" value="spring-test" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
</bean>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1" />
</bean>
I'm not sure what the spring version is that you are using or if AbstractIntegrationTest is extending something, but one thing to check is that in your hierarchy your tests should extend some abstract transactional context aware spring test class.
The classes that I'm thinking about:
org.springframework.test.AbstractTransactionalSpringContextTests
org.springframework.test.AbstractTransactionalDataSourceSpringContextTests
or some jUnit flavor (depending on the version that you are using):
org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests
org.springframework.test.context.junit38.AbstractTransactionalJUnit38SpringContextTests
I could think of two reasons:
#PostLoad is only executed after the transaction is committed. Unlikely.
How did you enable transactions? Did you specify proxyTargetClass = true? Otherwise, you can get weird behavior.

Spring + EntityManagerFactory +Hibernate Listeners + Injection

i have a simple question. Its possible to add dependency injection via #Ressource or #Autowired to the Hibernate Eventlistener?
I will show you my entitymanagerfactory configuration:
<bean id="entityManagerFactory" class="org.hibernate.ejb.EntityManagerFactoryImpl">
<qualifier value="entityManagerFactory" />
<constructor-arg>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager">
<bean
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManagerr">
<property name="defaultDataSource" ref="dataSource" />
</bean>
</property>
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="mis" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaProperties" ref="jpa.properties" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database">
<util:constant
static-field="org.springframework.orm.jpa.vendor.Database.POSTGRESQL" />
</property>
<property name="showSql" value="true" />
</bean>
</property>
</bean>
</constructor-arg>
</bean>
At the moment i register my listener via jpa.properties,
hibernate.ejb.event.load=com.example.hibernate.events.LoadEvent
but in this case i have no spring injection in my listener. I found a solution, but this use the sessionFactory and not the entitymanager oder can i modifiy the sessionfactory in my context? Hopefully someone have a nice idea or solutionhow to deal with this problematic!
Big thanks!
If you used SessionFactory, this would be the configuration:
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- Stripped other stuff -->
<property name="eventListeners">
<map>
<entry key="pre-load">
<bean class="com.mycompany.MyCustomHibernateEventListener1" />
</entry>
<entry key="pre-persist">
<bean class="com.mycompany.MyCustomHibernateEventListener2" />
</entry>
</map>
</property>
</bean>
But since you are using JPA, I'm afraid you need to use AOP as outlined in this thread
Or you can
store the ApplicationContext in a ThreadLocal or a custom holder class and expose it through a static method
have a base class for your listeners something like this:
Base class:
public abstract class ListenerBase{
protected void wireMe(){
ApplicationContext ctx = ContextHelper.getCurrentApplicationContext();
ctx.getAutowireCapableBeanFactory().autowireBean(this);
}
}
Now in your lifycycle methods call wireMe() first.
Update:
Here is a sample implementation of ContextHelper:
public final class ContextHelper implements ApplicationContextAware{
private static final ContextHelper INSTANCE = new ContextHelper();
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(final ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}
public static ApplicationContext getCurrentApplicationContext(){
return INSTANCE.applicationContext;
};
public static ContextHelper getInstance(){
return INSTANCE;
}
private ContextHelper(){
}
}
Wire it in your Spring Bean configuration like this:
<bean class="com.mycompany.ContextHelper" factory-method="getInstance" />

Categories

Resources