0

Completely at my wit's end with this, nothing I can find seems to help. I keep getting the exception

org.hibernate.HibernateException: No Session found for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:988)
    at com.thing.basicwebform.dao.AbstractHbnDao.getSession(AbstractHbnDao.java:31)
    at com.thing.basicwebform.dao.HbnAccountDao.findByUsername(HbnAccountDao.java:38)
    at com.thing.basicwebform.service.AccountServiceImpl.validateUsername(AccountServiceImpl.java:34)
    at com.thing.basicwebform.service.AccountServiceImpl.registerAccount(AccountServiceImpl.java:27)
    at com.thing.basicwebform.AccountController.postRegistrationForm(AccountController.java:50)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)

I've got my application context set up thusly:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:util="http://www.springframework.org/schema/util"
        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.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.1.xsd
                http://www.springframework.org/schema/jee
                http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
                http://www.springframework.org/schema/util
                http://www.springframework.org/schema/util/spring-util-3.1.xsd
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
        <jee:jndi-lookup id="dataSource" jndi-name="jdbc/basicwebform" resource-ref="true" />
        <bean class="org.springframework.jdbc.core.JdbcTemplate"> 
            <property name="dataSource" ref="dataSource" /> 
        </bean>
        <util:properties id="hibernateProperties">
            <prop key="hibernate.dialect">
                org.hibernate.dialect.MySQL5InnoDBDialect
            </prop>
            <prop key="hibernate.show_sql">false</prop>
        </util:properties>
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <property name="packagesToScan">
                <list>
                    <value>com.thing.basicwebform.domain</value>
                </list>
            </property>
            <property name="hibernateProperties" ref="hibernateProperties" />
            <property name="dataSource" ref="dataSource" />
        </bean>
        <bean id="transactionManager"
            class="org.springframework.orm.hibernate4.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
        <context:annotation-config />
        <tx:annotation-driven transaction-manager="transactionManager" /> 
        <context:component-scan base-package="com.thing.basicwebform.dao" />
        <context:component-scan base-package="com.thing.basicwebform.service" />
</beans>

My AccountService is this:

package com.thing.basicwebform.service;

import com.thing.basicwebform.dao.AccountDao;
import com.thing.basicwebform.domain.Account;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.Errors;

@Service
@Transactional(readOnly = true)
public class AccountServiceImpl implements AccountService{
    @Inject private AccountDao accountDao;
    @Override
    @Transactional(readOnly = false)
    public boolean registerAccount(Account account, String password, Errors errors) {
        validateUsername(account.getUsername(), errors);
        boolean valid = !errors.hasErrors();
        if(valid){ accountDao.create(account, password);}
        return valid;
    }

    private void validateUsername(String username, Errors errors){
        if(accountDao.findByUsername(username) != null){
            errors.rejectValue("username", "error.duplicate", new String[]{username},null);
        }
    }
}

And finally, my abstract DAO looks like this (the top layer isn't really any different, a couple of nice wrapper methods and that's it):

package com.thing.basicwebform.dao;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;

public abstract class AbstractHbnDao<T extends Object> 
    implements Dao<T> {
    @Inject
    private SessionFactory sessionFactory;
    private Class<T> domainClass;

    protected Session getSession(){
        return this.sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    private Class<T> getDomainClass(){
        if(domainClass == null){
            ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();
            this.domainClass = (Class<T>) thisType.getActualTypeArguments()[0];
        }
        return domainClass;
    }

    private String getDomainClassName(){
        return getDomainClass().getName();
    }

    @Override
    public void create(T t){
        Method method = ReflectionUtils.findMethod(getDomainClass(), "setDateCreated", new Class[]{Date.class});
        if(method != null){
            try{
                method.invoke(t, new Date());
            }catch(Exception e){/*Ignore*/}
        }
        getSession().save(t);
    }

    @Override
    public T get(Serializable id){
        return (T) getSession().get(getDomainClass(), id);
    }

    @Override
    public T load(Serializable id){
        return (T) getSession().get(getDomainClass(), id);
    }

    public List<T> getAll(){
        return getSession()
                .createQuery("from " + getDomainClassName())
                .list();
    }

    @Override
    public void delete(T t){
        getSession().delete(t);
    }

    @Override
    public void update(T t){
        getSession().update(t);
    }

    @Override
    public void deleteById(Serializable id){
        delete(load(id));
    }

    @Override
    public void deleteAll(){
        getSession()
                .createQuery("delete " + getDomainClassName())
                .executeUpdate();
    }

    @Override
    public long count(){
        return (Long) getSession()
                .createQuery("select count(*) from " + getDomainClassName())
                .uniqueResult();
    }

    @Override
    public boolean exists(Serializable id){
        return get(id) != null;
    }
}

I'm new to Spring/Hibernate, and this is driving me mad when everything I find on stack overflow seems to be telling me that this is ok, since the XML contains this to things annotated with @Service and leaves my controllers alone

EDIT:

User Jay provided me with this link in the comments below. I got a new

org.hibernate.HibernateException: getNamedQuery is not valid without active transaction

error once I'd added the

<property name="hibernate.current_session_context_class">thread</property>

to my hibernate properties object, but after adding beginTransaction() and transaction.commit() calls, this was fixed. Thanks, guys :)

  • Give more of the stacktrace to help us know when the exception's happening. – Emerson Farrugia Mar 26 '14 at 13:58
  • There's nothing obviously wrong that I can see. Two followup questions. Is all of the processing happening on one thread? Can you also paste the AccountDao? – Emerson Farrugia Mar 26 '14 at 14:14
  • Have you already went through [this](http://stackoverflow.com/questions/8846586/no-session-found-for-current-thread-spring-3-1-x-and-hibernate-4) and [this](http://stackoverflow.com/questions/20716939/spring-hibernate-no-session-found-for-current-thread) – eis Mar 26 '14 at 16:10
  • This is what I was missing [link](http://docs.jboss.org/hibernate/core/3.3/reference/en/html/architecture.html#architecture-current-session) – HeadBangingSloth Mar 26 '14 at 21:56
  • The whole point of `@Transactional` and `` is to not call `beginTransaction()` and `commit()` manually. – Emerson Farrugia Mar 26 '14 at 22:12
  • I figured that was the point, but for whatever reason the transaction manager hates me. I'll eventually sort it out, but for now I'll just put up with it. My abstract DAO class wraps everything well enough that it isn't too much of a problem – HeadBangingSloth Mar 26 '14 at 23:11
  • Oh, actually, I think I figured out the problem. My controllers are in the parent package com.thing rather than their own package, so my dispatcher-servlet.xml file could theoretically be loading up an empty instance of my AccountServiceImpl? Not entirely sure, will have to wait until my lunch break to test this theory, but if I move the controllers into their own, non-root package and update my servlet config, it might fix it – HeadBangingSloth Mar 26 '14 at 23:32

1 Answers1

0

If there is no current session, open a new session like this

protected Session getSession() {
    Session session = null;
    try {
        session = getSessionFactory().getCurrentSession();
    } catch (HibernateException e) {
        System.out.println("Current session is NULL..opening new session");
        session = getSessionFactory().openSession();
    }
    return session;
}
Jay
  • 9,189
  • 12
  • 56
  • 96