I've got a problem in my standalone Java application. The thing is that I'm trying to Autowire both my Services and my DAOs, but I get a NullPointerException when I invoke service methods from the UI since dependency injection is not working properly. I've tried a lot of things, many of them from similar questions, but the problem is still there. I'm using Spring 4.0.6.RELEASE and Hibernate 4.3.11.Final. Here is my code:
1 - Invocation of service:
public class LoginView {
#Autowired
private UsuarioService usuarioService;
...
...
JButton btnAutenticarse = new JButton("Autenticar");
btnAutenticarse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Usuario usuario = usuarioService.login(textField.getText(),
String.valueOf(passwordField.getPassword()), false); // NullPointerException
} catch (InstanceNotFoundException e1) {
...
2 - Definition of service:
#Service("usuarioService")
public class UsuarioServiceImpl implements UsuarioService {
#Autowired
private UsuarioDao usuarioDao;
...
3 - Definition of DAO:
#Repository("usuarioDao")
public class UsuarioDaoHibernate extends GenericDaoHibernate <Usuario, Long>
implements UsuarioDao {
...
4 - Definition of GenericDAO:
public class GenericDaoHibernate<E, PK extends Serializable> implements
GenericDao<E, PK> {
#Autowired
private SessionFactory sessionFactory;
....
5 - AppConfig.java:
#Configuration
#ComponentScan(basePackages = "org.example.model")
public class AppConfig {
#Bean(name = "usuarioService")
public UsuarioService usuarioService() {
return new UsuarioServiceImpl();
}
#Bean(name = "usuarioDao")
public UsuarioDao usuarioDao() {
return new UsuarioDaoHibernate();
}
6 - spring-config.xml:
<!-- Enable usage of #Autowired. -->
<context:annotation-config/>
<!-- Enable component scanning for defining beans with annotations. -->
<context:component-scan base-package="org.example.model"/>
<!-- For translating native persistence exceptions to Spring's
DataAccessException hierarchy. -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<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/appdb" />
<property name="username" value="username" />
<property name="password" value="password"/>
</bean>
<bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"
p:targetDataSource-ref="dataSource"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>org.example.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- Enable the configuration of transactional behavior based on
annotations. -->
<tx:annotation-driven transaction-manager="transactionManager" />
Spring will only inject Autowired fields in Spring managed beans. AKA if you are using new LoginView() Spring cannot inject dependencies.
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
should be
#Component
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
If you can't let Spring manage that class, you'll need to design it a different way.
I'd recommend you use constructor injection instead of field injection, by the way.
What I might do is make another class to be a Spring managed bean and do something like this:
#Component
public class InitClass{
private UsarioService usarioService;
#Autowired
public InitClass(UsarioService usarioService){
this.usarioService = usarioService;
}
#PostConstruct
public void init(){
new LoginView(usarioService);
}
}
Then this class will handle all the initialization you're doing now in #PostConstruct. It may be required to do this in #PostConstruct as Spring beans may not be fully initialized until then.
However, without seeing how everything is initialized, it's hard to tell what the best strategy would be.
Make explicit component scan in the application context file. I did like this and it worked for me.
<context:component-scan base-package="com.example" />
You can see more information in the link here
Related
I want to manage my transactions with Spring #Transactional and support nested transaction by following this example in order to do so.
My problem is if I call UserService.addAdmin() that SpringTransactionProvider.begin() and SpringTransactionProvider.commit() are not getting called for some reason which indicates that it is not working the way I'm doing it ..
I'm having my service implemented:
/*
*
*/
public class UserService {
private final static Logger LOGGER = Logger.getLogger(UserService.class.getName());
private AdminRepository adminRepository;
public UserService(DSLContext ctx) {
this.adminRepository = new AdminRepository(ctx);
}
#Transactional
public void addAdmin(String userId) {
DSLContext ctx = adminRepository.getCtx();
ctx.insertInto(Admin.ADMIN)
.set(Admin.ADMIN.USER_NAME, userId)
.execute();
}
}
As well as defined my configuration file servlet-context.xml
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/mz_db" />
<property name="username" value="postgres" />
<property name="password" value="huehuehue" />
</bean>
<!-- Configure Spring's transaction manager to use a DataSource -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Configure jOOQ's TransactionProvider as a proxy to Spring's transaction manager -->
<bean id="transactionProvider"
class="com.mz.server.web.SpringTransactionProvider">
</bean>
<!-- Configure jOOQ's ConnectionProvider to use Spring's TransactionAwareDataSourceProxy,
which can dynamically discover the transaction context -->
<bean id="transactionAwareDataSource"
class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dataSource" />
</bean>
<bean class="org.jooq.impl.DataSourceConnectionProvider" name="connectionProvider">
<constructor-arg ref="transactionAwareDataSource" />
</bean>
<!-- Configure the DSL object, optionally overriding jOOQ Exceptions with Spring Exceptions -->
<bean id="dsl" class="org.jooq.impl.DefaultDSLContext">
<constructor-arg ref="config" />
</bean>
<!-- Invoking an internal, package-private constructor for the example
Implement your own Configuration for more reliable behaviour -->
<bean class="org.jooq.impl.DefaultConfiguration" name="config">
<property name="SQLDialect"><value type="org.jooq.SQLDialect">POSTGRES_9_4</value></property>
<property name="connectionProvider" ref="connectionProvider" />
<property name="transactionProvider" ref="transactionProvider" />
</bean>
<!-- BEGIN Services -->
<bean id="userService" class="com.mz.server.web.service.UserService">
<constructor-arg>
<ref bean="dsl" />
</constructor-arg>
</bean>
and basically a copy of SpringTransactionProvider:
public class SpringTransactionProvider implements TransactionProvider {
private final static Logger LOGGER = Logger.getLogger(SpringTransactionProvider.class);
#Autowired
DataSourceTransactionManager txMgr;
public SpringTransactionProvider() {
LOGGER.info("Ctor()");
}
#Override
public void begin(TransactionContext ctx) {
LOGGER.info("##### begin #####");
TransactionStatus tx = txMgr.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_NESTED));
ctx.transaction(new SpringTransaction(tx));
}
#Override
public void commit(TransactionContext ctx) {
LOGGER.info("##### commit #####");
txMgr.commit(((SpringTransaction) ctx.transaction()).tx);
}
#Override
public void rollback(TransactionContext ctx) {
LOGGER.info("##### rollback #####");
txMgr.rollback(((SpringTransaction) ctx.transaction()).tx);
}
}
I would have expected to see
INFO com.mz.server.web.SpringTransactionProvider - Ctor()
DEBUG com.mz.server.web.servlet.UserServletImpl - Login request by userId: username
INFO com.mz.server.web.SpringTransactionProvider - #### begin ####
INFO com.mz.server.web.service.UserService - Yay!
INFO com.mz.server.web.SpringTransactionProvider - #### commit ####
but I'm only getting
INFO com.mz.server.web.SpringTransactionProvider - Ctor()
DEBUG com.mz.server.web.servlet.UserServletImpl - Login request by userId: username
INFO com.mz.server.web.service.UserService - Yay!
Why does the SpringTrancationProvider not getting utilized?
jOOQ's TransactionProvider provides an implementation for the explicit jOOQ transaction API, wiring it to Spring, which you don't seem to be using. An example addAdmin() method that uses the explicit jOOQ transaction API would be this one:
// no #Transactional - no need for declarative transaction management
public void addAdmin(String userId) {
adminRepository.getCtx().transaction(configuration -> {
DSL.using(configuration)
.insertInto(Admin.ADMIN)
.set(Admin.ADMIN.USER_NAME, userId)
.execute();
});
}
The TransactionProvider is not involved if you use Spring's declarative #Transaction API. In other words, you don't need it.
I'm trying to setup entity manager with Spring 4 and I always get NullPointerException when I try to inject EntityManager with #PersistenceContext annotation.
I have Maven web application. Here's my applicationContext.xml configuration
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="EcommercePU">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.mysite.ecommerceapp.domain</value>
<value>com.mysite.ecommerceapp.domain.*</value>
<value>com.mysite.ecommerceapp.domain.*.*</value>
<value>com.mysite.ecommerceapp.domain.*.*.*</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/ecommercedb" />
<property name="username" value="postgres" />
<property name="password" value="test" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
applicationContext.xml is located under WEB-INF folder. Because I use NetBeans 8 I added Spring Framework support to my project from project properties -> Frameworks. I'm using EntityManager injection with file called GenericDaoImpl and here's it's code:
public abstract class GenericDaoImpl<E extends EntityClass> implements GenericDao<E> {
private Class<E> entityClass;
#PersistenceContext()
private EntityManager entityManager;
//Constructor
public GenericDaoImpl(final Class<E> entityClass) {
this.entityClass = entityClass;
}
//Getters and Setters
public Class<E> getEntityClass() {
return entityClass;
}
public void setEntityClass(final Class<E> entityClass) {
this.entityClass = entityClass;
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
public void checkEntityManager() {
System.out.println("em: " + this.entityManager);
}
}
I have one test file where I simply print entity manager with checkEntityManager() method. Whenever I run it I always get null value for EntityManager. What could be wrong? My biggest doubt is that my applicationContext.xml is in wrong place or it is not used anywhere and thus it can't find configuration properties in applicationContext. I have tested moving applicationContext.xml file to resources folder but it didn't helped either. Other questions that I also have are following:
Do I need to have persistence.xml? Since I use Spring 4 with packagesToScan feature I heard that persistence.xml is not required but I'm not sure.
Is it wise to use hibernate to take care only basic entities cruds and other dao queries with JdbcTemplate?
All help would be appreciated.
I finally solved the problem and there were lots of things that has to be done.
When I tested my Entity Manager through JUnit tests I got NullPointerException and reason was the configuration file was incorrect folder.
applicationContext.xml was properly setup except there was a small problem that messed the whole file and that was <property name="persistenceUnitName" value="EcommercePU">. Because I didn't had such persistence unit file in whole project it couldn't find it. When you add that property it doesn't mean that you have created a spring configuration file that has such persistence unit name. It simply means that if you want to provide persistence configurations to your LocalContainerEntityManagerFactory you would refer with that name to your persistence unit. This is not required in Spring 4.
applicationContext.xml had to be moved from WEB-INF to resources folder.
When you would run JUnit tests you should use #Autowired annotation to annotate DAO's.
Dao implementation classes should have #Repository annotation.
#Transactional annotation is required at least for CRUD methods if you are going to use. You can also annotate whole class. If you don't add #Transactional annotation EntityManager wouldn't execute persist, remove, update, find and other methods properly. Remember this is required if you are using Spring configurations.
I keep getting this error, and can't figure out why.. yes I know there many people had similar issues, but reading the answers they got, does not solve my problem.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'contactController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private net.service.ContactService net.controller.ContactController.contactService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [net.service.ContactService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
here is the controller:
#Controller
#SessionAttributes
public class ContactController {
#Autowired
private ContactService contactService;
//methods...
}
the ContactServiceImpl
#Service("contactService")
#Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class ContactServiceImpl implements ContactService {
#Autowired
private ContactDao contactDao;
public ContactServiceImpl() {
}
#Override
#Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void addContact(Contact contact) {
contactDao.saveContact(contact);
}
#Override
public List<Contact> getContacts() {
return contactDao.getAllContacts();
}
}
the ContactDaoImpl
#Repository("contactDao")
public class ContactDaoImpl implements ContactDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public void saveContact(Contact contact) {
sessionFactory.getCurrentSession().saveOrUpdate(contact);
}
#Override
#SuppressWarnings("unchecked")
public List<Contact> getAllContacts() {
return (List<Contact>) sessionFactory.getCurrentSession().createQuery("from contact c").list();
}
}
and the spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
<context:component-scan base-package="net.controller" />
<tx:annotation-driven transaction-manager="hibernateTransactionManager" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>net.form.Contact</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
In spring servlet .xml :
<context:component-scan base-package="net.controller" />
(I assumed that the service impl is in the same package as the service interface "net.service")
I think you have to add the package net.service (or all of net) to the component scan. Currently spring only searches in net.controller for components and as your service impl is in net.service, it will not be instantiated by spring.
I was getting this same error and searching for it led me here. My fix appeared to be simply to add #Component annotation to the implementation of the abstract service.
In this case, that would look like:
import org.springframework.stereotype.Component;
...
#Component
public class ContactServiceImpl implements ContactService {
Well there's a problem with the creation of the ContactServiceImpl bean. First, make sure that the class is actually instantiated by debugging the no-args constructor when the Spring context is initiated and when an instance of ContactController is created.
If the ContactServiceImpl is actually instantiated by the Spring context, but it's simply not matched against your #Autowire annotation, try being more explicit in your annotation injection. Here's a guy dealing with a similar problem as yours and giving some possible solutions:
http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
If you ask me, I think you'll be ok if you replace
#Autowired
private ContactService contactService;
with:
#Resource
#Qualifier("contactService")
private ContactService contactService;
When you get this error some annotation is missing.
I was missing #service annotation on service. When I added that annotation it worked fine for me.
I've faced the same issue today. Turned out to be I forgot to mention #Service/#Component annotation for my service implementation file, for which spring is not able autowire and failing to create the bean.
I had exactly the same problem
try to put the two classes in the same package and add line in the pom.xml
<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-web </artifactId>
<version> 1.2.0.RELEASE </version>
</dependency>
In java config,make sure you have import your config in RootConfig like this
#Import(PersistenceJPAConfig.class)
Encountered similar error, and tried the solutions earlier mentioned in this post but none of them worked for me. What finally resolved the issue was to set #Autowired(required = false)
I have a webapp using Hibernate 4.1 and Spring 3.1 and JSF 1.2 (myFaces).
I have this "LazyInitializationException" each time I try to access one of my pages
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at £org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:149)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:195)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at foo.data.bo.implementations.EOServiceType_$$_javassist_10.getTechKey(EOServiceType_$$_javassist_10.java)
at foo.converter.EOServiceTypeConverter.getAsString(EOServiceTypeConverter.java:36)
at org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:648)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils.getSubmittedOrSelectedValuesAsSet(HtmlRendererUtils.java:362)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils.internalRenderSelect(HtmlRendererUtils.java:337)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils.renderMenu(HtmlRendererUtils.java:288)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlMenuRendererBase.encodeEnd(HtmlMenuRendererBase.java:57)
at org.apache.myfaces.renderkit.html.ext.HtmlMenuRenderer.encodeEnd(HtmlMenuRenderer.java:70)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:649)
... 50 more
I think I missunderstood something because I don't know How to give the "session" to my classes.
For info, here are some of my configuration files :
spring-config.xml:
<context:annotation-config />
<context:component-scan base-package="foo" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="namingStrategy">
<ref bean="oracleNamingStrategy" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<alias name="jndiDataSource" alias="dataSource" />
<bean name="oracleNamingStrategy"
class="org.hibernate.cfg.ImprovedNamingStrategy">
</bean>
<bean name="jndiDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/fooDS</value>
</property>
</bean>
My java class EOServiceType
#Entity
#Table(name="EOSERVICETYPE")
public class EOServiceType implements IEOServiceType {
#Id
#Column(name="EOSERVICETYPE_ID")
private long techKey;
#Column(name="H_PROPERTY")
private String property;
#Column(name="H_DESCRIPTION")
private String description;
//... + all getters and setters
}
My DAO implementation for Hibernate EOServiceTypeDaoHibernateImpl
#Repository("eOServiceTypeDao")
public class EOServiceTypeDaoHibernateImpl implements IEOServiceTypeDao {
#Autowired
private SessionFactory sessionFactory;
public void save(IEOServiceType serviceType) {
sessionFactory.getCurrentSession().save(serviceType);
}
public void update(IEOServiceType serviceType) {
sessionFactory.getCurrentSession().update(serviceType);
}
//... and some other CRUD operations...
}
My POJO Service implementation for Hibernate EOWebStaffServicesImpl
#Service
public class EOWebStaffServicesImpl implements IEOWebStaffServices {
#Autowired
private SessionFactory sessionFactory;
//...
#Autowired
private IEOServiceTypeDao eoServiceTypeDao;
public void saveOrUpdateEOServiceType(IEOServiceType eoServiceType) {
try {
eoServiceTypeDao.saveOrUpdate(eoServiceType);
} catch (DataIntegrityViolationException e) {
DuplicateKeyException exception= new DuplicateKeyException("Duplicate business key for " + eoServiceType,e);
throw exception;
}
}
public void deleteEOServiceType(IEOServiceType eoServiceType) {
eoServiceTypeDao.delete(eoServiceType);
}
My Hibernate Config file :
<hibernate-configuration>
<session-factory>
<property name="hibernate.mapping.precedence">hbm, class</property>
<property name="show_sql">false</property>
<property name="format_sql">true</property>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="jdbc.batch_size">20</property>
<mapping class="foo.data.bo.implementations.EOServiceType"/>
<!-- ... and other mappings -->
</session-factory>
</hibernate-configuration>
Does any body have a tip to help me ? I read some articles and post but did not really find a solution to my problem.
Best regards,
Kamran
I had the same kind of problem several weeks ago. I obviously forgot to annotate my method which is interacting with Hibernate.
I recommend you the
#Transactional
annotation. It should fix your problem.
Otherwise here is the related Hibernate documentation:
Sessions and Transactions
I think this happens because you don't use transactions in your DAO classes. Hibernate will not work with Spring outside of the transaction. You can define declarative transactions with Spring (annotate necessary classes with #Transactional annotation). Here is a link to Spring reference documentation about Transactions.
Also you should inject SessionFactory to your bean before using it:
#autowired
private SessionFactory sessionFactory;
What are you planing to archive with the SessionFactory in your service class?
Anyway, i think the problem is that you are trying to access a detached object with lazy properties. (That's usually the case when you see that exception)
Is that all the code there is of your POJOs?
My service makes use of a generic DAO (which explicitly uses Hibernate session factory). I have spent some time before I discovered this error
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I annotated my service and all works perfectly. Now I want to use context path scanning, and remove this line from my configuration:
<bean id="societaService" class="it.trew.prove.services.SocietaService" />
So.... here's my final version:
#Service
#Transactional(readOnly = true)
public class SocietaService {
private Dao societaDao;
#Autowired
public void setSocietaDao(Dao societaDao) {
this.societaDao = societaDao;
}
public void salvaSocieta(Societa s) {
societaDao.save(s);
}
public List<Societa> listAll() {
return societaDao.getAll(Societa.class);
}
public void deleteById(Long id) {
societaDao.delete(getSocieta(id));
}
public Societa getSocieta(String id) {
return getSocieta(Long.parseLong(id));
}
public Societa getSocieta(Long id) {
return societaDao.get(Societa.class, id);
}
}
Adding #Service annotation makes my app give the awful hibernate error above. Why?
Removing #Service and configuring the service bean via xml = it works. WHY??
In addition:
does transactional annotating my service class makes all its methods to be executing in a transaction?
EDIT
Here's my context xml:
<context:annotation-config />
<context:component-scan base-package="it.trew.prove" />
<!-- Hibernate -->
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.google.appengine.api.rdbms.AppEngineDriver" />
<property name="url" value="jdbc:google:rdbms://xxx:xxx/xxx" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="annotatedClasses">
<list>
<value>it.trew.prove.model.beans.Scadenza</value>
<value>it.trew.prove.model.beans.Fornitore</value>
<value>it.trew.prove.model.beans.Societa</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<!-- <prop key="hibernate.hbm2ddl.import_files">/setup.sql</prop> -->
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
Did you enabled annotations ?
<context:annotation-config />
and
<context:component-scan base-package="org.example"/>
this will enable annotations like #Service, #Component and #Repository
First of all, you need to tell spring to enable Transactional annotation with something like that:
<tx:annotation-driven transaction-manager="transactionManager" />
Second, if you use #Transactional at class level, any call to a method of your Service will be transactional. Whether it starts a transaction or not depends on the "propagation" attribute. The default is start one if none started in this session (Propagation.REQUIRED). If you use #Transactional only at class level, all of your methods will inherit its attributes, i.e., if you set "readOnly = true", all of yours methods will be read only, thus, updates/saves/delete won't work. I would recommend you to read more the Spring Transaction Management Doc