1

I tried creating a small example using Spring, rest, Hibernate. In order to have the session open for when the marshalling is done, I added the filter org.springframework.orm.hibernate3.support.OpenSessionInViewFilter in the web.xml

Now, however, I get heavily stuck, which might be because I'm pretty new with AOP. I face the problem that the session is not opened, when a request is sent:

20.10.2011 17:26:40 org.apache.catalina.core.StandardWrapperValve invoke
SCHWERWIEGEND: Servlet.service() for servlet mvc-dispatcher threw exception
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:685)

I think it is the same problem as described in Spring + Hibernate with annotations: No Hibernate Session bound to thread but I don't get it to work.

web.xml:

<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>Spring Web MVC Application</display-name>

<filter>
    <filter-name>SessionPerRequest</filter-name>
    <filter-class>
        org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>SessionPerRequest</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

</web-app>

mvc-dispatcher-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:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config />

<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/test" />
    <property name="username" value="backend"/>
    <property name="password" value="bUWGRysbbzYuXsbq" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />

<context:component-scan base-package="de.company.springtest" />

<mvc:annotation-driven />

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configurationClass">
        <value>org.hibernate.cfg.AnnotationConfiguration</value>
    </property>
</bean>


<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="txAdvice">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<!--    <aop:config> -->
<!--        <aop:advisor pointcut="execution(* de.company.springtest..*.*(..))" advice-ref="txAdvice" /> -->
<!--    </aop:config> -->


</beans>

If the aop part is uncommented (which is the solution in the other thread), it throws the following exception when it is starting:

    INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@46e06703: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,dataSource,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,JSONController,hibernateConfiguration,org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,sessionFactory,transactionManager,txAdvice,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0,sessionFactoryBean]; root of factory hierarchy
20.10.2011 17:37:04 org.springframework.web.context.ContextLoader initWebApplicationContext
SCHWERWIEGEND: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Cannot resolve reference to bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' while setting bean property 'transactionAttributeSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:452)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)

Rest controller, which however does not yet get called. So break points in the very beginning of the functions are not called.

package de.company.springtest.controller;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import de.company.springtest.Item;
import de.company.springtest.Order;


@Controller
@RequestMapping("/user")
// localhost:8080/RESTfulTest/rest/user/abc
public class JSONController {

@Autowired
private SessionFactory sessionFactory;

@RequestMapping(method = RequestMethod.POST)
public @ResponseBody
Order postOrderInJSON() {

    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Order order = new Order();
    order.getItems().add(new Item());
    session.save(order);
    // session.flush();
    transaction.commit();
    // session.close();
    return order;

}


@RequestMapping(value = "get/{id}", method = RequestMethod.GET)
public @ResponseBody
Order getUserInJSON(/* @PathVariable Long id */) {

    Session session = sessionFactory.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Order order = new Order();
    order.getItems().add(new Item());
    session.save(order);
    // session.flush();
    transaction.commit();
    // session.close();

    return order;

}

}

HibernateConfiguration.java

package de.company.springtest;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.dialect.MySQLDialect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;

@Configuration
public class HibernateConfiguration {

@Value("#{dataSource}")
private DataSource dataSource;

@Bean
public AnnotationSessionFactoryBean sessionFactoryBean() {
    Properties props = new Properties();
    props.put("hibernate.dialect", MySQLDialect.class.getName());
    props.put("hibernate.current_session_context_class", "thread");
    props.put("hibernate.transaction.factory_class", "org.hibernate.transaction.JDBCTransactionFactory");
    props.put("hibernate.format_sql", "true");

    AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();
    bean.setAnnotatedClasses(new Class[]{Item.class, Order.class});     
    bean.setHibernateProperties(props);
    bean.setDataSource(this.dataSource);
    bean.setSchemaUpdate(true);
    return bean;
}

@Bean
public HibernateTransactionManager transactionManager() {
    HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager( sessionFactoryBean().getObject() );
    return hibernateTransactionManager;
}

}

Do you have any proposition where I could continue with my search?

3 Answers 3

2

The error when uncommenting the part is most likely caused by aspectj missing in the classpath.

Alternatively, you could use the @Transactional annotation in your DAO or wherever beginning/ending transactions fits in your application design, as the first comment in the linked thread points out. You need to have either of this to start a transaction (or do it manually) - just having a transaction manager configured isn't enough.

Sign up to request clarification or add additional context in comments.

Comments

0

nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException

You need to deploy aspectJ (aspectjweaver.jar) together with your application.

If you use maven than add this to your pom:

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.9</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.9</version>
    </dependency>

If you do not use maven, than add this two jars by hand.

Comments

0

You whole configuration / wiring looks pretty "raw". The reason for this exception => your "service layer" is not transacted, hence Hibernate complains.

Do not put @Transactional at the DAO level, as somebody suggests => it is wrong. You should always transact on the business unit => in the service layer.

Take a look at the example project (just clone it) that integrates Spring and Hibernate together.

There is actually a HibernateSessionNotBoundToThreadIntegrationTest that shows the reason for this exception.

Here is an example on the proper TX configuration via Spring AOP:

<?xml version="1.0" encoding="UTF-8"?>
<beans ...>

    <aop:config>
        <aop:pointcut id="moneyMakingBusinessServiceMethods"
                      expression="execution(* org.gitpod.startup.service.MoneyMakingBusinessService.*(..))"/>

        <aop:advisor advice-ref="moneyMakingAdvice"
                     pointcut-ref="moneyMakingBusinessServiceMethods"/>
    </aop:config>

    <tx:advice id="moneyMakingAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="makeMoney" propagation="REQUIRED"/>
            <tx:method name="withdrawMoney" propagation="REQUIRED" read-only="true"/>            
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>

</beans>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.